diff --git a/.gitignore b/.gitignore index 1cb6a72785..3c47370786 100644 --- a/.gitignore +++ b/.gitignore @@ -1,64 +1,14 @@ -html/ -.DS_Store -*.o -*.dylib -test -*.png -*.dat -*.ii -*.s -*.tmp -*.la -*.lo -*.dump *.beam *.class -benchmarks/mailbox_performance -benchmarks/actor_creation -benchmarks/mixed_case -benchmarks/matching -theron_mailbox_performance -.libs/ -.deps/ -libcppa.pc -Makefile.in -aclocal.m4 -autom4te.cache/ -gen_server/parallel_send -gen_server/sequential_send -gen_server/test.dSYM/ -depcomp -install-sh -libtool -ltmain.sh -missing -unit_testing/Makefile.in -unit_testing/unit_tests -unit_testing/.deps/ -config.* -configure -INSTALL -m4/libtool.m4 -m4/lt*.m4 -a.out* -queue_test -cppa.creator.user -8threads -4threads -libcppa.Makefile -variadic_templates_test -variadic_templates_test.dSYM/ -Makefile -unit_testing/Makefile -libcppa.so* -blob/cppatest +*.dat +*.dump +*.png +*.tmp +.DS_Store callgrind.out* -examples/announce_example_1 -examples/announce_example_2 -examples/announce_example_3 -examples/announce_example_4 -examples/announce_example_5 -examples/hello_world_example -examples/math_actor_example -examples/dining_philosophers -examples/dancing_kirby +cppa.creator.user +html/ +libcppa.pc +bin/* +build/* +lib/* diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..4f5860b278 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,177 @@ +cmake_minimum_required(VERSION 2.4) +project(cppa CXX) + +set (CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wextra -Wall -pedantic") + +set(LIBCPPA_SRC + src/abstract_tuple.cpp + src/actor.cpp + src/actor_count.cpp + src/actor_proxy.cpp + src/actor_proxy_cache.cpp + src/actor_registry.cpp + src/addressed_message.cpp + src/any_tuple.cpp + src/atom.cpp + src/attachable.cpp + src/behavior_stack.cpp + src/binary_deserializer.cpp + src/binary_serializer.cpp + src/channel.cpp + src/thread_mapped_actor.cpp + src/demangle.cpp + src/deserializer.cpp + src/duration.cpp + src/empty_tuple.cpp + src/event_based_actor.cpp + src/exception.cpp + src/factory.cpp + src/fiber.cpp + src/group.cpp + src/group_manager.cpp + src/local_actor.cpp + src/mailman.cpp + src/native_socket.cpp + src/network_manager.cpp + src/object.cpp + src/object_array.cpp + src/partial_function.cpp + src/pattern.cpp + src/post_office.cpp + src/primitive_variant.cpp + src/process_information.cpp + src/receive.cpp + src/ripemd_160.cpp + src/scheduled_actor.cpp + src/scheduled_actor_dummy.cpp + src/scheduler.cpp + src/self.cpp + src/serializer.cpp + src/shared_spinlock.cpp + src/singleton_manager.cpp + src/string_serialization.cpp + src/thread_pool_scheduler.cpp + src/to_uniform_name.cpp + src/unicast_network.cpp + src/uniform_type_info.cpp + src/yield_interface.cpp + src/context_switching_actor.cpp +) + +set(boost_context third_party/boost_context/) + +# add third_party boost_context sources +if(APPLE) + set_property(SOURCE + ${boost_context}/src/asm/fcontext_x86_64_sysv_macho_gas.S + PROPERTY LANGUAGE CXX) + set(LIBCPPA_SRC + ${LIBCPPA_SRC} + ${boost_context}/src/stack_utils_posix.cpp + ${boost_context}/src/stack_allocator_posix.cpp + ${boost_context}/src/fcontext.cpp + ${boost_context}/src/asm/fcontext_x86_64_sysv_macho_gas.S + ) +elseif(UNIX) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + set_property(SOURCE + ${boost_context}/src/asm/fcontext_i386_sysv_elf_gas.S + PROPERTY LANGUAGE CXX) + set(fcontext_asm ${boost_context}/src/asm/fcontext_i386_sysv_elf_gas.S) + else() + set_property(SOURCE + ${boost_context}/src/asm/fcontext_x86_64_sysv_elf_gas.S + PROPERTY LANGUAGE CXX) + set(fcontext_asm ${boost_context}/src/asm/fcontext_x86_64_sysv_elf_gas.S) + endif() + set(LIBCPPA_SRC + ${LIBCPPA_SRC} + ${fcontext_asm} + ${boost_context}/src/stack_utils_posix.cpp + ${boost_context}/src/stack_allocator_posix.cpp + ${boost_context}/src/fcontext.cpp + ) +endif() + +find_package(Boost COMPONENTS thread REQUIRED) + +link_directories(${Boost_LIBRARY_DIRS}) +include_directories(. ${Boost_INCLUDE_DIRS} ${boost_context}/include) + +add_library(libcppa SHARED ${LIBCPPA_SRC}) + +target_link_libraries(libcppa ${CMAKE_LD_LIBS} ${Boost_THREAD_LIBRARY}) + +set(LIBCPPA_VERSION_MAJOR 0) +set(LIBCPPA_VERSION_MINOR 2) +set(LIBCPPA_VERSION_PATCH 0) +set(LIBRARY_VERSION ${LIBCPPA_VERSION_MAJOR}.${LIBCPPA_VERSION_MINOR}.${LIBCPPA_VERSION_PATCH}) +set(LIBRARY_SOVERSION ${LIBCPPA_VERSION_MAJOR}) + +set_target_properties(libcppa PROPERTIES SOVERSION ${LIBRARY_SOVERSION} VERSION ${LIBRARY_VERSION} OUTPUT_NAME cppa) +install(TARGETS libcppa LIBRARY DESTINATION lib) + +# install includes +install(DIRECTORY cppa/ DESTINATION include/cppa + FILES_MATCHING PATTERN "*.hpp") +# uninstall target +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + +add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P + ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + + + +if (LIBRARY_OUTPUT_PATH) + set (CPPA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}) + set (CPPA_LIBRARY_PATH ${LIBRARY_OUTPUT_PATH}) +else() + set (CPPA_LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/lib) + set (CPPA_LIBRARY_PATH ${CPPA_LIBRARY_OUTPUT_PATH}) + set (LIBRARY_OUTPUT_PATH ${CPPA_LIBRARY_OUTPUT_PATH} CACHE PATH "Single directory for all libraries") +endif() + +# setting path to cppa headers and libcppa +set (CPPA_INCLUDE_PATH ${CMAKE_SOURCE_DIR}/libcppa) +set (CPPA_INCLUDE ${CPPA_INCLUDE_PATH}) + +if (APPLE) + set (CPPA_LIBRARY ${LIBRARY_OUTPUT_PATH}/libcppa.dylib) +elseif (UNIX) + set (CPPA_LIBRARY ${LIBRARY_OUTPUT_PATH}/libcppa.so) +else () + message (SEND_FATAL "Host platform not supported ...") +endif () + +if (EXECUTABLE_OUTPUT_PATH) +else () + set (EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin CACHE PATH "Single directory for all executables") +endif () + +add_subdirectory(unit_testing) +add_subdirectory(examples) +add_subdirectory(benchmarks) +#add_subdirectory(benchmarks) +#add_dependencies(unit_tests libcppa) +#add_dependencies(benchmarks libcppa) +add_dependencies(announce_example_1 libcppa) +add_dependencies(announce_example_2 libcppa) +add_dependencies(announce_example_3 libcppa) +add_dependencies(announce_example_4 libcppa) +add_dependencies(announce_example_5 libcppa) +add_dependencies(dancing_kirby libcppa) +add_dependencies(dining_philosophers libcppa) +add_dependencies(hello_world_example libcppa) +add_dependencies(math_actor_example libcppa) +add_dependencies(unit_tests libcppa) +add_dependencies(actor_creation libcppa) +add_dependencies(mailbox_performance libcppa) +add_dependencies(mixed_case libcppa) +add_dependencies(distributed libcppa) +add_dependencies(matching libcppa) diff --git a/COPYING b/COPYING deleted file mode 100644 index 94a9ed024d..0000000000 --- a/COPYING +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/ChangeLog b/ChangeLog index e69de29bb2..bc8a53ff41 100644 --- a/ChangeLog +++ b/ChangeLog @@ -0,0 +1,12 @@ +Version 0.2 + +2012-06-29 + +- Removed become_void() [use quit() instead] +- Renamed "future_send()" to "delayed_send()" +- Removed "stacked_actor"; moved functionality to "event_based_actor" +- Renamed "fsm_actor" to "sb_actor" +- Refactored "spawn": spawn(new T(...)) => spawn(...) +- Implemented become()/unbecome() for context-switching & thread-mapped actors +- Moved become()/unbecome() to local_actor +- Ported libcppa from to Boost.Context library diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index e93ca0902e..0000000000 --- a/Makefile.am +++ /dev/null @@ -1,234 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 - -lib_LTLIBRARIES = libcppa.la - -libcppa_la_SOURCES = \ - src/abstract_event_based_actor.cpp \ - src/abstract_scheduled_actor.cpp \ - src/abstract_tuple.cpp \ - src/actor.cpp \ - src/actor_count.cpp \ - src/actor_proxy.cpp \ - src/actor_proxy_cache.cpp \ - src/actor_registry.cpp \ - src/addressed_message.cpp \ - src/any_tuple.cpp \ - src/atom.cpp \ - src/attachable.cpp \ - src/binary_deserializer.cpp \ - src/binary_serializer.cpp \ - src/channel.cpp \ - src/converted_thread_context.cpp \ - src/cppa.cpp \ - src/demangle.cpp \ - src/deserializer.cpp \ - src/duration.cpp \ - src/empty_tuple.cpp \ - src/event_based_actor.cpp \ - src/exception.cpp \ - src/fiber.cpp \ - src/group.cpp \ - src/group_manager.cpp \ - src/invokable.cpp \ - src/local_actor.cpp \ - src/mailman.cpp \ - src/mock_scheduler.cpp \ - src/native_socket.cpp \ - src/network_manager.cpp \ - src/object.cpp \ - src/object_array.cpp \ - src/partial_function.cpp \ - src/pattern.cpp \ - src/post_office.cpp \ - src/post_office_msg.cpp \ - src/primitive_variant.cpp \ - src/process_information.cpp \ - src/receive.cpp \ - src/ripemd_160.cpp \ - src/scheduled_actor.cpp \ - src/scheduler.cpp \ - src/self.cpp \ - src/serializer.cpp \ - src/shared_spinlock.cpp \ - src/singleton_manager.cpp \ - src/stacked_event_based_actor.cpp \ - src/string_serialization.cpp \ - src/thread_pool_scheduler.cpp \ - src/to_uniform_name.cpp \ - src/unicast_network.cpp \ - src/uniform_type_info.cpp \ - src/yield_interface.cpp \ - src/yielding_actor.cpp - -if VERSIONED_INCLUDE_DIR -library_includedir = $(includedir)/cppa/$(PACKAGE_VERSION)/ -else -library_includedir = $(includedir)/ -endif - -nobase_library_include_HEADERS = \ - cppa/abstract_actor.hpp \ - cppa/abstract_event_based_actor.hpp \ - cppa/actor.hpp \ - cppa/actor_proxy.hpp \ - cppa/announce.hpp \ - cppa/any_tuple.hpp \ - cppa/anything.hpp \ - cppa/atom.hpp \ - cppa/attachable.hpp \ - cppa/behavior.hpp \ - cppa/binary_deserializer.hpp \ - cppa/binary_serializer.hpp \ - cppa/channel.hpp \ - cppa/config.hpp \ - cppa/cow_ptr.hpp \ - cppa/cow_tuple.hpp \ - cppa/cppa.hpp \ - cppa/deserializer.hpp \ - cppa/detail/abstract_scheduled_actor.hpp \ - cppa/detail/abstract_tuple.hpp \ - cppa/detail/actor_count.hpp \ - cppa/detail/actor_proxy_cache.hpp \ - cppa/detail/actor_registry.hpp \ - cppa/detail/addressed_message.hpp \ - cppa/detail/atom_val.hpp \ - cppa/detail/boxed.hpp \ - cppa/detail/buffer.hpp \ - cppa/detail/channel.hpp \ - cppa/detail/container_tuple_view.hpp \ - cppa/detail/converted_thread_context.hpp \ - cppa/detail/decorated_tuple.hpp \ - cppa/detail/default_uniform_type_info_impl.hpp \ - cppa/detail/demangle.hpp \ - cppa/detail/disablable_delete.hpp \ - cppa/detail/empty_tuple.hpp \ - cppa/detail/get_behavior.hpp \ - cppa/detail/group_manager.hpp \ - cppa/detail/implicit_conversions.hpp \ - cppa/detail/invokable.hpp \ - cppa/detail/list_member.hpp \ - cppa/detail/mailman.hpp \ - cppa/detail/map_member.hpp \ - cppa/detail/matches.hpp \ - cppa/detail/mock_scheduler.hpp \ - cppa/detail/native_socket.hpp \ - cppa/detail/network_manager.hpp \ - cppa/detail/object_array.hpp \ - cppa/detail/object_impl.hpp \ - cppa/detail/pair_member.hpp \ - cppa/detail/post_office.hpp \ - cppa/detail/post_office_msg.hpp \ - cppa/detail/primitive_member.hpp \ - cppa/detail/projection.hpp \ - cppa/detail/pseudo_tuple.hpp \ - cppa/detail/ptype_to_type.hpp \ - cppa/detail/receive_loop_helper.hpp \ - cppa/detail/ref_counted_impl.hpp \ - cppa/detail/serialize_tuple.hpp \ - cppa/detail/singleton_manager.hpp \ - cppa/detail/swap_bytes.hpp \ - cppa/detail/tdata.hpp \ - cppa/detail/thread.hpp \ - cppa/detail/thread_pool_scheduler.hpp \ - cppa/detail/to_uniform_name.hpp \ - cppa/detail/tuple_cast_impl.hpp \ - cppa/detail/tuple_iterator.hpp \ - cppa/detail/tuple_vals.hpp \ - cppa/detail/tuple_view.hpp \ - cppa/detail/type_to_ptype.hpp \ - cppa/detail/types_array.hpp \ - cppa/detail/unboxed.hpp \ - cppa/detail/uniform_type_info_map.hpp \ - cppa/detail/value_guard.hpp \ - cppa/detail/yield_interface.hpp \ - cppa/detail/yielding_actor.hpp \ - cppa/either.hpp \ - cppa/event_based_actor.hpp \ - cppa/event_based_actor_base.hpp \ - cppa/exception.hpp \ - cppa/exit_reason.hpp \ - cppa/from_string.hpp \ - cppa/fsm_actor.hpp \ - cppa/get.hpp \ - cppa/group.hpp \ - cppa/guard_expr.hpp \ - cppa/intrusive/forward_iterator.hpp \ - cppa/intrusive/single_reader_queue.hpp \ - cppa/intrusive/singly_linked_list.hpp \ - cppa/intrusive_ptr.hpp \ - cppa/local_actor.hpp \ - cppa/match.hpp \ - cppa/match_expr.hpp \ - cppa/object.hpp \ - cppa/on.hpp \ - cppa/option.hpp \ - cppa/partial_function.hpp \ - cppa/pattern.hpp \ - cppa/primitive_type.hpp \ - cppa/primitive_variant.hpp \ - cppa/process_information.hpp \ - cppa/receive.hpp \ - cppa/ref_counted.hpp \ - cppa/scheduled_actor.hpp \ - cppa/scheduler.hpp \ - cppa/scheduling_hint.hpp \ - cppa/self.hpp \ - cppa/serializer.hpp \ - cppa/stacked_event_based_actor.hpp \ - cppa/to_string.hpp \ - cppa/tpartial_function.hpp \ - cppa/tuple_cast.hpp \ - cppa/type_value_pair.hpp \ - cppa/uniform_type_info.hpp \ - cppa/util/abstract_uniform_type_info.hpp \ - cppa/util/apply_args.hpp \ - cppa/util/apply_tuple.hpp \ - cppa/util/arg_match_t.hpp \ - cppa/util/at.hpp \ - cppa/util/callable_trait.hpp \ - cppa/util/comparable.hpp \ - cppa/util/compare_tuples.hpp \ - cppa/util/conjunction.hpp \ - cppa/util/deduce_ref_type.hpp \ - cppa/util/disjunction.hpp \ - cppa/util/duration.hpp \ - cppa/util/element_at.hpp \ - cppa/util/fiber.hpp \ - cppa/util/fixed_vector.hpp \ - cppa/util/if_else.hpp \ - cppa/util/is_array_of.hpp \ - cppa/util/is_builtin.hpp \ - cppa/util/is_comparable.hpp \ - cppa/util/is_forward_iterator.hpp \ - cppa/util/is_iterable.hpp \ - cppa/util/is_legal_tuple_type.hpp \ - cppa/util/is_manipulator.hpp \ - cppa/util/is_mutable_ref.hpp \ - cppa/util/is_primitive.hpp \ - cppa/util/left_or_right.hpp \ - cppa/util/producer_consumer_list.hpp \ - cppa/util/projection.hpp \ - cppa/util/pt_dispatch.hpp \ - cppa/util/pt_token.hpp \ - cppa/util/purge_refs.hpp \ - cppa/util/replace_type.hpp \ - cppa/util/ripemd_160.hpp \ - cppa/util/rm_option.hpp \ - cppa/util/rm_ref.hpp \ - cppa/util/shared_lock_guard.hpp \ - cppa/util/shared_spinlock.hpp \ - cppa/util/static_foreach.hpp \ - cppa/util/tbind.hpp \ - cppa/util/type_list.hpp \ - cppa/util/type_pair.hpp \ - cppa/util/upgrade_lock_guard.hpp \ - cppa/util/void_type.hpp \ - cppa/util/wrapped.hpp - -libcppa_la_CXXFLAGS = --std=c++0x -pedantic -Wall -Wextra -libcppa_la_LDFLAGS = -release $(PACKAGE_VERSION) $(BOOST_CPPFLAGS) - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libcppa.pc - -SUBDIRS = . unit_testing examples benchmarks diff --git a/NEWS b/NEWS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/README b/README deleted file mode 100644 index 64e458a847..0000000000 --- a/README +++ /dev/null @@ -1,15 +0,0 @@ -Blog: http://libcppa.blogspot.com - -This project is in an early / experimental stage. - -It makes use of variadic templates, unrestricted unions, -type inference and other C++11 features. -Thus, GCC in version >= 4.6 is required to compile libcppa. -You'll also need automake and the boost thread library. - - -Building libcppa: - -* autoreconf -i -* ./configure -* make diff --git a/README.md b/README.md new file mode 100644 index 0000000000..88d6e4fa8b --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +libcppa +======= + +libcppa is an LGPL C++11 actor model implementation featuring lightweight & fast +actor implementations, pattern matching for messages, +network transparent messaging, and more. + + +On the Web +---------- + +* __Blog__: http://libcppa.blogspot.com +* __Manual__: http://neverlord.github.com/libcppa/manual/ +* __Documentation__: http://neverlord.github.com/libcppa/ +* __Project Homepage__: http://www.realmv6.org/libcppa.html + +Get the Sources +--------------- + +* git clone git://github.com/Neverlord/libcppa.git +* cd libcppa + + +First Steps +----------- + +* mkdir build +* cd build +* cmake .. +* make + +It is recommended to run the unit tests as well. + +* ./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. + + +Dependencies +------------ + +* CMake +* The Boost Library + + +Supported Compilers +------------------- + +* GCC >= 4.7 +* Clang >= 3.2 + + +Supported Operating Systems +--------------------------- + +* Linux +* Mac OS X diff --git a/benchmarks/ActorCreation.scala b/benchmarks/ActorCreation.scala index 3aaf1441b7..cfd9becdbf 100644 --- a/benchmarks/ActorCreation.scala +++ b/benchmarks/ActorCreation.scala @@ -104,14 +104,12 @@ object ActorCreation { if (args(0) == "threaded") { val newMax = (1 << n) + 100 System.setProperty("actors.maxPoolSize", newMax.toString) - //actor { - (new ThreadedTestee(self)).start ! Spread(n) - receive { - case Result(v) => - if (v != (1 << n)) - Console.println("ERROR: expected " + (1 << n) + ", received " + v) - } - //} + (new ThreadedTestee(self)).start ! Spread(n) + receive { + case Result(v) => + if (v != (1 << n)) + Console.println("ERROR: expected " + (1 << n) + ", received " + v) + } } else if (args(0) == "threadless") { actor { diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 0000000000..12c2a6fe13 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 2.6) +project(cppa_benchmarks CXX) + +# Set up environment paths to cmake modules and libcppa +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +add_executable(actor_creation actor_creation.cpp) +add_executable(mailbox_performance mailbox_performance.cpp) +add_executable(mixed_case mixed_case.cpp) +add_executable(distributed distributed.cpp) +add_executable(matching matching.cpp) + +# search for libs +if(NOT cppa_LIBRARY) + find_package(Libcppa REQUIRED) +endif (NOT cppa_LIBRARY) + +find_package(Boost COMPONENTS thread REQUIRED) + +link_directories(${Boost_LIBRARY_DIRS}) +include_directories(. ${cppa_INCLUDE} ${Boost_INCLUDE_DIRS}) + +set(benchmark_LIBS ${CMAKE_DL_LIBS} ${CPPA_LIBRARY} ${Boost_THREAD_LIBRARY}) + +target_link_libraries(actor_creation ${benchmark_LIBS}) +target_link_libraries(mailbox_performance ${benchmark_LIBS}) +target_link_libraries(mixed_case ${benchmark_LIBS}) +target_link_libraries(distributed ${benchmark_LIBS}) +target_link_libraries(matching ${benchmark_LIBS}) diff --git a/benchmarks/Distributed.scala b/benchmarks/Distributed.scala new file mode 100644 index 0000000000..d54e3353af --- /dev/null +++ b/benchmarks/Distributed.scala @@ -0,0 +1,374 @@ +import scala.actors._ +import scala.actors.Actor.self +import scala.actors.remote.RemoteActor +import scala.actors.remote.RemoteActor.{alive, select, register} +import scala.actors.remote.Node +import scala.actors.TIMEOUT + +import akka.actor.{ Props, Actor => AkkaActor, ActorRef => AkkaActorRef, ActorSystem } +import com.typesafe.config.ConfigFactory + +import scala.annotation.tailrec +import Console.println + +case class Ping(value: Int) +case class Pong(value: Int) +case class KickOff(value: Int) + +case object Done +case class Ok(token: String) +case class Hello(token: String) +case class Olleh(token: String) +case class Error(msg: String, token: String) +case class AddPong(path: String, token: String) + +case class AddPongTimeout(path: String, token: String) + +object global { + val latch = new java.util.concurrent.CountDownLatch(1) +} + +trait ServerActorPrototype[T] { + + protected def reply(what: Any): Unit + protected def kickOff(old: T, value: Int): Unit + protected def connectionEstablished(peers: T, pending: Any): T + protected def newPending(peers: T, path: String, token: String) : T + protected def handleTimeout(peers: T): (Boolean, T) = throw new RuntimeException("unsupported timeout") + protected def handleAddPongTimeout(peers: T, path: String, token: String): (Boolean, T) = throw new RuntimeException("unsupported timeout") + + def recvFun(peers: T { def connected: List[{ def path: String }]; def pending: List[{ def clientToken: String }] }): PartialFunction[Any, (Boolean, T)] = { + case Ping(value) => reply(Pong(value)); (false, peers) + case Hello(token) => reply(Olleh(token)); (false, peers) + case Olleh(token) => peers.pending find (_.clientToken == token) match { + case Some(x) => (true, connectionEstablished(peers, x)) + case None => (false, peers) + } + case AddPong(path, token) => { + //println("received AddPong(" + path + ", " + token + ")") + if (peers.connected exists (_.path == path)) { + reply(Ok(token)) + //println("recv[" + peers + "]: " + path + " cached (replied 'Ok')") + (false, peers) + } + else { + try { (true, newPending(peers, path, token)) } + catch { + // catches match error and integer conversion failure + case e => reply(Error(e.toString, token)); (false, peers) + } + } + } + case KickOff(value) => kickOff(peers, value); (false, peers) + case AddPongTimeout(path, token) => handleAddPongTimeout(peers, path, token) + case TIMEOUT => handleTimeout(peers) + } +} + +case class RemoteActorPath(uri: String, host: String, port: Int) + +class PingActor(parent: OutputChannel[Any], pongs: List[OutputChannel[Any]]) extends Actor { + + private var left = pongs.length + + private def recvLoop: Nothing = react { + case Pong(0) => { + parent ! Done + if (left > 1) { + left -= 1 + recvLoop + } + } + case Pong(value) => sender ! Ping(value - 1); recvLoop + } + + override def act() = react { + case KickOff(value) => pongs.foreach(_ ! Ping(value)); recvLoop + } +} + +case class Peer(path: String, channel: OutputChannel[Any]) +case class PendingPeer(path: String, channel: OutputChannel[Any], client: OutputChannel[Any], clientToken: String) +case class Peers(connected: List[Peer], pending: List[PendingPeer]) + +class ServerActor(port: Int) extends Actor with ServerActorPrototype[Peers] { + + //def reply(what: Any): Unit = sender ! what // inherited from ReplyReactor + + protected override def kickOff(peers: Peers, value: Int) = { + (new PingActor(sender, peers.connected map (_.channel))).start ! KickOff(value) + } + + protected override def connectionEstablished(peers: Peers, x: Any) = x match { + case PendingPeer(path, channel, client, token) => { + client ! Ok(token) + Peers(Peer(path, channel) :: peers.connected, peers.pending filterNot (_.clientToken == token)) + } + } + + protected def newPending(peers: Peers, path: String, token: String) : Peers = path split ":" match { + case Array(node, port) => { + val channel = select(new Node(node, port.toInt), 'Pong) + channel ! Hello(token) + //println("recv[" + peers + "]: sent 'Hello' to " + path) + Peers(peers.connected, PendingPeer(path, channel, sender, token) :: peers.pending) + } + } + + protected override def handleTimeout(peers: Peers) = { + peers.pending foreach (x => x.client ! Error("cannot connect to " + x.path, x.clientToken)) + (true, Peers(peers.connected, Nil)) + } + + override def act() { + RemoteActor classLoader = getClass().getClassLoader + alive(port) + register('Pong, self) + @tailrec def recvLoop(peers: Peers): Nothing = { + def recv(peers: Peers, receiveFun: PartialFunction[Any, (Boolean, Peers)] => (Boolean, Peers)): Peers = receiveFun(recvFun(peers))._2 + recvLoop(recv(peers, if (peers.pending isEmpty) receive else receiveWithin(5000))) + } + recvLoop(Peers(Nil, Nil)) + } + +} + +class ClientActor(pongPaths: List[RemoteActorPath], numPings: Int) extends Actor { + override def act() = { + RemoteActor classLoader = getClass().getClassLoader + val pongs = pongPaths map (x => { + val pong = select(new Node(x.host, x.port), 'Pong) + pongPaths foreach (y => if (x != y) pong ! AddPong(y.uri, x.uri + " -> " + y.uri)) + pong + }) + @tailrec def collectOkMessages(left: Int, receivedTokens: List[String]): Unit = { + if (left > 0) + collectOkMessages(left - 1, receiveWithin(10000) { + case Ok(token) => token :: receivedTokens + case Error(msg, token) => throw new RuntimeException("connection failed: " + token + ", message from server: " + msg) + case TIMEOUT => throw new RuntimeException("no Ok within 10sec.\nreceived tokens:\n" + receivedTokens.sortWith(_.compareTo(_) < 0).mkString("\n")) + }) + } + collectOkMessages(pongs.length * (pongs.length - 1), Nil) + // kickoff + pongs foreach (_ ! KickOff(numPings)) + // collect done messages + for (_ <- 1 until (pongs.length * (pongs.length - 1))) { + receiveWithin(30*60*1000) { + case Done => Unit + case TIMEOUT => throw new RuntimeException("no Done within 30min") + case x => throw new RuntimeException("Unexpected message: " + x.toString) + } + } + } +} + +case class SetParent(parent: AkkaActorRef) + +class AkkaPingActor(pongs: List[AkkaActorRef]) extends AkkaActor { + + import context.become + + private var parent: AkkaActorRef = null + private var left = pongs.length + + private def recvLoop: Receive = { + case Pong(0) => { + parent ! Done + //println(parent.toString + " ! Done") + if (left > 1) left -= 1 + else context.stop(self) + } + case Pong(value) => sender ! Ping(value - 1) + } + + def receive = { + case SetParent(p) => parent = p + case KickOff(value) => pongs.foreach(_ ! Ping(value)); become(recvLoop) + } +} + +case class AkkaPeer(path: String, channel: AkkaActorRef) +case class PendingAkkaPeer(path: String, channel: AkkaActorRef, client: AkkaActorRef, clientToken: String) +case class AkkaPeers(connected: List[AkkaPeer], pending: List[PendingAkkaPeer]) + +class AkkaServerActor(system: ActorSystem) extends AkkaActor with ServerActorPrototype[AkkaPeers] { + + import context.become + + protected def reply(what: Any): Unit = sender ! what + + protected def kickOff(peers: AkkaPeers, value: Int): Unit = { + val ping = context.actorOf(Props(new AkkaPingActor(peers.connected map (_.channel)))) + ping ! SetParent(sender) + ping ! KickOff(value) + //println("[" + peers + "]: KickOff(" + value + ")") + } + + protected def connectionEstablished(peers: AkkaPeers, x: Any): AkkaPeers = x match { + case PendingAkkaPeer(path, channel, client, token) => { + client ! Ok(token) + //println("connected to " + path) + AkkaPeers(AkkaPeer(path, channel) :: peers.connected, peers.pending filterNot (_.clientToken == token)) + } + } + + protected def newPending(peers: AkkaPeers, path: String, token: String) : AkkaPeers = { + val channel = system.actorFor(path) + channel ! Hello(token) + import akka.util.duration._ + system.scheduler.scheduleOnce(5 seconds, self, AddPongTimeout(path, token)) + //println("[" + peers + "]: sent 'Hello' to " + path) + AkkaPeers(peers.connected, PendingAkkaPeer(path, channel, sender, token) :: peers.pending) + } + + protected override def handleAddPongTimeout(peers: AkkaPeers, path: String, token: String) = { + peers.pending find (x => x.path == path && x.clientToken == token) match { + case Some(PendingAkkaPeer(_, channel, client, _)) => { + client ! Error(path + " did not respond", token) + //println(path + " did not respond") + (true, AkkaPeers(peers.connected, peers.pending filterNot (x => x.path == path && x.clientToken == token))) + } + case None => (false, peers) + } + } + + def bhvr(peers: AkkaPeers): Receive = { + case x => { + recvFun(peers)(x) match { + case (true, newPeers) => become(bhvr(newPeers)) + case _ => Unit + } + } + } + + def receive = bhvr(AkkaPeers(Nil, Nil)) + +} + +case class TokenTimeout(token: String) +case class RunAkkaClient(paths: List[String], numPings: Int) + +class AkkaClientActor(system: ActorSystem) extends AkkaActor { + + import context.become + + def collectDoneMessages(left: Int): Receive = { + case Done => { +//println("Done") + if (left == 1) { + global.latch.countDown + context.stop(self) + } else { + become(collectDoneMessages(left - 1)) + } + } + case _ => { + // ignore any other message + } + } + + def collectOkMessages(pongs: List[AkkaActorRef], left: Int, receivedTokens: List[String], numPings: Int): Receive = { + case Ok(token) => { +//println("Ok") + if (left == 1) { + //println("collected all Ok messages (wait for Done messages)") + pongs foreach (_ ! KickOff(numPings)) + become(collectDoneMessages(pongs.length * (pongs.length - 1))) + } + else { + become(collectOkMessages(pongs, left - 1, token :: receivedTokens, numPings)) + } + } + case TokenTimeout(token) => { + if (!receivedTokens.contains(token)) { + println("Error: " + token + " did not reply within 10 seconds") + global.latch.countDown + context.stop(self) + } + } + case Error(what, token) => { + println("Error [from " + token+ "]: " + what) + global.latch.countDown + context.stop(self) + } + } + + def receive = { + case RunAkkaClient(paths, numPings) => { +//println("RunAkkaClient(" + paths.toString + ", " + numPings + ")") + import akka.util.duration._ + val pongs = paths map (x => { + val pong = system.actorFor(x) + paths foreach (y => if (x != y) { + val token = x + " -> " + y + pong ! AddPong(y, token) +//println(x + " ! AddPong(" + y + ", " + token + ")") + system.scheduler.scheduleOnce(10 seconds, self, TokenTimeout(token)) + }) + pong + }) + become(collectOkMessages(pongs, pongs.length * (pongs.length - 1), Nil, numPings)) + } + } +} + +object DistributedClientApp { + + val NumPings = "num_pings=([0-9]+)".r + val SimpleUri = "([0-9a-zA-Z\\.]+):([0-9]+)".r + + @tailrec def run(args: List[String], paths: List[String], numPings: Option[Int], finalizer: (List[String], Int) => Unit): Unit = args match { + case NumPings(num) :: tail => numPings match { + case Some(x) => throw new IllegalArgumentException("\"num_pings\" already defined, first value = " + x + ", second value = " + num) + case None => run(tail, paths, Some(num.toInt), finalizer) + } + case arg :: tail => run(tail, arg :: paths, numPings, finalizer) + case Nil => numPings match { + case Some(x) => { + if (paths.length < 2) throw new RuntimeException("at least two hosts required") + finalizer(paths, x) + } + case None => throw new RuntimeException("no \"num_pings\" found") + } + } + + def main(args: Array[String]): Unit = { + try { + args(0) match { + case "remote_actors" => run(args.toList.drop(1), Nil, None, ((paths, x) => { + (new ClientActor(paths map (path => path match { case SimpleUri(host, port) => RemoteActorPath(path, host, port.toInt) }), x)).start + })) + case "akka" => run(args.toList.drop(1), Nil, None, ((paths, x) => { + val system = ActorSystem("benchmark", ConfigFactory.load.getConfig("benchmark")) + system.actorOf(Props(new AkkaClientActor(system))) ! RunAkkaClient(paths, x) + global.latch.await + system.shutdown + System.exit(0) + })) + } + } + catch { + case e => { + println("usage: DistributedClientApp (remote_actors|akka) {nodes...} num_pings={num}\nexample: DistributedClientApp remote_actors localhost:1234 localhost:2468 num_pings=1000\n") + throw e + } + } + } +} + +object DistributedServerApp { + + val IntStr = "([0-9]+)".r + + def main(args: Array[String]): Unit = args match { + case Array("remote_actors", IntStr(istr)) => (new ServerActor(istr.toInt)).start + case Array("akka") => { + val system = ActorSystem("pongServer", ConfigFactory.load.getConfig("pongServer")) + val pong = system.actorOf(Props(new AkkaServerActor(system)), "pong") + Unit + } + case _ => println("usage: DistributedServerApp remote_actors PORT\n" + + " or: DistributedServerApp akka") + } +} diff --git a/benchmarks/FindLibcppa.cmake b/benchmarks/FindLibcppa.cmake new file mode 100644 index 0000000000..c1f1d2236a --- /dev/null +++ b/benchmarks/FindLibcppa.cmake @@ -0,0 +1,65 @@ +# - Try to find libcppa +# Once done this will define +# +# CPPA_FOUND - system has libcppa +# CPPA_INCLUDE - libcppa include dir +# CPPA_LIBRARY - link againgst libcppa +# + +if (CPPA_LIBRARY AND CPPA_INCLUDE) + set(CPPA_FOUND TRUE) +else (CPPA_LIBRARY AND CPPA_INCLUDE) + + find_path(CPPA_INCLUDE + NAMES + cppa/cppa.hpp + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ${CPPA_INCLUDE_PATH} + ${CPPA_LIBRARY_PATH} + ${CMAKE_INCLUDE_PATH} + ${CMAKE_INSTALL_PREFIX}/include + ) + + if (CPPA_INCLUDE) + message (STATUS "Header files found ...") + else (CPPA_INCLUDE) + message (SEND_ERROR "Header files NOT found. Provide absolute path with -DCPPA_INCLUDE_PATH=.") + endif (CPPA_INCLUDE) + + find_library(CPPA_LIBRARY + NAMES + libcppa + cppa + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ${CPPA_INCLUDE_PATH} + ${CPPA_INCLUDE_PATH}/.libs + ${CPPA_LIBRARY_PATH} + ${CPPA_LIBRARY_PATH}/.libs + ${CMAKE_LIBRARY_PATH} + ${CMAKE_INSTALL_PREFIX}/lib + ${LIBRARY_OUTPUT_PATH} + ) + + if (CPPA_LIBRARY) + message (STATUS "Library found ...") + else (CPPA_LIBRARY) + message (SEND_ERROR "Library NOT found. Provide absolute path with -DCPPA_LIBRARY_PATH=.") + endif (CPPA_LIBRARY) + + if (CPPA_INCLUDE AND CPPA_LIBRARY) + set(CPPA_FOUND TRUE) + set(CPPA_INCLUDE ${CPPA_INCLUDE}) + set(CPPA_LIBRARY ${CPPA_LIBRARY}) + else (CPPA_INCLUDE AND CPPA_LIBRARY) + message (FATAL_ERROR "CPPA LIBRARY AND/OR HEADER NOT FOUND!") + endif (CPPA_INCLUDE AND CPPA_LIBRARY) + +endif (CPPA_LIBRARY AND CPPA_INCLUDE) diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am deleted file mode 100644 index c1f35e99e5..0000000000 --- a/benchmarks/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -AUTOMAKE_OPTIONS = subdir-objects -ACLOCAL_AMFLAGS = -I ../m4 - -AM_CXXFLAGS = -I../ --std=c++0x -pedantic -Wall -Wextra - -noinst_PROGRAMS = actor_creation mailbox_performance mixed_case matching - -actor_creation_SOURCES = actor_creation.cpp -mailbox_performance_SOURCES = mailbox_performance.cpp -mixed_case_SOURCES = mixed_case.cpp -matching_SOURCES = matching.cpp - -EXAMPLES_LIBS = -L../.libs/ -lcppa $(BOOST_LDFLAGS) $(BOOST_THREAD_LIB) - -actor_creation_LDADD = $(EXAMPLES_LIBS) -mailbox_performance_LDADD = $(EXAMPLES_LIBS) -mixed_case_LDADD = $(EXAMPLES_LIBS) -matching_LDADD = $(EXAMPLES_LIBS) diff --git a/benchmarks/actor_creation.cpp b/benchmarks/actor_creation.cpp index 002e07a000..e5f7ef6b23 100644 --- a/benchmarks/actor_creation.cpp +++ b/benchmarks/actor_creation.cpp @@ -35,7 +35,7 @@ #include "utility.hpp" #include "cppa/cppa.hpp" -#include "cppa/fsm_actor.hpp" +#include "cppa/sb_actor.hpp" using std::cout; using std::cerr; @@ -44,34 +44,25 @@ using std::uint32_t; using namespace cppa; -struct testee : fsm_actor -{ +struct testee : sb_actor { actor_ptr parent; behavior init_state; - testee(const actor_ptr& pptr) : parent(pptr) - { - init_state = - ( - on(atom("spread"), 0) >> [=]() - { + testee(const actor_ptr& pptr) : parent(pptr) { + init_state = ( + on(atom("spread"), 0) >> [=]() { send(parent, atom("result"), (uint32_t) 1); - become_void(); + quit(); }, - on() >> [=](int x) - { + on() >> [=](int x) { any_tuple msg = make_cow_tuple(atom("spread"), x - 1); - spawn(new testee(this)) << msg; - spawn(new testee(this)) << msg; - become - ( - on() >> [=](uint32_t r1) - { - become - ( - on() >> [=](uint32_t r2) - { + spawn(this) << msg; + spawn(this) << msg; + become ( + on() >> [=](uint32_t r1) { + become ( + on() >> [=](uint32_t r2) { send(parent, atom("result"), r1 + r2); - become_void(); + quit(); } ); } @@ -81,27 +72,19 @@ struct testee : fsm_actor } }; -void stacked_testee(actor_ptr parent) -{ - receive - ( - on(atom("spread"), 0) >> [&]() - { +void stacked_testee(actor_ptr parent) { + receive ( + on(atom("spread"), 0) >> [&]() { send(parent, atom("result"), (uint32_t) 1); }, - on() >> [&](int x) - { + on() >> [&](int x) { any_tuple msg = make_cow_tuple(atom("spread"), x-1); spawn(stacked_testee, self) << msg; spawn(stacked_testee, self) << msg; - receive - ( - on() >> [&](uint32_t v1) - { - receive - ( - on() >> [&](uint32_t v2) - { + receive ( + on() >> [&](uint32_t v1) { + receive ( + on() >> [&](uint32_t v2) { send(parent, atom("result"), v1 + v2); } ); @@ -111,45 +94,38 @@ void stacked_testee(actor_ptr parent) ); } -void usage() -{ +void usage() { cout << "usage: actor_creation (stacked|event-based) POW" << endl << " creates 2^POW actors" << endl << endl; } -int main(int argc, char** argv) -{ - if (argc == 3) - { +int main(int argc, char** argv) { + if (argc == 3) { int num = rd(argv[2]); - if (strcmp(argv[1], "stacked") == 0) - { + if (strcmp(argv[1], "stacked") == 0) { send(spawn(stacked_testee, self), atom("spread"), num); } - else if (strcmp(argv[1], "event-based") == 0) - { - send(spawn(new testee(self)), atom("spread"), num); + else if (strcmp(argv[1], "event-based") == 0) { + send(spawn(self), atom("spread"), num); } - else - { + else { usage(); return 1; } - receive - ( - on() >> [=](uint32_t value) - { + receive ( + on() >> [=](uint32_t value) { //cout << "value = " << value << endl // << "expected => 2^" << num << " = " // << (1 << num) << endl; - assert(value == (((uint32_t) 1) << num)); + if (value != (((uint32_t) 1) << num)) { + cerr << "ERROR: received wrong result!\n"; + } } ); await_all_others_done(); } - else - { + else { usage(); return 1; } diff --git a/benchmarks/application.conf b/benchmarks/application.conf new file mode 100644 index 0000000000..d1c6062969 --- /dev/null +++ b/benchmarks/application.conf @@ -0,0 +1,36 @@ +benchmark { + akka { + loglevel = ERROR + actor.provider = "akka.remote.RemoteActorRefProvider" + remote { + transport = "akka.remote.netty.NettyRemoteTransport" + untrusted-mode = on +# remote-daemon-ack-timeout = 300s +# netty { +# connection-timeout = 1800s +# } + } + } +} +pongServer { + akka { + loglevel = ERROR + actor { + provider = "akka.remote.RemoteActorRefProvider" + } + remote { + transport = "akka.remote.netty.NettyRemoteTransport" + untrusted-mode = on +# remote-daemon-ack-timeout = 300s + netty { +# backoff-timeout = 0ms + connection-timeout = 1800s +# read-timeout = 1800s +# write-timeout = 10s + all-timeout = 1800s + #hostname = "mobi10" + port = 2244 + } + } + } +} diff --git a/benchmarks/distributed.cpp b/benchmarks/distributed.cpp new file mode 100644 index 0000000000..5f4954ffb0 --- /dev/null +++ b/benchmarks/distributed.cpp @@ -0,0 +1,407 @@ +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + + +#include +#include +#include + +#include +#include + +#include "utility.hpp" +#include "cppa/cppa.hpp" +#include "cppa/match.hpp" +#include "cppa/actor_proxy.hpp" + +using std::cout; +using std::endl; +using std::string; +using std::uint16_t; +using std::uint32_t; + +using namespace cppa; +using namespace cppa::placeholders; + +#define PRINT_MESSAGE() { \ +std::ostringstream oss; \ +oss << to_string(self->parent_process()) << ": " << __PRETTY_FUNCTION__ << " ->" \ + << to_string(self->last_dequeued()) \ + << "\n"; \ +cout << oss.str(); \ +} ((void) 0) + +option c_2i(const char* cstr) { + char* endptr = nullptr; + int result = static_cast(strtol(cstr, &endptr, 10)); + if (endptr == nullptr || *endptr != '\0') { + return {}; + } + return result; +} + +inline option _2i(const std::string& str) { + return c_2i(str.c_str()); +} + +void usage() { + cout << "Running in server mode:" << endl + << " mode=server " << endl + << " --port=NUM publishes an actor at port NUM" << endl + << " -p NUM alias for --port=NUM" << endl + << endl + << endl + << "Running the benchmark:" << endl + << " mode=benchmark run the benchmark, connect to any number" << endl + << " of given servers, use HOST:PORT syntax" << endl + << " num_pings=NUM run benchmark with NUM messages per node" << endl + << endl + << " example: mode=benchmark 192.168.9.1:1234 " + "192.168.9.2:1234 " + "--num_pings=100" << endl + << endl + << endl + << "Shutdown servers:" << endl + << " mode=shutdown shuts down any number of given servers" << endl + << endl + << endl + << "Miscellaneous:" << endl + << " -h, --help print this text and exit" << endl + << endl; + exit(0); +} + +template +class actor_template { + + MatchExpr m_expr; + + public: + + actor_template(MatchExpr me) : m_expr(std::move(me)) { } + + actor_ptr spawn() const { + struct impl : sb_actor { + behavior init_state; + impl(const MatchExpr& mx) : init_state(mx.as_partial_function()) { + } + }; + return cppa::spawn(new impl{m_expr}); + } + +}; + +template +auto actor_prototype(const Args&... args) -> actor_template { + return {mexpr_concat(args...)}; +} + +struct ping_actor : sb_actor { + + behavior init_state; + actor_ptr parent; + + ping_actor(actor_ptr parent_ptr) : parent(std::move(parent_ptr)) { + init_state = ( + on(atom("kickoff"), arg_match) >> [=](actor_ptr pong, uint32_t value) { + send(pong, atom("ping"), value); + become ( + on().when(_x2 == uint32_t(0)) >> [=]() { + send(parent, atom("done")); + quit(); + }, + on(atom("pong"), arg_match) >> [=](uint32_t value) { + reply(atom("ping"), value - 1); + }, + others() >> [=]() { + cout << "ping_actor: unexpected: " + << to_string(last_dequeued()) + << endl; + } + ); + }, + others() >> [=]() { + cout << "ping_actor: unexpected: " + << to_string(last_dequeued()) + << endl; + } + ); + } + +}; + +struct server_actor : sb_actor { + + typedef std::map, actor_ptr> pong_map; + + behavior init_state; + pong_map m_pongs; + + server_actor() { + trap_exit(true); + init_state = ( + on(atom("ping"), arg_match) >> [=](uint32_t value) { + reply(atom("pong"), value); + }, + on(atom("add_pong"), arg_match) >> [=](const string& host, uint16_t port) { + auto key = std::make_pair(host, port); + auto i = m_pongs.find(key); + if (i == m_pongs.end()) { + try { + auto p = remote_actor(host.c_str(), port); + link_to(p); + m_pongs.insert(std::make_pair(key, p)); + reply(atom("ok")); + } + catch (std::exception& e) { + reply(atom("error"), e.what()); + } + } + else { + reply(atom("ok")); + } + }, + on(atom("kickoff"), arg_match) >> [=](uint32_t num_pings) { + for (auto& kvp : m_pongs) { + auto ping = spawn(last_sender()); + send(ping, atom("kickoff"), kvp.second, num_pings); + } + }, + on(atom("purge")) >> [=]() { + m_pongs.clear(); + }, + on() >> [=]() { + actor_ptr who = last_sender(); + auto i = std::find_if(m_pongs.begin(), m_pongs.end(), + [&](const pong_map::value_type& kvp) { + return kvp.second == who; + }); + if (i != m_pongs.end()) m_pongs.erase(i); + }, + on(atom("shutdown")) >> [=]() { + m_pongs.clear(); + quit(); + }, + others() >> [=]() { + cout << "unexpected: " << to_string(last_dequeued()) << endl; + } + + ); + } + +}; + +template +void usage(Arg0&& arg0) { + cout << std::forward(arg0) << endl << endl; + usage(); +} + +template +void usage(Arg0&& arg0, Arg1&& arg1, Args&&... args) { + cout << std::forward(arg0); + usage(std::forward(arg1), std::forward(args)...); +} + +template +void server_mode(Iterator first, Iterator last) { + string port_prefix = "--port="; + // extracts port from a key-value pair + auto kvp_port = [&](const string& str) -> option { + if (std::equal(port_prefix.begin(), port_prefix.end(), str.begin())) { + return c_2i(str.c_str() + port_prefix.size()); + } + return {}; + }; + match(std::vector{first, last}) ( (on(kvp_port) || on("-p", _2i)) >> [](int port) { + if (port > 1024 && port < 65536) { + publish(spawn(), port); + } + else { + usage("illegal port: ", port); + } + }, + others() >> [=]() { + if (first != last) usage("illegal argument: ", *first); + else usage(); + } + ); + await_all_others_done(); +} + +template +void client_mode(Iterator first, Iterator last) { + if (first == last) usage("no server, no fun"); + std::uint32_t init_value = 0; + std::vector > remotes; + string pings_prefix = "--num_pings="; + auto num_msgs = [&](const string& str) -> option { + if (std::equal(pings_prefix.begin(), pings_prefix.end(), str.begin())) { + return c_2i(str.c_str() + pings_prefix.size()); + } + return {}; + }; + match_each(first, last, std::bind(split, std::placeholders::_1, ':')) ( + on(val, _2i) >> [&](string& host, int port) { + if (port <= 1024 || port >= 65536) { + throw std::invalid_argument("illegal port: " + std::to_string(port)); + } + remotes.emplace_back(std::move(host), static_cast(port)); + }, + on(num_msgs) >> [&](int num) { + if (num > 0) init_value = static_cast(num); + } + ); + if (init_value == 0) { + cout << "no non-zero, non-negative init value given" << endl; + exit(1); + } + if (remotes.size() < 2) { + cout << "less than two nodes given" << endl; + exit(1); + } + std::vector remote_actors; + for (auto& r : remotes) { + remote_actors.push_back(remote_actor(r.first.c_str(), r.second)); + } + // setup phase + //cout << "tell server nodes to connect to each other" << endl; + for (size_t i = 0; i < remotes.size(); ++i) { + for (size_t j = 0; j < remotes.size(); ++j) { + if (i != j) { + auto& r = remotes[j]; + send(remote_actors[i], atom("add_pong"), r.first, r.second); + } + } + } + { // collect {ok} messages + size_t i = 0; + size_t end = remote_actors.size() * (remote_actors.size() - 1); + receive_for(i, end) ( + on(atom("ok")) >> []() { + }, + on(atom("error"), arg_match) >> [&](const string& str) { + cout << "error: " << str << endl; + for (auto& x : remote_actors) { + send(x, atom("purge")); + } + throw std::logic_error(""); + }, + others() >> []() { + cout << "expected {ok|error}, received: " + << to_string(self->last_dequeued()) + << endl; + throw std::logic_error(""); + }, + after(std::chrono::seconds(10)) >> [&]() { + cout << "remote didn't answer within 10sec." << endl; + for (auto& x : remote_actors) { + send(x, atom("purge")); + } + throw std::logic_error(""); + } + ); + } + // kickoff + //cout << "setup done" << endl; + //cout << "kickoff, init value = " << init_value << endl; + for (auto& r : remote_actors) { + send(r, atom("kickoff"), init_value); + } + { // collect {done} messages + size_t i = 0; + size_t end = remote_actors.size() * (remote_actors.size() - 1); + receive_for(i, end) ( + on(atom("done")) >> []() { + //cout << "...done..." << endl; + }, + others() >> []() { + cout << "unexpected: " << to_string(self->last_dequeued()) << endl; + throw std::logic_error(""); + } + ); + } + await_all_others_done(); +} + +template +void shutdown_mode(Iterator first, Iterator last) { + std::vector > remotes; + match_each(first, last, std::bind(split, std::placeholders::_1, ':')) ( + on(val, _2i) >> [&](string& host, int port) { + if (port <= 1024 || port >= 65536) { + throw std::invalid_argument("illegal port: " + std::to_string(port)); + } + remotes.emplace_back(std::move(host), static_cast(port)); + } + ); + for (auto& r : remotes) { + try { + actor_ptr x = remote_actor(r.first.c_str(), r.second); + self->monitor(x); + send(x, atom("shutdown")); + receive ( + on(atom("DOWN"), val) >> []() { + // ok, done + }, + after(std::chrono::seconds(10)) >> [&]() { + cout << r.first << ":" << r.second << " didn't shut down " + << "within 10s" + << endl; + } + ); + } + catch (...) { + } + } +} + +int main(int argc, char** argv) { + if (argc < 2) usage(); + auto first = argv + 1; + auto last = argv + argc; + match(*first) ( + on().when(_x1.in({"-h", "--help"})) >> []() { + usage(); + }, + on("mode=server") >> [=]() { + server_mode(first + 1, last); + }, + on("mode=benchmark") >> [=]() { + client_mode(first + 1, last); + await_all_others_done(); + }, + on("mode=shutdown") >> [=]() { + shutdown_mode(first + 1, last); + }, + others() >> [=]() { + usage("unknown argument: ", *first); + } + ); +} diff --git a/benchmarks/distributed.erl b/benchmarks/distributed.erl new file mode 100644 index 0000000000..8bb4da68db --- /dev/null +++ b/benchmarks/distributed.erl @@ -0,0 +1,107 @@ +-module(distributed). +-export([start/1, ping_loop/2]). + +ping_loop(Parent, Pong) -> + receive + {pong, 0} -> Parent ! done; + {pong, X} -> + Pong ! {ping, self(), X - 1}, + ping_loop(Parent, Pong); + {kickoff, X} -> + Pong ! {ping, self(), X}, + ping_loop(Parent, Pong); + _ -> ping_loop(Parent, Pong) + end. + +server_loop(Pongs) -> + receive + {ping, Pid, X} -> + Pid ! {pong, X}, + server_loop(Pongs); + {add_pong, Pid, Node} -> + case lists:any(fun({N, _}) -> N == Node end, Pongs) of + true -> + Pid ! {ok, cached}, + server_loop(Pongs); + false -> + case rpc:call(Node, erlang, whereis, [pong]) of + {badrpc, Reason} -> + Pid ! {error, Reason}, + server_loop(Pongs); + undefined -> + Pid ! {error, 'pong is undefined'}, + server_loop(Pongs); + Pong -> + Pid ! {ok, added}, + server_loop(Pongs ++ [{Node, Pong}]) + end + end; + {purge} -> server_loop([]); + {get_pongs, Pid} -> + Pid ! Pongs, + server_loop(Pongs); + {kickoff, Pid, NumPings} -> + lists:foreach(fun({_, P}) -> spawn(distributed, ping_loop, [Pid, P]) ! {kickoff, NumPings} end, Pongs), + server_loop(Pongs); + _ -> server_loop(Pongs) + end. + +server_mode() -> + register(pong, self()), + server_loop([]). + +add_pong_fun(_, _, []) -> true; +add_pong_fun(Pong, Node, [Node|T]) -> add_pong_fun(Pong, Node, T); +add_pong_fun(Pong, Node, [H|T]) -> + Pong ! {add_pong, self(), H}, + receive + {ok, _} -> add_pong_fun(Pong, Node, T); + {error, Reason} -> error(Reason) + after 10000 -> error(timeout) + end. + +client_mode_receive_done_msgs(0) -> true; +client_mode_receive_done_msgs(Left) -> + receive done -> client_mode_receive_done_msgs(Left - 1) end. + + +% receive a {done} message for each node +client_mode([], [], [], _) -> error("no node, no fun"); +client_mode([], [], Nodes, _) -> + client_mode_receive_done_msgs(length(Nodes) * (length(Nodes) - 1)); + +% send kickoff messages +client_mode([Pong|Pongs], [], Nodes, NumPings) -> + Pong ! {kickoff, self(), NumPings}, + client_mode(Pongs, [], Nodes, NumPings); + +client_mode(Pongs, [H|T], Nodes, NumPings) -> + case rpc:call(H, erlang, whereis, [pong]) of + {badrpc, Reason} -> + io:format("cannot connect to ~s~n", [atom_to_list(H)]), + error(Reason); + undefined -> + io:format("no 'pong' defined on node ~s~n", [atom_to_list(H)]); + P -> + add_pong_fun(P, H, Nodes), + client_mode(Pongs ++ [P], T, Nodes, NumPings) + end. + +run(_, undefined, []) -> error("NumPings is undefined"); +run(Hosts, _, []) when length(Hosts) < 2 -> error("less than two nodes specified"); +run(Hosts, NumPings, []) -> client_mode([], Hosts, Hosts, NumPings); +run(Hosts, NumPings, [H|T]) -> + Arg = atom_to_list(H), + case lists:prefix("num_pings=", Arg) of + true when NumPings /= undefined -> error("NumPings already set"); + true -> run(Hosts, list_to_integer(lists:sublist(Arg, 11, length(Arg))), T); + false -> run(Hosts ++ [H], NumPings, T) + end. + +start(X) -> + case X of + ['mode=server'|[]] -> server_mode(); + ['mode=server'|_] -> io:format("too much arguments~n", []); + ['mode=benchmark'|T] -> run([], undefined, T); + _ -> io:format("invalid arguments~n", []) + end. diff --git a/benchmarks/erlang_test.sh b/benchmarks/erlang_test.sh index 229d0e6f19..17599c1d47 100755 --- a/benchmarks/erlang_test.sh +++ b/benchmarks/erlang_test.sh @@ -1,2 +1,2 @@ #!/bin/bash -echo "erl -noshell -noinput +P 20000000 -s $@ -s init stop" | ./exec.sh +echo "erl -noshell -noinput +P 20000000 -setcookie abc123 -sname benchmark -s $@ -s init stop" | ./exec.sh diff --git a/benchmarks/mailbox_performance.cpp b/benchmarks/mailbox_performance.cpp index 5705f076db..8592fa5825 100644 --- a/benchmarks/mailbox_performance.cpp +++ b/benchmarks/mailbox_performance.cpp @@ -28,6 +28,7 @@ \******************************************************************************/ +#include #include #include #include @@ -35,8 +36,7 @@ #include "utility.hpp" #include "cppa/cppa.hpp" -#include "cppa/fsm_actor.hpp" -#include "cppa/detail/thread.hpp" +#include "cppa/sb_actor.hpp" using std::cout; using std::cerr; @@ -45,83 +45,64 @@ using std::int64_t; using namespace cppa; -struct fsm_receiver : fsm_actor -{ +struct fsm_receiver : sb_actor { int64_t m_value; behavior init_state; - fsm_receiver(int64_t max) : m_value(0) - { - init_state = - ( - on(atom("msg")) >> [=]() - { + fsm_receiver(int64_t max) : m_value(0) { + init_state = ( + on(atom("msg")) >> [=]() { ++m_value; - if (m_value == max) - { - become_void(); + if (m_value == max) { + quit(); } } ); } }; -void receiver(int64_t max) -{ +void receiver(int64_t max) { int64_t value; - receive_while(gref(value) < max) - //receive_while([&]() { return value < max; }) - ( - on(atom("msg")) >> [&]() - { + receive_while(gref(value) < max) ( + on(atom("msg")) >> [&]() { ++value; } ); } -void sender(actor_ptr whom, int64_t count) -{ +void sender(actor_ptr whom, int64_t count) { any_tuple msg = make_cow_tuple(atom("msg")); - for (int64_t i = 0; i < count; ++i) - { + for (int64_t i = 0; i < count; ++i) { whom->enqueue(nullptr, msg); } } -void usage() -{ +void usage() { cout << "usage: mailbox_performance " "(stacked|event-based) (sending threads) (msg per thread)" << endl << endl; } -int main(int argc, char** argv) -{ - if (argc == 4) - { +int main(int argc, char** argv) { + if (argc == 4) { int64_t num_sender = rd(argv[2]); int64_t num_msgs = rd(argv[3]); actor_ptr testee; - if (strcmp(argv[1], "stacked") == 0) - { + if (strcmp(argv[1], "stacked") == 0) { testee = spawn(receiver, num_sender * num_msgs); } - else if (strcmp(argv[1], "event-based") == 0) - { - testee = spawn(new fsm_receiver(num_sender * num_msgs)); + else if (strcmp(argv[1], "event-based") == 0) { + testee = spawn(num_sender * num_msgs); } - else - { + else { usage(); return 1; } - for (int64_t i = 0; i < num_sender; ++i) - { - detail::thread(sender, testee, num_msgs).detach(); + for (int64_t i = 0; i < num_sender; ++i) { + std::thread(sender, testee, num_msgs).detach(); } await_all_others_done(); } - else - { + else { usage(); return 1; } diff --git a/benchmarks/matching.cpp b/benchmarks/matching.cpp index dc59dcaaaf..0d7936c32b 100644 --- a/benchmarks/matching.cpp +++ b/benchmarks/matching.cpp @@ -53,12 +53,10 @@ using std::int64_t; using namespace cppa; template -T rd(char const* cstr) -{ +T rd(const char* cstr) { char* endptr = nullptr; T result = static_cast(strtol(cstr, &endptr, 10)); - if (endptr == nullptr || *endptr != '\0') - { + if (endptr == nullptr || *endptr != '\0') { std::string errstr; errstr += "\""; errstr += cstr; @@ -68,29 +66,71 @@ T rd(char const* cstr) return result; } -int main(int argc, char** argv) -{ +void usage() { + cerr << "usage: matching (cow_tuple|object_array) {NUM_LOOPS}" << endl; + exit(1); +} + +int main(int argc, char** argv) { announce>(); - if (argc != 2) - { - cerr << "usage: matching {NUM_LOOPS}" << endl; - return 1; + if (argc != 3) usage(); + auto num_loops = rd(argv[2]); + any_tuple m1; + any_tuple m2; + any_tuple m3; + any_tuple m4; + any_tuple m5; + any_tuple m6; + + if (strcmp(argv[1], "cow_tuple") == 0) { + m1 = make_cow_tuple(atom("msg1"), 0); + m2 = make_cow_tuple(atom("msg2"), 0.0); + m3 = make_cow_tuple(atom("msg3"), list{0}); + m4 = make_cow_tuple(atom("msg4"), 0, "0"); + m5 = make_cow_tuple(atom("msg5"), 0, 0, 0); + m6 = make_cow_tuple(atom("msg6"), 0, 0.0, "0"); + } + else if (strcmp(argv[1], "object_array") == 0) { + auto m1o = new detail::object_array; + m1o->push_back(object::from(atom("msg1"))); + m1o->push_back(object::from(0)); + m1 = any_tuple{m1o}; + auto m2o = new detail::object_array; + m2o->push_back(object::from(atom("msg2"))); + m2o->push_back(object::from(0.0)); + m2 = any_tuple{m2o}; + auto m3o = new detail::object_array; + m3o->push_back(object::from(atom("msg3"))); + m3o->push_back(object::from(list{0})); + m3 = any_tuple{m3o}; + auto m4o = new detail::object_array; + m4o->push_back(object::from(atom("msg4"))); + m4o->push_back(object::from(0)); + m4o->push_back(object::from(std::string("0"))); + m4 = any_tuple{m4o}; + auto m5o = new detail::object_array; + m5o->push_back(object::from(atom("msg5"))); + m5o->push_back(object::from(0)); + m5o->push_back(object::from(0)); + m5o->push_back(object::from(0)); + m5 = any_tuple{m5o}; + auto m6o = new detail::object_array; + m6o->push_back(object::from(atom("msg6"))); + m6o->push_back(object::from(0)); + m6o->push_back(object::from(0.0)); + m6o->push_back(object::from(std::string("0"))); + m6 = any_tuple{m6o}; + } + else { + usage(); } - auto num_loops = rd(argv[1]); - any_tuple m1 = make_cow_tuple(atom("msg1"), 0); - any_tuple m2 = make_cow_tuple(atom("msg2"), 0.0); - any_tuple m3 = cppa::make_cow_tuple(atom("msg3"), list{0}); - any_tuple m4 = make_cow_tuple(atom("msg4"), 0, "0"); - any_tuple m5 = make_cow_tuple(atom("msg5"), 0, 0, 0); - any_tuple m6 = make_cow_tuple(atom("msg6"), 0, 0.0, "0"); int64_t m1matched = 0; int64_t m2matched = 0; int64_t m3matched = 0; int64_t m4matched = 0; int64_t m5matched = 0; int64_t m6matched = 0; - auto part_fun = - ( + auto part_fun = ( on() >> [&]() { ++m1matched; }, on() >> [&]() { ++m2matched; }, on >() >> [&]() { ++m3matched; }, @@ -98,8 +138,7 @@ int main(int argc, char** argv) on() >> [&]() { ++m5matched; }, on() >> [&]() { ++m6matched; } ); - for (int64_t i = 0; i < num_loops; ++i) - { + for (int64_t i = 0; i < num_loops; ++i) { part_fun(m1); part_fun(m2); part_fun(m3); @@ -107,4 +146,10 @@ int main(int argc, char** argv) part_fun(m5); part_fun(m6); } + assert(m1matched == num_loops); + assert(m2matched == num_loops); + assert(m3matched == num_loops); + assert(m4matched == num_loops); + assert(m5matched == num_loops); + assert(m6matched == num_loops); } diff --git a/benchmarks/mixed_case.cpp b/benchmarks/mixed_case.cpp index 9cbaba9aa1..79ba40e924 100644 --- a/benchmarks/mixed_case.cpp +++ b/benchmarks/mixed_case.cpp @@ -35,79 +35,10 @@ #include "utility.hpp" -//#include "boost/threadpool.hpp" - #include "cppa/cppa.hpp" -#include "cppa/fsm_actor.hpp" -#include "cppa/detail/mock_scheduler.hpp" -#include "cppa/detail/yielding_actor.hpp" - -/* -namespace cppa { namespace detail { - -struct pool_job -{ - abstract_event_based_actor* ptr; - pool_job(abstract_event_based_actor* mptr) : ptr(mptr) { } - void operator()() - { - struct handler : abstract_scheduled_actor::resume_callback - { - abstract_event_based_actor* job; - handler(abstract_event_based_actor* mjob) : job(mjob) { } - void exec_done() - { - if (!job->deref()) delete job; - dec_actor_count(); - } - }; - handler h{ptr}; - ptr->resume(nullptr, &h); - } -}; - -class boost_threadpool_scheduler : public scheduler -{ - - boost::threadpool::thread_pool m_pool; - //boost::threadpool::pool m_pool; - - public: - - void start() - { - m_pool.size_controller().resize(std::max(num_cores(), 4)); - } - - void stop() - { - m_pool.wait(); - } - void enqueue(abstract_scheduled_actor* what) - { - auto job = static_cast(what); - boost::threadpool::schedule(m_pool, pool_job{job}); - } - - actor_ptr spawn(abstract_event_based_actor* what) - { - what->attach_to_scheduler(this); - inc_actor_count(); - CPPA_MEMORY_BARRIER(); - intrusive_ptr ctx(what); - ctx->ref(); - return std::move(ctx); - } - - actor_ptr spawn(scheduled_actor* bhvr, scheduling_hint) - { - return mock_scheduler::spawn(bhvr); - } - -}; - -} } // namespace cppa::detail -*/ +#include "cppa/match.hpp" +#include "cppa/sb_actor.hpp" +#include "cppa/context_switching_actor.hpp" using std::cout; using std::cerr; @@ -123,93 +54,75 @@ constexpr uint64_t s_task_n = uint64_t(86028157)*329545133; constexpr uint64_t s_factor1 = 86028157; constexpr uint64_t s_factor2 = 329545133; -void check_factors(const factors& vec) -{ +void check_factors(const factors& vec) { assert(vec.size() == 2); assert(vec[0] == s_factor1); assert(vec[1] == s_factor2); +# ifdef NDEBUG + static_cast(vec); +# endif } -struct fsm_worker : fsm_actor -{ +struct fsm_worker : sb_actor { actor_ptr mc; behavior init_state; - fsm_worker(const actor_ptr& msgcollector) : mc(msgcollector) - { - init_state = - ( - on() >> [=](uint64_t what) - { + fsm_worker(const actor_ptr& msgcollector) : mc(msgcollector) { + init_state = ( + on() >> [=](uint64_t what) { send(mc, atom("result"), factorize(what)); }, - on(atom("done")) >> [=]() - { - become_void(); + on(atom("done")) >> [=]() { + quit(); } ); } }; -struct fsm_chain_link : fsm_actor -{ +struct fsm_chain_link : sb_actor { actor_ptr next; behavior init_state; - fsm_chain_link(const actor_ptr& n) : next(n) - { - init_state = - ( - on() >> [=](int v) - { - next->enqueue(nullptr, std::move(self->last_dequeued())); - if (v == 0) become_void(); + fsm_chain_link(const actor_ptr& n) : next(n) { + init_state = ( + on() >> [=](int v) { + next << std::move(last_dequeued()); + if (v == 0) quit(); } ); } }; -struct fsm_chain_master : fsm_actor -{ +struct fsm_chain_master : sb_actor { int iteration; actor_ptr mc; actor_ptr next; actor_ptr worker; behavior init_state; - void new_ring(int ring_size, int initial_token_value) - { + void new_ring(int ring_size, int initial_token_value) { send(worker, atom("calc"), s_task_n); next = self; - for (int i = 1; i < ring_size; ++i) - { - next = spawn(new fsm_chain_link(next)); + for (int i = 1; i < ring_size; ++i) { + next = spawn(next); } send(next, atom("token"), initial_token_value); } - fsm_chain_master(actor_ptr msgcollector) : iteration(0), mc(msgcollector) - { - init_state = - ( - on() >> [=](int rs, int itv, int n) - { - worker = spawn(new fsm_worker(msgcollector)); + fsm_chain_master(actor_ptr msgcollector) : iteration(0), mc(msgcollector) { + init_state = ( + on(atom("init"), arg_match) >> [=](int rs, int itv, int n) { + worker = spawn(msgcollector); iteration = 0; new_ring(rs, itv); - become - ( - on(atom("token"), 0) >> [=]() - { - if (++iteration < n) - { + become ( + on(atom("token"), 0) >> [=]() { + if (++iteration < n) { new_ring(rs, itv); } - else - { + else { send(worker, atom("done")); send(mc, atom("masterdone")); - become_void(); + quit(); } }, - on() >> [=](int v) - { + on() >> [=](int v) { send(next, atom("token"), v - 1); } ); @@ -218,93 +131,71 @@ struct fsm_chain_master : fsm_actor } }; -struct fsm_supervisor : fsm_actor -{ +struct fsm_supervisor : sb_actor { int left; behavior init_state; - fsm_supervisor(int num_msgs) : left(num_msgs) - { - init_state = - ( - on(atom("masterdone")) >> [=]() - { - if (--left == 0) become_void(); + fsm_supervisor(int num_msgs) : left(num_msgs) { + init_state = ( + on(atom("masterdone")) >> [=]() { + if (--left == 0) quit(); }, - on() >> [=](const factors& vec) - { + on() >> [=](const factors& vec) { check_factors(vec); - if (--left == 0) become_void(); + if (--left == 0) quit(); } ); } }; -void chain_link(actor_ptr next) -{ +void chain_link(actor_ptr next) { bool done = false; - do_receive - ( - on() >> [&](int v) - { - next << self->last_dequeued(); - if (v == 0) - { + do_receive ( + on() >> [&](int v) { + if (v == 0) { done = true; } + next << std::move(self->last_dequeued()); } ) .until([&]() { return done == true; }); } -void worker_fun(actor_ptr msgcollector) -{ +void worker_fun(actor_ptr msgcollector) { bool done = false; - do_receive - ( - on() >> [&](uint64_t what) - { + do_receive ( + on() >> [&](uint64_t what) { send(msgcollector, atom("result"), factorize(what)); }, - on(atom("done")) >> [&]() - { + on(atom("done")) >> [&]() { done = true; } ) .until([&]() { return done == true; }); } -actor_ptr new_ring(actor_ptr next, int ring_size) -{ +actor_ptr new_ring(actor_ptr next, int ring_size) { for (int i = 1; i < ring_size; ++i) next = spawn(chain_link, next); return next; } -void chain_master(actor_ptr msgcollector) -{ +void chain_master(actor_ptr msgcollector) { auto worker = spawn(worker_fun, msgcollector); - receive - ( - on() >> [&](int rs, int itv, int n) - { + receive ( + on(atom("init"), arg_match) >> [&](int rs, int itv, int n) { int iteration = 0; auto next = new_ring(self, rs); send(next, atom("token"), itv); send(worker, atom("calc"), s_task_n); - do_receive - ( - on() >> [&](int v) - { - if (v == 0) - { - if (++iteration < n) - { + do_receive ( + on() >> [&](int v) { + if (v == 0) { + if (++iteration < n) { next = new_ring(self, rs); send(next, atom("token"), itv); send(worker, atom("calc"), s_task_n); } } - else - { + else { send(next, atom("token"), v - 1); } } @@ -316,16 +207,12 @@ void chain_master(actor_ptr msgcollector) send(worker, atom("done")); } -void supervisor(int num_msgs) -{ - do_receive - ( - on(atom("masterdone")) >> [&]() - { +void supervisor(int num_msgs) { + do_receive ( + on(atom("masterdone")) >> [&]() { --num_msgs; }, - on() >> [&](const factors& vec) - { + on() >> [&](const factors& vec) { --num_msgs; check_factors(vec); } @@ -334,16 +221,14 @@ void supervisor(int num_msgs) } template -void run_test(F&& spawn_impl, +void run_test(F spawn_impl, int num_rings, int ring_size, - int initial_token_value, int repetitions) -{ + int initial_token_value, int repetitions) { std::vector masters; // of the universe // each master sends one masterdone message and one // factorization is calculated per repetition //auto supermaster = spawn(supervisor, num_rings+repetitions); - for (int i = 0; i < num_rings; ++i) - { + for (int i = 0; i < num_rings; ++i) { masters.push_back(spawn_impl()); send(masters.back(), atom("init"), ring_size, @@ -353,9 +238,8 @@ void run_test(F&& spawn_impl, await_all_others_done(); } -void usage() -{ - cout << "usage: mailbox_performance [--boost_pool] " +void usage() { + cout << "usage: mailbox_performance " "(stacked|event-based) (num rings) (ring size) " "(initial token value) (repetitions)" << endl @@ -365,46 +249,42 @@ void usage() enum mode_type { event_based, fiber_based }; -int main(int argc, char** argv) -{ +option _2i(const std::string& str) { + char* endptr = nullptr; + int result = static_cast(strtol(str.c_str(), &endptr, 10)); + if (endptr == nullptr || *endptr != '\0') { + return {}; + } + return result; +} + +int main(int argc, char** argv) { announce(); if (argc != 6) usage(); - auto iter = argv; - ++iter; // argv[0] (app name) - /* - if (argc == 7) - { - if (strcmp(*iter++, "--boost_pool") == 0) - cppa::set_scheduler(new cppa::detail::boost_threadpool_scheduler); - else usage(); - } - */ - mode_type mode; - std::string mode_str = *iter++; - if (mode_str == "event-based") mode = event_based; - else if (mode_str == "stacked") mode = fiber_based; - else usage(); - int num_rings = rd(*iter++); - int ring_size = rd(*iter++); - int initial_token_value = rd(*iter++); - int repetitions = rd(*iter++); - int num_msgs = num_rings + (num_rings * repetitions); - switch (mode) - { - case event_based: - { - auto mc = spawn(new fsm_supervisor(num_msgs)); - run_test([&]() { return spawn(new fsm_chain_master(mc)); }, - num_rings, ring_size, initial_token_value, repetitions); - break; - } - case fiber_based: - { - auto mc = spawn(supervisor, num_msgs); - run_test([&]() { return spawn(chain_master, mc); }, - num_rings, ring_size, initial_token_value, repetitions); - break; - } - } + // skip argv[0] (app name) + std::vector args{argv + 1, argv + argc}; + match(args) ( + on(val, _2i, _2i, _2i, _2i) >> [](const std::string& mode, + int num_rings, + int ring_size, + int initial_token_value, + int repetitions) { + int num_msgs = num_rings + (num_rings * repetitions); + if (mode == "event-based") { + auto mc = spawn(num_msgs); + run_test([&]() { return spawn(mc); }, + num_rings, ring_size, initial_token_value, repetitions); + } + else if (mode == "stacked") { + auto mc = spawn(supervisor, num_msgs); + run_test([&]() { return spawn(chain_master, mc); }, + num_rings, ring_size, initial_token_value, repetitions); + } + else { + usage(); + } + }, + others() >> usage + ); return 0; } diff --git a/benchmarks/mixed_case_libprocess.cpp b/benchmarks/mixed_case_libprocess.cpp new file mode 100644 index 0000000000..f2ad2c5de0 --- /dev/null +++ b/benchmarks/mixed_case_libprocess.cpp @@ -0,0 +1,186 @@ +#include +#include + +#include "utility.hpp" + +typedef std::vector factors; +constexpr uint64_t s_task_n = uint64_t(86028157)*329545133; +constexpr uint64_t s_factor1 = 86028157; +constexpr uint64_t s_factor2 = 329545133; + +void check_factors(const factors& vec) +{ + assert(vec.size() == 2); + assert(vec[0] == s_factor1); + assert(vec[1] == s_factor2); +} + +class supervisor : public process::Process +{ +public: + supervisor(int num_msgs) + : left_(num_msgs) + { + } + + void subtract() + { + if (--left_ == 0) + process::terminate(self()); + } + + void check(const factors& vec) + { + check_factors(vec); + if (--left_ == 0) + process::terminate(self()); + } + +private: + int left_; +}; + +class chain_link : public process::Process +{ +public: + chain_link() + { + } + + chain_link(process::PID pid) + : next_(std::move(pid)) + { + } + + virtual ~chain_link() { } + + virtual void token(int v) + { + assert(next_); + process::dispatch(next_, &chain_link::token, v); + if (v == 0) + process::terminate(self()); + } + +private: + process::PID next_; +}; + +class worker : public process::Process +{ +public: + worker(process::PID collector) + : collector_(std::move(collector)) + { + } + + void calc(uint64_t what) + { + process::dispatch(collector_, &supervisor::check, factorize(what)); + } + + void done() + { + process::terminate(self()); + } + +private: + process::PID collector_; +}; + +class chain_master : public chain_link +{ +public: + chain_master(process::PID collector, int rs, int itv, int n) + : chain_link() + , ring_size_(rs) + , initial_value_(itv) + , repetitions_(n) + , iteration_(0) + , collector_(collector) + { + } + + void new_ring(int ring_size, int initial_token_value) + { + process::dispatch(worker_, &worker::calc, s_task_n); + next_ = self(); + for (int i = 1; i < ring_size; ++i) + next_ = process::spawn(new chain_link(next_), true); + + process::dispatch(next_, &chain_link::token, initial_token_value); + } + + void init() + { + worker_ = process::spawn(new worker(collector_), true); + new_ring(ring_size_, initial_value_); + } + + virtual void token(int t) + { + if (t == 0) + { + if (++iteration_ < repetitions_) + { + new_ring(ring_size_, initial_value_); + } + else + { + dispatch(worker_, &worker::done); + dispatch(collector_, &supervisor::subtract); + process::terminate(self()); + } + } + else + { + process::dispatch(next_, &chain_link::token, t - 1); + } + } + +private: + const int ring_size_; + const int initial_value_; + const int repetitions_; + int iteration_; + process::PID collector_; + process::PID next_; + process::PID worker_; +}; + +int main(int argc, char** argv) +{ + if (argc != 5) + { + std::cout << "usage " << argv[0] << ": " << + "(num rings) (ring size) (initial token value) (repetitions)" + << std::endl; + + return 1; + } + + auto iter = argv; + ++iter; // argv[0] (app name) + int num_rings = rd(*iter++); + int ring_size = rd(*iter++); + int initial_token_value = rd(*iter++); + int repetitions = rd(*iter++); + int num_msgs = num_rings + (num_rings * repetitions); + + auto mc = process::spawn(new supervisor(num_msgs), true); + std::vector> masters; + for (int i = 0; i < num_rings; ++i) + { + auto master = process::spawn( + new chain_master(mc, ring_size, initial_token_value, repetitions), + true); + + process::dispatch(master, &chain_master::init); + masters.push_back(master); + } + + for (auto& m : masters) + process::wait(m); + + return 0; +} diff --git a/benchmarks/mk_mixed_case_libprocess.sh b/benchmarks/mk_mixed_case_libprocess.sh new file mode 100755 index 0000000000..2147b32692 --- /dev/null +++ b/benchmarks/mk_mixed_case_libprocess.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +# quick & dirty: eval args to enable CXX=... and CXXFLAGS=... +for arg in "$@"; do + eval "$arg" +done + +if test "" = "$CXX"; then + CXX=g++ +fi + +function verbose_exec { + echo $1 + eval $1 + if test "0" != "$?" ; then + echo ; echo "command failed!" + exit + fi +} + +function check_var { + if test "" = "$1" ; then + echo "something went wrong ... $2 not found" + exit + fi +} + +function fetch_lib { + find mesos/third_party/libprocess -name "$1" + if test "$2" = "true" ; then + echo "something went wrong ... $1 not found" + fi +} + +if ! test -d mesos ; then + echo "fetch mesos (for libprocess)" + verbose_exec "git clone https://github.com/apache/mesos.git" +else + echo "found mesos repository" +fi + +LIBFILE=$(fetch_lib libprocess.a) +LIBGLOGFILE=$(fetch_lib libglog.a) +LIBEVFILE=$(fetch_lib libev.a) + +echo "LIBFILE=$LIBFILE" +echo "LIBGLOGFILE=$LIBGLOGFILE" +echo "LIBEVFILE=$LIBEVFILE" + +if test "" = "$LIBFILE" -o "" = "$LIBGLOGFILE" -o "" = "$LIBEVFILE" ; then + CURR=$PWD + echo "build libprocess" + cd mesos/third_party/libprocess/ + verbose_exec "autoreconf -Wnone -i && ./configure CXX=\"$CXX\" CXXFLAGS=\"$CXXFLAGS -D_XOPEN_SOURCE\" && make" + echo "build third_party libraries" + cd third_party + for dir in * ; do + if test -d $dir ; then + # skip boost in third_party directory + if [[ "$dir" == glog* ]] || [[ "$dir" == libev* ]] ; then + echo "cd $dir" + cd $dir + verbose_exec "autoreconf -i ; ./configure CXX=\"$CXX\" CXXFLAGS=\"$CXXFLAGS\" ; make" + echo "cd .." + cd .. + fi + fi + done + cd $CURR + LIBFILE=$(fetch_lib libprocess.a true) + LIBGLOGFILE=$(fetch_lib libglog.a true) + LIBEVFILE=$(fetch_lib libev.a true) +else + echo "found libprocess library: $LIBFILE" +fi +LIBDIRS="-L$(dirname "$LIBFILE") -L$(dirname "$LIBGLOGFILE") -L$(dirname "$LIBEVFILE")" + +verbose_exec "$CXX --std=c++0x $CXXFLAGS -Imesos/third_party/libprocess/include/ $LIBDIRS mixed_case_libprocess.cpp -o mixed_case_libprocess -lprocess -lglog -lev" + diff --git a/benchmarks/mk_scala.sh b/benchmarks/mk_scala.sh index 091938d0de..b5c6b42100 100755 --- a/benchmarks/mk_scala.sh +++ b/benchmarks/mk_scala.sh @@ -1,11 +1,11 @@ #!/bin/bash if [[ $# -eq 0 ]] ; then for i in *.scala; do - echo "scalac -cp ../../akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar \"$i\"" - scalac -cp ../../akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar "$i" + echo "compile \"$i\"" + scalac -unchecked -cp $AKKA_LIBS "$i" done elif [[ $# -eq 1 ]] ; then - echo "scalac -cp ../../akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar \"$1.scala\"" - scalac -cp ../../akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar "$1.scala" + echo "compile \"$1.scala\"" + scalac -unchecked -cp $AKKA_LIBS "$1.scala" fi echo done diff --git a/benchmarks/scala_test.sh b/benchmarks/scala_test.sh index a0adcd00d0..29d21357eb 100755 --- a/benchmarks/scala_test.sh +++ b/benchmarks/scala_test.sh @@ -1,4 +1,5 @@ #!/bin/bash #export JAVA_OPTS="-Xmx1024" #echo "scala -cp /home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar $@" | ./exec.sh -echo "scala -cp /home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar $@" | ./exec.sh +JARS=/home/neverlord/akka-microkernel-1.2/lib/akka/activation-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-tests-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-amqp-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-beanstalk-mailbox-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-camel-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-camel-typed-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-dispatcher-extras-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-file-mailbox-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-http-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-kernel-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-mailboxes-common-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-redis-mailbox-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-remote-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-scalaz-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-slf4j-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-spring-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-stm-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-testkit-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/akka-typed-actor-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/amqp-client-2.5.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/aopalliance-1.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/asm-3.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/aspectwerkz-2.2.3.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/beanstalk_client-1.4.5.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/camel-core-2.7.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-cli-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-codec-1.4.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-io-2.0.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-logging-1.1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-management-1.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/commons-pool-1.5.5.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/dispatch-json_2.9.0-0.8.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/guice-all-2.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/h2-lzf-1.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/hawtdispatch-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/hawtdispatch-scala-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jackson-core-asl-1.8.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jackson-mapper-asl-1.8.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jaxb-api-2.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jaxb-impl-2.1.12.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jersey-core-1.3.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jersey-json-1.3.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jersey-scala-1.3.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jersey-server-1.3.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jettison-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-continuation-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-http-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-io-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-security-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-server-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-servlet-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-util-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jetty-xml-7.4.0.v20110414.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jsr250-api-1.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jsr311-api-1.1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/jsr311-api-1.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/junit-4.8.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/log4j-1.2.16.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/multiverse-alpha-0.6.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/netty-3.2.5.Final.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/objenesis-1.2.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/protobuf-java-2.4.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/redisclient_2.9.0-2.3.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/scalaz-core_2.9.0-1-6.0.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/servlet-api-2.5.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/sjson_2.9.0-0.11.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/slf4j-api-1.5.8.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/slf4j-api-1.6.0.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/slf4j-log4j12-1.5.8.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-aop-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-asm-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-beans-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-context-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-core-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/spring-expression-3.0.5.RELEASE.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/stax-api-1.0.1.jar:/home/neverlord/akka-microkernel-1.2/lib/akka/stax-api-1.0-2.jar +echo "scala -cp $JARS $@" | ./exec.sh diff --git a/benchmarks/theron_actor_creation.cpp b/benchmarks/theron_actor_creation.cpp index 0bd29f4baa..825a737997 100644 --- a/benchmarks/theron_actor_creation.cpp +++ b/benchmarks/theron_actor_creation.cpp @@ -18,41 +18,33 @@ struct result { uint32_t value; }; using namespace Theron; -struct testee : Actor -{ +struct testee : Actor { Address m_parent; bool m_first_result_received; uint32_t m_first_result; std::vector m_children; - void spread_handler(const spread& arg, const Address) - { - if (arg.value == 0) - { + void spread_handler(const spread& arg, const Address) { + if (arg.value == 0) { Send(result{1}, m_parent); } - else - { + else { spread msg = {arg.value-1}; Parameters params = {GetAddress()}; - for (int i = 0; i < 2; ++i) - { + for (int i = 0; i < 2; ++i) { m_children.push_back(GetFramework().CreateActor(params)); m_children.back().Push(msg, GetAddress()); } } } - void result_handler(const result& arg, const Address) - { - if (!m_first_result_received) - { + void result_handler(const result& arg, const Address) { + if (!m_first_result_received) { m_first_result_received = true; m_first_result = arg.value; } - else - { + else { m_children.clear(); Send(result{m_first_result + arg.value}, m_parent); } @@ -60,25 +52,21 @@ struct testee : Actor typedef struct { Address arg0; } Parameters; - testee(const Parameters& p) : m_parent(p.arg0), m_first_result_received(false) - { + testee(const Parameters& p) : m_parent(p.arg0), m_first_result_received(false) { RegisterHandler(this, &testee::spread_handler); RegisterHandler(this, &testee::result_handler); } }; -void usage() -{ +void usage() { cout << "usage: theron_actor_creation _ POW" << endl << " creates 2^POW actors" << endl << endl; } -int main(int argc, char** argv) -{ - if (argc != 3) - { +int main(int argc, char** argv) { + if (argc != 3) { usage(); return 1; } diff --git a/benchmarks/theron_mailbox_performance.cpp b/benchmarks/theron_mailbox_performance.cpp index a876c7de9d..4665f88b99 100644 --- a/benchmarks/theron_mailbox_performance.cpp +++ b/benchmarks/theron_mailbox_performance.cpp @@ -18,47 +18,39 @@ using namespace Theron; int64_t t_max = 0; -struct receiver : Actor -{ +struct receiver : Actor { int64_t m_num; - void handler(const int64_t&, const Address from) - { + void handler(const int64_t&, const Address from) { if (++m_num == t_max) Send(t_max, from); } - receiver() : m_num(0) - { + receiver() : m_num(0) { RegisterHandler(this, &receiver::handler); } }; -void send_sender(Framework& f, ActorRef ref, Address waiter, int64_t num) -{ +void send_sender(Framework& f, ActorRef ref, Address waiter, int64_t num) { auto addr = ref.GetAddress(); int64_t msg; for (int64_t i = 0; i < num; ++i) f.Send(msg, waiter, addr); } -void push_sender(Framework& f, ActorRef ref, Address waiter, int64_t num) -{ +void push_sender(Framework& f, ActorRef ref, Address waiter, int64_t num) { int64_t msg; for (int64_t i = 0; i < num; ++i) ref.Push(msg, waiter); } -void usage() -{ +void usage() { cout << "usage ('push'|'send') (num_threads) (num_messages)" << endl; exit(1); } -int main(int argc, char** argv) -{ - if (argc != 4) - { +int main(int argc, char** argv) { + if (argc != 4) { usage(); } enum { invalid_impl, push_impl, send_impl } impl = invalid_impl; @@ -74,8 +66,7 @@ int main(int argc, char** argv) ActorRef aref(framework.CreateActor()); std::list threads; auto impl_fun = (impl == push_impl) ? send_sender : push_sender; - for (int64_t i = 0; i < num_sender; ++i) - { + for (int64_t i = 0; i < num_sender; ++i) { threads.push_back(std::thread(impl_fun, std::ref(framework), aref, receiverAddr, num_msgs)); } r.Wait(); diff --git a/benchmarks/theron_mixed_case.cpp b/benchmarks/theron_mixed_case.cpp index fcd23969e0..ab0dce9c91 100644 --- a/benchmarks/theron_mixed_case.cpp +++ b/benchmarks/theron_mixed_case.cpp @@ -30,40 +30,32 @@ struct master_done { }; struct worker_done { }; -struct worker : Actor -{ - void handle_calc(const calc_msg& msg, Address from) - { +struct worker : Actor { + void handle_calc(const calc_msg& msg, Address from) { factorize(msg.value); } - void handle_master_done(const master_done&, Address from) - { + void handle_master_done(const master_done&, Address from) { Send(worker_done(), from); } - worker() - { + worker() { RegisterHandler(this, &worker::handle_calc); RegisterHandler(this, &worker::handle_master_done); } }; -struct chain_link : Actor -{ +struct chain_link : Actor { Address next; - void handle_token(const token_msg& msg, Address) - { + void handle_token(const token_msg& msg, Address) { Send(msg, next); } typedef struct { Address next; } Parameters; - chain_link(const Parameters& p) : next(p.next) - { + chain_link(const Parameters& p) : next(p.next) { RegisterHandler(this, &chain_link::handle_token); } }; -struct master : Actor -{ +struct master : Actor { Address mc; int iteration; int max_iterations; @@ -72,20 +64,17 @@ struct master : Actor int ring_size; int initial_token_value; std::vector m_children; - void new_ring() - { + void new_ring() { m_children.clear(); w.Push(calc_msg{s_task_n}, GetAddress()); next = GetAddress(); - for (int i = 1; i < ring_size; ++i) - { + for (int i = 1; i < ring_size; ++i) { m_children.push_back(GetFramework().CreateActor(chain_link::Parameters{next})); next = m_children.back().GetAddress(); } Send(token_msg{initial_token_value}, next); } - void handle_init(const init_msg& msg, Address) - { + void handle_init(const init_msg& msg, Address) { w = GetFramework().CreateActor(); iteration = 0; ring_size = msg.ring_size; @@ -93,40 +82,32 @@ struct master : Actor max_iterations = msg.iterations; new_ring(); } - void handle_token(const token_msg& msg, Address) - { - if (msg.value == 0) - { - if (++iteration < max_iterations) - { + void handle_token(const token_msg& msg, Address) { + if (msg.value == 0) { + if (++iteration < max_iterations) { new_ring(); } - else - { + else { w.Push(master_done(), GetAddress()); } } - else - { + else { Send(token_msg{msg.value - 1}, next); } } - void handle_worker_done(const worker_done&, Address) - { + void handle_worker_done(const worker_done&, Address) { Send(master_done(), mc); w = ActorRef::Null(); } typedef struct { Address mc; } Parameters; - master(const Parameters& p) : mc(p.mc), iteration(0) - { + master(const Parameters& p) : mc(p.mc), iteration(0) { RegisterHandler(this, &master::handle_init); RegisterHandler(this, &master::handle_token); RegisterHandler(this, &master::handle_worker_done); } }; -void usage() -{ +void usage() { cout << "usage: mailbox_performance " "'send' (num rings) (ring size) " "(initial token value) (repetitions)" @@ -135,8 +116,7 @@ void usage() exit(1); } -int main(int argc, char** argv) -{ +int main(int argc, char** argv) { if (argc != 6) usage(); if (strcmp("send", argv[1]) != 0) usage(); int num_rings = rd(argv[2]); @@ -146,12 +126,10 @@ int main(int argc, char** argv) Receiver r; Framework framework(num_cores()); std::vector masters; - for (int i = 0; i < num_rings; ++i) - { + for (int i = 0; i < num_rings; ++i) { masters.push_back(framework.CreateActor(master::Parameters{r.GetAddress()})); } - for (ActorRef& m : masters) - { + for (ActorRef& m : masters) { m.Push(init_msg{ring_size, inital_token_value, repetitions}, r.GetAddress()); } for (int i = 0; i < num_rings; ++i) r.Wait(); diff --git a/benchmarks/utility.hpp b/benchmarks/utility.hpp index 44a5e09be2..f38e2b420b 100644 --- a/benchmarks/utility.hpp +++ b/benchmarks/utility.hpp @@ -32,18 +32,35 @@ #define UTILITY_HPP #include +#include +#include #include #include -#include "boost/thread.hpp" +inline std::vector split(const std::string& str, char delim) { + std::vector result; + std::stringstream strs{str}; + std::string tmp; + while (std::getline(strs, tmp, delim)) result.push_back(tmp); + return result; +} + +inline std::string join(const std::vector& vec, + const std::string& delim = "") { + if (vec.empty()) return ""; + auto result = vec.front(); + for (auto i = vec.begin() + 1; i != vec.end(); ++i) { + result += delim; + result += *i; + } + return result; +} template -T rd(char const* cstr) -{ +T rd(const char* cstr) { char* endptr = nullptr; T result = static_cast(strtol(cstr, &endptr, 10)); - if (endptr == nullptr || *endptr != '\0') - { + if (endptr == nullptr || *endptr != '\0') { std::string errstr; errstr += "\""; errstr += cstr; @@ -53,18 +70,10 @@ T rd(char const* cstr) return result; } -#ifdef __APPLE__ -int num_cores() -{ - return static_cast(boost::thread::hardware_concurrency()); -} -#else -int num_cores() -{ +int num_cores() { char cbuf[100]; FILE* cmd = popen("/bin/cat /proc/cpuinfo | /bin/grep processor | /usr/bin/wc -l", "r"); - if (fgets(cbuf, 100, cmd) == 0) - { + if (fgets(cbuf, 100, cmd) == 0) { throw std::runtime_error("cannot determine number of cores"); } pclose(cmd); @@ -73,26 +82,20 @@ int num_cores() *i = '\0'; return rd(cbuf); } -#endif -std::vector factorize(uint64_t n) -{ +std::vector factorize(uint64_t n) { std::vector result; - if (n <= 3) - { + if (n <= 3) { result.push_back(n); return std::move(result); } uint64_t d = 2; - while(d < n) - { - if((n % d) == 0) - { + while(d < n) { + if((n % d) == 0) { result.push_back(d); n /= d; } - else - { + else { d = (d == 2) ? 3 : (d + 2); } } diff --git a/blob/AUTHORS b/blob/AUTHORS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/blob/COPYING b/blob/COPYING deleted file mode 100644 index 94a9ed024d..0000000000 --- a/blob/COPYING +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/blob/ChangeLog b/blob/ChangeLog deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/blob/Makefile.am b/blob/Makefile.am deleted file mode 100644 index 1976de1270..0000000000 --- a/blob/Makefile.am +++ /dev/null @@ -1,84 +0,0 @@ -ACLOCAL_AMFLAGS = -I ../m4 - -bin_PROGRAMS = cppatest - -cppatest_SOURCES = \ - ../src/abstract_tuple.cpp \ - ../src/abstract_type_list.cpp \ - ../src/actor_behavior.cpp \ - ../src/actor_count.cpp \ - ../src/actor.cpp \ - ../src/actor_proxy_cache.cpp \ - ../src/actor_proxy.cpp \ - ../src/actor_registry.cpp \ - ../src/addressed_message.cpp \ - ../src/any_tuple.cpp \ - ../src/any_tuple_iterator.cpp \ - ../src/atom.cpp \ - ../src/attachable.cpp \ - ../src/binary_deserializer.cpp \ - ../src/binary_serializer.cpp \ - ../src/blocking_message_queue.cpp \ - ../src/channel.cpp \ - ../src/local_actor.cpp \ - ../src/converted_thread_context.cpp \ - ../src/cppa.cpp \ - ../src/delegate.cpp \ - ../src/demangle.cpp \ - ../src/deserializer.cpp \ - ../src/duration.cpp \ - ../src/empty_tuple.cpp \ - ../src/exception.cpp \ - ../src/fiber.cpp \ - ../src/group.cpp \ - ../src/group_manager.cpp \ - ../src/intermediate.cpp \ - ../src/invokable.cpp \ - ../src/invoke_rules.cpp \ - ../src/mailman.cpp \ - ../src/matcher_arguments.cpp \ - ../src/message_queue.cpp \ - ../src/mock_scheduler.cpp \ - ../src/native_socket.cpp \ - ../src/network_manager.cpp \ - ../src/object_array.cpp \ - ../src/object.cpp \ - ../src/post_office.cpp \ - ../src/post_office_msg.cpp \ - ../src/primitive_variant.cpp \ - ../src/process_information.cpp \ - ../src/ripemd_160.cpp \ - ../src/scheduled_actor.cpp \ - ../src/scheduler.cpp \ - ../src/serializer.cpp \ - ../src/shared_spinlock.cpp \ - ../src/singleton_manager.cpp \ - ../src/string_serialization.cpp \ - ../src/task_scheduler.cpp \ - ../src/thread_pool_scheduler.cpp \ - ../src/to_uniform_name.cpp \ - ../src/unicast_network.cpp \ - ../src/uniform_type_info.cpp \ - ../src/yielding_message_queue.cpp \ - ../src/yield_interface.cpp \ - ../unit_testing/hash_of.cpp \ - ../unit_testing/main.cpp \ - ../unit_testing/ping_pong.cpp \ - ../unit_testing/test__a_matches_b.cpp \ - ../unit_testing/test__atom.cpp \ - ../unit_testing/test__intrusive_ptr.cpp \ - ../unit_testing/test__local_group.cpp \ - ../unit_testing/test__primitive_variant.cpp \ - ../unit_testing/test__remote_actor.cpp \ - ../unit_testing/test__ripemd_160.cpp \ - ../unit_testing/test__serialization.cpp \ - ../unit_testing/test__spawn.cpp \ - ../unit_testing/test__tuple.cpp \ - ../unit_testing/test__type_list.cpp \ - ../unit_testing/test__uniform_type.cpp \ - ../unit_testing/test__yield_interface.cpp - -AM_CPPFLAGS = -I../ -cppatest_CXXFLAGS = --std=c++0x -pedantic -Wall -Wextra -#AM_LDFLAGS = $(BOOST_LDFLAGS) $(BOOST_THREAD_LIB) -cppatest_LDADD = $(BOOST_LDFLAGS) $(BOOST_THREAD_LIB) diff --git a/blob/NEWS b/blob/NEWS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/blob/README b/blob/README deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/blob/c_context_impl.c b/blob/c_context_impl.c deleted file mode 100644 index ca73befb7b..0000000000 --- a/blob/c_context_impl.c +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _XOPEN_SOURCE -#define _XOPEN_SOURCE -#endif - -#include - -#include -#include -#include -#include - -static ucontext_t ctx[2]; - -__thread int m_count = 0; - -void coroutine() -{ - for (;;) - { - ++m_count; - printf("m_count = %i\n", m_count); - swapcontext(&ctx[1], &ctx[0]); - } -} - -int main(int argc, char** argv) -{ - int i; - void* coroutine_stack = mmap(0, - SIGSTKSZ, - PROT_EXEC | PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, - -1, - 0); - - memset(&ctx[0], 0, sizeof(ucontext_t)); - getcontext(&ctx[0]); - - memset(&ctx[1], 0, sizeof(ucontext_t)); - getcontext(&ctx[1]); - ctx[1].uc_stack.ss_sp = coroutine_stack; - ctx[1].uc_stack.ss_size = SIGSTKSZ; - ctx[1].uc_link = &ctx[0]; - makecontext(&ctx[1], coroutine, 0); - - for (i = 1; i < 11; ++i) - { - printf("i = %i\n", i); - swapcontext(&ctx[0], &ctx[1]); - } - - munmap(coroutine_stack, SIGSTKSZ); - - return 0; -} - diff --git a/blob/configure.ac b/blob/configure.ac deleted file mode 100644 index 9dd7c4e74d..0000000000 --- a/blob/configure.ac +++ /dev/null @@ -1,13 +0,0 @@ -AC_PREREQ([2.6]) -AC_INIT([cppatest], [0.1]) -AM_INIT_AUTOMAKE(@PACKAGE_NAME@, @PACKAGE_VERSION@) -AC_CONFIG_MACRO_DIR([../m4]) - -AC_PROG_CXX - -# check for boost and boost_thread -AX_BOOST_BASE([1.42.0]) -AX_BOOST_THREAD - -AC_CONFIG_FILES([Makefile]) -AC_OUTPUT diff --git a/blob/context_impl_test.cpp b/blob/context_impl_test.cpp deleted file mode 100644 index 741f16d776..0000000000 --- a/blob/context_impl_test.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include "cppa_fibre.h" - -using std::cout; -using std::endl; - -struct pseudo_worker -{ - int m_value; - - pseudo_worker() : m_value(0) { } - - void operator()() - { - for (;;) - { - ++m_value; - cout << "value = " << m_value << endl; - cppa_fibre_yield(0); - } - } -}; - -void coroutine() -{ - auto pw = reinterpret_cast(cppa_fibre_init_switch_arg()); - (*pw)(); -} - -int main() -{ - pseudo_worker pw; - cppa_fibre fself; - cppa_fibre fcoroutine; - cppa_fibre_ctor(&fself); - cppa_fibre_ctor2(&fcoroutine, coroutine, &pw); - cppa_fibre_initialize(&fcoroutine); - for (int i = 1; i < 11; ++i) - { - cout << "i = " << i << endl; - cppa_fibre_switch(&fself, &fcoroutine); - } - cppa_fibre_dtor(&fself); - cppa_fibre_dtor(&fcoroutine); - return 0; -} diff --git a/blob/cppa_fibre.c b/blob/cppa_fibre.c deleted file mode 100644 index ad1e6801f5..0000000000 --- a/blob/cppa_fibre.c +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef _XOPEN_SOURCE -#define _XOPEN_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "cppa_fibre.h" - -__thread void* s_switch_arg; -__thread int s_yield_value; -__thread ucontext_t* s_caller; -__thread ucontext_t* s_callee; - -void cppa_fibre_ctor(cppa_fibre* instance) -{ - instance->m_state = 0; - memset(&(instance->m_context), 0, sizeof(ucontext_t)); - getcontext(&(instance->m_context)); - instance->m_fun = 0; - instance->m_init_arg = 0; -} - -void cppa_fibre_ctor2(cppa_fibre* instance, void (*fun)(), void* arg) -{ - cppa_fibre_ctor(instance); - instance->m_state = 1; - instance->m_fun = fun; - instance->m_init_arg = arg; -} - -void cppa_fibre_initialize(cppa_fibre* instance) -{ - if (instance->m_state == 1) - { - instance->m_state = 2; - instance->m_context.uc_stack.ss_sp = mmap(0, - SIGSTKSZ, - PROT_EXEC | PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, - -1, - 0); - instance->m_context.uc_stack.ss_size = SIGSTKSZ; - makecontext(&(instance->m_context), instance->m_fun, 0); - s_switch_arg = instance->m_init_arg; - } -} - -void cppa_fibre_dtor(cppa_fibre* instance) -{ - if (instance->m_state == 2) - { - munmap(instance->m_context.uc_stack.ss_sp, SIGSTKSZ); - } -} - -void* cppa_fibre_init_switch_arg() -{ - return s_switch_arg; -} - -void cppa_fibre_switch(cppa_fibre* from, cppa_fibre* to) -{ - ucontext_t* ctx_from = &(from->m_context); - ucontext_t* ctx_to = &(to->m_context); - s_caller = ctx_from; - s_callee = ctx_to; - swapcontext(ctx_from, ctx_to); -} - -void cppa_fibre_yield(int value) -{ - s_yield_value = value; - swapcontext(s_callee, s_caller); -} - -int cppa_fibre_yielded_value() -{ - return s_yield_value; -} diff --git a/blob/cppa_fibre.h b/blob/cppa_fibre.h deleted file mode 100644 index 9bffe493cc..0000000000 --- a/blob/cppa_fibre.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef CPPA_FIBRE_H -#define CPPA_FIBRE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _XOPEN_SOURCE -#define _XOPEN_SOURCE -#endif - -#include -#include - -struct cppa_fibre_struct -{ - // 0: *this* context - // 1: fibre with function to execute, no stack assigned yet - // 2: as 1 but with assigned stack - int m_state; - ucontext_t m_context; - void (*m_fun)(); - void* m_init_arg; -}; - -typedef struct cppa_fibre_struct cppa_fibre; - -void cppa_fibre_ctor(cppa_fibre* instance); - -/* - * @brief Initializes the given fibre. - * @param instance Pointer to an uninitialized object. - * @param fun Function this fibre should execute. - * @param switch_arg This pointer is stored in a - * thread-local variable on first - * context switch to @p instance. - */ -void cppa_fibre_ctor2(cppa_fibre* instance, - void (*fun)(), - void* switch_arg); - -/* - * @warning call directly before the first switch - */ -void cppa_fibre_initialize(cppa_fibre* instance); - -void cppa_fibre_dtor(cppa_fibre* instance); - -/* - * @brief Returns - */ -void* cppa_fibre_init_switch_arg(); - -void cppa_fibre_switch(cppa_fibre* from, cppa_fibre* to); - -/* - * Switches back to the calling fibre. - */ -void cppa_fibre_yield(int value); - -/* - * Gets the yielded value of the client fibre. - */ -int cppa_fibre_yielded_value(); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in new file mode 100644 index 0000000000..10ff29ed2b --- /dev/null +++ b/cmake_uninstall.cmake.in @@ -0,0 +1,24 @@ +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: +\"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +list(REVERSE files) +foreach (file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + if(NOT ${rm_retval} EQUAL 0) + message(FATAL_ERROR "Problem when removing +\"$ENV{DESTDIR}${file}\"") + endif (NOT ${rm_retval} EQUAL 0) + else (EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif (EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) diff --git a/configure.ac b/configure.ac deleted file mode 100644 index a106f6ac10..0000000000 --- a/configure.ac +++ /dev/null @@ -1,46 +0,0 @@ -AC_PREREQ([2.6]) -AC_INIT([libcppa], [0.1]) -AM_INIT_AUTOMAKE(@PACKAGE_NAME@, @PACKAGE_VERSION@) -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_SRCDIR([src]) - -AC_PROG_CXX - -# check for boost and boost_thread -AX_BOOST_BASE([1.42.0]) -AX_BOOST_THREAD - -AC_PROG_LIBTOOL - -# check for C++0x compatibility -AC_LANG([C++]) -ORIGINAL_CPPFLAGS="$CPPFLAGS" -CPPFLAGS="$CPPFLAGS -Werror -std=c++0x" - -AC_CACHE_CHECK( - [whether C++ compiler supports variadic templates], - [ac_cv_cpp_variadic_templates], - AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include "variadic_templates_test.cpp"]])], - [ac_cv_cpp_variadic_templates=yes], - [ac_cv_cpp_variadic_templates=no])) - -#AC_CACHE_CHECK( -# [whether C++ compiler supports nullptr], -# [ac_cv_cpp_nullptr], -# AC_COMPILE_IFELSE([AC_LANG_SOURCE([[static void* myptr = nullptr;]])], -# [ac_cv_cpp_nullptr=yes], -# [ac_cv_cpp_nullptr=no])) - -AS_IF( - [test "x$ac_cv_cpp_variadic_templates" = "xyes" ], - [], - [AC_MSG_ERROR([at least one required C++ compiler feature is not supported])]) - -CPPFLAGS="$ORIGINAL_CPPFLAGS" - -# environment -AC_ARG_VAR([NO_VERSIONED_INCLUDE_DIR], [set this to 1 in order to install headers into /cppa/ rather than into /cppa//cppa/]) -AM_CONDITIONAL([VERSIONED_INCLUDE_DIR], [test "x$NO_VERSIONED_INCLUDE_DIR" != "x1"]) - -AC_CONFIG_FILES([Makefile unit_testing/Makefile examples/Makefile benchmarks/Makefile libcppa.pc]) -AC_OUTPUT diff --git a/cppa.files b/cppa.files index 5a794f2ef6..1b95e7359d 100644 --- a/cppa.files +++ b/cppa.files @@ -1,267 +1,265 @@ -cppa/ref_counted.hpp -cppa/cow_tuple.hpp -unit_testing/main.cpp -cppa/util/void_type.hpp -cppa/util/type_list.hpp -cppa/util/conjunction.hpp -cppa/util/disjunction.hpp -unit_testing/test.hpp -cppa/uniform_type_info.hpp -src/uniform_type_info.cpp +benchmarks/ActorCreation.scala +benchmarks/Distributed.scala +benchmarks/MailboxPerformance.scala +benchmarks/Matching.scala +benchmarks/MixedCase.scala +benchmarks/actor_creation.cpp +benchmarks/actor_creation.erl +benchmarks/distributed.cpp +benchmarks/distributed.erl +benchmarks/mailbox_performance.cpp +benchmarks/mailbox_performance.erl +benchmarks/matching.cpp +benchmarks/matching.erl +benchmarks/mixed_case.cpp +benchmarks/mixed_case.erl +benchmarks/theron_actor_creation.cpp +benchmarks/theron_mailbox_performance.cpp +benchmarks/theron_mixed_case.cpp +benchmarks/utility.hpp +cppa/detail/abstract_actor.hpp +cppa/event_based_actor.hpp +cppa/actor.hpp +cppa/actor_proxy.hpp +cppa/announce.hpp +cppa/any_tuple.hpp +cppa/anything.hpp +cppa/atom.hpp +cppa/attachable.hpp +cppa/behavior.hpp +cppa/binary_deserializer.hpp +cppa/binary_serializer.hpp +cppa/channel.hpp cppa/config.hpp -unit_testing/test__tuple.cpp -cppa/detail/abstract_tuple.hpp -cppa/detail/tuple_vals.hpp -cppa/detail/decorated_tuple.hpp cppa/cow_ptr.hpp -cppa/detail/ref_counted_impl.hpp -cppa/intrusive_ptr.hpp -unit_testing/test__spawn.cpp -src/mock_scheduler.cpp -cppa/actor.hpp -unit_testing/test__intrusive_ptr.cpp -cppa/util/callable_trait.hpp -unit_testing/test__type_list.cpp -cppa/util/compare_tuples.hpp -cppa/get.hpp -cppa/detail/tdata.hpp -cppa/detail/invokable.hpp -cppa/on.hpp -unit_testing/test__serialization.cpp -cppa/serializer.hpp +cppa/cow_tuple.hpp +cppa/cppa.hpp cppa/deserializer.hpp -cppa/object.hpp +cppa/detail/abstract_scheduled_actor.hpp +cppa/detail/abstract_tuple.hpp +cppa/detail/actor_count.hpp +cppa/detail/actor_proxy_cache.hpp +cppa/detail/actor_registry.hpp +cppa/detail/addressed_message.hpp +cppa/detail/atom_val.hpp +cppa/detail/boxed.hpp +cppa/detail/buffer.hpp +cppa/detail/channel.hpp +cppa/detail/container_tuple_view.hpp +cppa/thread_mapped_actor.hpp +cppa/detail/decorated_tuple.hpp +cppa/detail/default_uniform_type_info_impl.hpp +cppa/detail/demangle.hpp +cppa/detail/disablable_delete.hpp +cppa/detail/empty_tuple.hpp +cppa/detail/filter_result.hpp +cppa/detail/get_behavior.hpp +cppa/detail/group_manager.hpp +cppa/detail/implicit_conversions.hpp +cppa/detail/list_member.hpp +cppa/detail/mailman.hpp +cppa/detail/map_member.hpp +cppa/detail/matches.hpp +cppa/detail/native_socket.hpp +cppa/detail/network_manager.hpp +cppa/detail/object_array.hpp cppa/detail/object_impl.hpp -cppa/detail/swap_bytes.hpp -src/serializer.cpp -src/deserializer.cpp -cppa/util/is_legal_tuple_type.hpp -cppa/util/replace_type.hpp +cppa/detail/pair_member.hpp +cppa/detail/post_office.hpp +cppa/detail/primitive_member.hpp +cppa/detail/projection.hpp +cppa/detail/pseudo_tuple.hpp +cppa/detail/ptype_to_type.hpp +cppa/detail/receive_loop_helper.hpp +cppa/detail/recursive_queue_node.hpp +cppa/detail/ref_counted_impl.hpp +cppa/detail/scheduled_actor_dummy.hpp cppa/detail/serialize_tuple.hpp -unit_testing/test__atom.cpp +cppa/detail/singleton_manager.hpp +cppa/detail/swap_bytes.hpp +cppa/detail/tdata.hpp +cppa/detail/thread_pool_scheduler.hpp +cppa/detail/to_uniform_name.hpp +cppa/detail/tuple_cast_impl.hpp +cppa/detail/tuple_iterator.hpp +cppa/detail/tuple_vals.hpp +cppa/detail/tuple_view.hpp +cppa/detail/type_to_ptype.hpp +cppa/detail/types_array.hpp +cppa/detail/unboxed.hpp +cppa/detail/uniform_type_info_map.hpp +cppa/detail/value_guard.hpp +cppa/detail/yield_interface.hpp +cppa/context_switching_actor.hpp +cppa/either.hpp +cppa/exception.hpp +cppa/exit_reason.hpp +cppa/from_string.hpp +cppa/sb_actor.hpp +cppa/get.hpp +cppa/group.hpp +cppa/guard_expr.hpp +cppa/intrusive/forward_iterator.hpp cppa/intrusive/single_reader_queue.hpp -unit_testing/test__local_group.cpp -cppa/detail/channel.hpp +cppa/intrusive/singly_linked_list.hpp +cppa/intrusive_ptr.hpp cppa/local_actor.hpp -cppa/channel.hpp -src/channel.cpp +cppa/match.hpp +cppa/match_expr.hpp +cppa/object.hpp +cppa/on.hpp +cppa/option.hpp +cppa/partial_function.hpp +cppa/pattern.hpp +cppa/primitive_type.hpp +cppa/primitive_variant.hpp +cppa/process_information.hpp +cppa/receive.hpp +cppa/ref_counted.hpp cppa/scheduled_actor.hpp -cppa/cppa.hpp -cppa/scheduling_hint.hpp -src/scheduled_actor.cpp -cppa/group.hpp -src/group.cpp -queue_performances/main.cpp -queue_performances/sutter_list.hpp -queue_performances/defines.hpp -queue_performances/cached_stack.hpp -queue_performances/blocking_cached_stack.hpp -queue_performances/blocking_cached_stack2.hpp -queue_performances/blocking_sutter_list.hpp -queue_performances/lockfree_list.hpp -queue_performances/intrusive_sutter_list.hpp -src/local_actor.cpp cppa/scheduler.hpp -cppa/detail/mock_scheduler.hpp -src/scheduler.cpp -cppa/detail/converted_thread_context.hpp -src/converted_thread_context.cpp -unit_testing/test__uniform_type.cpp -cppa/detail/demangle.hpp -src/demangle.cpp -cppa/detail/to_uniform_name.hpp -src/to_uniform_name.cpp -cppa/detail/default_uniform_type_info_impl.hpp -src/object.cpp -cppa/util/comparable.hpp -cppa/primitive_variant.hpp -cppa/primitive_type.hpp -cppa/util/pt_token.hpp -cppa/detail/type_to_ptype.hpp -cppa/detail/ptype_to_type.hpp -cppa/util/is_primitive.hpp -cppa/util/is_iterable.hpp -src/primitive_variant.cpp -unit_testing/test__primitive_variant.cpp -cppa/detail/primitive_member.hpp -cppa/detail/list_member.hpp -cppa/detail/pair_member.hpp -cppa/detail/map_member.hpp -cppa/util/is_forward_iterator.hpp -cppa/util/rm_ref.hpp -cppa/binary_serializer.hpp -src/binary_serializer.cpp -cppa/binary_deserializer.hpp -src/binary_deserializer.cpp -src/actor.cpp -cppa/announce.hpp -cppa/util/shared_spinlock.hpp -src/shared_spinlock.cpp -cppa/util/shared_lock_guard.hpp -cppa/detail/object_array.hpp -src/object_array.cpp -cppa/any_tuple.hpp -src/any_tuple.cpp -cppa/util/abstract_uniform_type_info.hpp -cppa/util/upgrade_lock_guard.hpp +cppa/scheduling_hint.hpp +cppa/self.hpp +cppa/serializer.hpp cppa/to_string.hpp -src/string_serialization.cpp -cppa/from_string.hpp +cppa/tpartial_function.hpp +cppa/tuple_cast.hpp +cppa/uniform_type_info.hpp +cppa/util/abstract_uniform_type_info.hpp +cppa/util/apply_args.hpp +cppa/util/apply_tuple.hpp +cppa/util/arg_match_t.hpp cppa/util/at.hpp +cppa/util/callable_trait.hpp +cppa/util/comparable.hpp +cppa/util/compare_tuples.hpp +cppa/util/conjunction.hpp +cppa/util/deduce_ref_type.hpp +cppa/util/disjunction.hpp +cppa/util/duration.hpp cppa/util/element_at.hpp +cppa/util/fiber.hpp +cppa/util/fixed_vector.hpp cppa/util/if_else.hpp +cppa/util/is_array_of.hpp +cppa/util/is_builtin.hpp +cppa/util/is_comparable.hpp +cppa/util/is_forward_iterator.hpp +cppa/util/is_iterable.hpp +cppa/util/is_legal_tuple_type.hpp +cppa/util/is_manipulator.hpp +cppa/util/is_mutable_ref.hpp +cppa/util/is_primitive.hpp +cppa/util/left_or_right.hpp +cppa/util/producer_consumer_list.hpp cppa/util/pt_dispatch.hpp -cppa/detail/get_behavior.hpp -unit_testing/test__ripemd_160.cpp -cppa/process_information.hpp -src/process_information.cpp +cppa/util/pt_token.hpp +cppa/util/purge_refs.hpp +cppa/util/replace_type.hpp cppa/util/ripemd_160.hpp -src/ripemd_160.cpp -src/unicast_network.cpp -unit_testing/test__remote_actor.cpp -unit_testing/ping_pong.hpp -unit_testing/ping_pong.cpp -cppa/exception.hpp -src/exception.cpp -cppa/actor_proxy.hpp -src/actor_proxy.cpp -cppa/detail/actor_proxy_cache.hpp -src/actor_proxy_cache.cpp -src/attachable.cpp -cppa/attachable.hpp -cppa/atom.hpp -cppa/detail/atom_val.hpp -src/atom.cpp -src/cppa.cpp -cppa/exit_reason.hpp -cppa/abstract_actor.hpp -cppa/detail/mailman.hpp -src/mailman.cpp -cppa/detail/native_socket.hpp -src/native_socket.cpp -cppa/detail/post_office.hpp -src/post_office.cpp -cppa/detail/buffer.hpp -cppa/detail/actor_count.hpp -src/actor_count.cpp -cppa/util/fiber.hpp -src/fiber.cpp -cppa/detail/yield_interface.hpp -src/yield_interface.cpp -cppa/detail/abstract_scheduled_actor.hpp -src/abstract_scheduled_actor.cpp -src/invokable.cpp -cppa/detail/thread_pool_scheduler.hpp -src/thread_pool_scheduler.cpp -cppa/detail/receive_loop_helper.hpp +cppa/util/rm_option.hpp +cppa/util/rm_ref.hpp +cppa/util/shared_lock_guard.hpp +cppa/util/shared_spinlock.hpp +cppa/util/static_foreach.hpp +cppa/util/tbind.hpp +cppa/util/type_list.hpp +cppa/util/type_pair.hpp +cppa/util/upgrade_lock_guard.hpp +cppa/util/void_type.hpp cppa/util/wrapped.hpp -cppa/detail/boxed.hpp -cppa/detail/unboxed.hpp -src/abstract_tuple.cpp -cppa/util/duration.hpp -src/duration.cpp -cppa/receive.hpp -cppa/detail/thread.hpp -cppa/detail/singleton_manager.hpp -src/singleton_manager.cpp -cppa/detail/actor_registry.hpp -src/actor_registry.cpp -cppa/detail/uniform_type_info_map.hpp -cppa/detail/network_manager.hpp -src/network_manager.cpp -cppa/detail/post_office_msg.hpp -src/post_office_msg.cpp -cppa/detail/group_manager.hpp -src/group_manager.cpp -cppa/detail/empty_tuple.hpp -src/empty_tuple.cpp -cppa/detail/addressed_message.hpp -src/addressed_message.cpp -unit_testing/test__yield_interface.cpp -cppa/anything.hpp -cppa/pattern.hpp -unit_testing/test__pattern.cpp -cppa/util/fixed_vector.hpp -cppa/detail/implicit_conversions.hpp -cppa/util/is_array_of.hpp examples/announce_example_1.cpp examples/announce_example_2.cpp examples/announce_example_3.cpp examples/announce_example_4.cpp examples/announce_example_5.cpp +examples/dancing_kirby.cpp +examples/dining_philosophers.cpp examples/hello_world_example.cpp examples/math_actor_example.cpp -cppa/detail/yielding_actor.hpp -src/yielding_actor.cpp -cppa/either.hpp -cppa/abstract_event_based_actor.hpp -src/abstract_event_based_actor.cpp -cppa/event_based_actor.hpp +queue_performances/blocking_cached_stack.hpp +queue_performances/blocking_cached_stack2.hpp +queue_performances/blocking_sutter_list.hpp +queue_performances/cached_stack.hpp +queue_performances/defines.hpp +queue_performances/intrusive_sutter_list.hpp +queue_performances/lockfree_list.hpp +queue_performances/main.cpp +queue_performances/sutter_list.hpp src/event_based_actor.cpp -cppa/stacked_event_based_actor.hpp -src/stacked_event_based_actor.cpp -cppa/event_based_actor_base.hpp -cppa/fsm_actor.hpp -cppa/self.hpp -src/self.cpp -cppa/behavior.hpp +src/abstract_tuple.cpp +src/actor.cpp +src/actor_count.cpp +src/actor_proxy.cpp +src/actor_proxy_cache.cpp +src/actor_registry.cpp +src/addressed_message.cpp +src/any_tuple.cpp +src/atom.cpp +src/attachable.cpp +src/binary_deserializer.cpp +src/binary_serializer.cpp +src/channel.cpp +src/thread_mapped_actor.cpp +src/demangle.cpp +src/deserializer.cpp +src/duration.cpp +src/empty_tuple.cpp +src/exception.cpp +src/fiber.cpp +src/group.cpp +src/group_manager.cpp +src/local_actor.cpp +src/mailman.cpp +src/native_socket.cpp +src/network_manager.cpp +src/object.cpp +src/object_array.cpp +src/partial_function.cpp +src/pattern.cpp +src/post_office.cpp +src/primitive_variant.cpp +src/process_information.cpp src/receive.cpp -benchmarks/actor_creation.cpp -benchmarks/mailbox_performance.cpp -benchmarks/mixed_case.cpp -benchmarks/actor_creation.erl -benchmarks/mailbox_performance.erl -benchmarks/mixed_case.erl -benchmarks/ActorCreation.scala -benchmarks/MailboxPerformance.scala -benchmarks/MixedCase.scala -cppa/util/producer_consumer_list.hpp -cppa/util/arg_match_t.hpp -cppa/detail/types_array.hpp -cppa/util/is_builtin.hpp -cppa/util/type_pair.hpp -cppa/util/tbind.hpp -cppa/option.hpp -cppa/tuple_cast.hpp -cppa/util/is_mutable_ref.hpp -cppa/util/is_manipulator.hpp -cppa/util/apply_tuple.hpp -benchmarks/Matching.scala -benchmarks/matching.cpp -benchmarks/matching.erl -benchmarks/theron_mailbox_performance.cpp -benchmarks/utility.hpp -benchmarks/theron_actor_creation.cpp -benchmarks/theron_mixed_case.cpp -cppa/util/static_foreach.hpp -cppa/type_value_pair.hpp -examples/dining_philosophers.cpp -cppa/detail/disablable_delete.hpp +src/ripemd_160.cpp +src/scheduled_actor.cpp +src/scheduled_actor_dummy.cpp +src/scheduler.cpp +src/self.cpp +src/serializer.cpp +src/shared_spinlock.cpp +src/singleton_manager.cpp +src/string_serialization.cpp +src/thread_pool_scheduler.cpp +src/to_uniform_name.cpp +src/unicast_network.cpp +src/uniform_type_info.cpp +src/yield_interface.cpp +src/context_switching_actor.cpp +unit_testing/main.cpp +unit_testing/ping_pong.cpp +unit_testing/ping_pong.hpp +unit_testing/test.hpp +unit_testing/test__atom.cpp unit_testing/test__fixed_vector.cpp -cppa/detail/tuple_cast_impl.hpp -cppa/match.hpp -cppa/partial_function.hpp -src/partial_function.cpp -cppa/intrusive/singly_linked_list.hpp -cppa/intrusive/forward_iterator.hpp unit_testing/test__intrusive_containers.cpp -examples/dancing_kirby.cpp -cppa/util/is_comparable.hpp -cppa/detail/tuple_view.hpp -cppa/detail/container_tuple_view.hpp -cppa/detail/matches.hpp +unit_testing/test__intrusive_ptr.cpp +unit_testing/test__local_group.cpp unit_testing/test__match.cpp -cppa/guard_expr.hpp -src/pattern.cpp -cppa/util/left_or_right.hpp -cppa/util/apply_args.hpp -cppa/tpartial_function.hpp -cppa/util/rm_option.hpp -cppa/util/projection.hpp -cppa/util/purge_refs.hpp -cppa/util/deduce_ref_type.hpp -cppa/detail/projection.hpp -cppa/detail/value_guard.hpp -cppa/detail/tuple_iterator.hpp -cppa/match_expr.hpp -cppa/detail/pseudo_tuple.hpp +unit_testing/test__pattern.cpp +unit_testing/test__primitive_variant.cpp +unit_testing/test__remote_actor.cpp +unit_testing/test__ripemd_160.cpp +unit_testing/test__serialization.cpp +unit_testing/test__spawn.cpp +unit_testing/test__tuple.cpp +unit_testing/test__type_list.cpp +unit_testing/test__uniform_type.cpp +unit_testing/test__yield_interface.cpp +cppa/detail/receive_policy.hpp +cppa/detail/behavior_stack.hpp +src/behavior_stack.cpp +cppa/detail/stacked_actor_mixin.hpp +cppa/detail/event_based_actor_factory.hpp +cppa/factory.hpp +src/factory.cpp diff --git a/cppa.includes b/cppa.includes index 3f7cd052d7..6e6b737a91 100644 --- a/cppa.includes +++ b/cppa.includes @@ -1,6 +1,5 @@ -/Users/neverlord/libcppa -/home/neverlord/libcppa +. +./unit_testing +./third_party/boost_context/include/ /opt/local/include/gcc46/c++ /opt/local/include/ -/Users/neverlord/libcppa/unit_testing -/home/neverlord/libcppa/unit_testing diff --git a/cppa/abstract_event_based_actor.hpp b/cppa/abstract_event_based_actor.hpp deleted file mode 100644 index b6cdc8e652..0000000000 --- a/cppa/abstract_event_based_actor.hpp +++ /dev/null @@ -1,145 +0,0 @@ -/******************************************************************************\ - * ___ __ * - * /\_ \ __/\ \ * - * \//\ \ /\_\ \ \____ ___ _____ _____ __ * - * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * - * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * - * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * - * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * - * \ \_\ \ \_\ * - * \/_/ \/_/ * - * * - * Copyright (C) 2011, 2012 * - * Dominik Charousset * - * * - * This file is part of libcppa. * - * libcppa is free software: you can redistribute it and/or modify it under * - * the terms of the GNU Lesser General Public License as published by the * - * Free Software Foundation, either version 3 of the License * - * or (at your option) any later version. * - * * - * libcppa is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with libcppa. If not, see . * -\******************************************************************************/ - - -#ifndef EVENT_DRIVEN_ACTOR_HPP -#define EVENT_DRIVEN_ACTOR_HPP - -#include -#include -#include - -#include "cppa/config.hpp" -#include "cppa/either.hpp" -#include "cppa/pattern.hpp" -#include "cppa/behavior.hpp" -#include "cppa/detail/disablable_delete.hpp" -#include "cppa/detail/abstract_scheduled_actor.hpp" - -namespace cppa { - -/** - * @brief Base class for all event-based actor implementations. - */ -class abstract_event_based_actor : public detail::abstract_scheduled_actor -{ - - typedef detail::abstract_scheduled_actor super; - typedef super::queue_node queue_node; - - public: - - void dequeue(behavior&); //override - - void dequeue(partial_function&); //override - - void resume(util::fiber*, resume_callback* callback); //override - - /** - * @brief Initializes the actor by defining an initial behavior. - */ - virtual void init() = 0; - - /** - * @copydoc cppa::scheduled_actor::on_exit() - */ - virtual void on_exit(); - - inline abstract_event_based_actor* attach_to_scheduler(scheduler* sched) - { - CPPA_REQUIRE(sched != nullptr); - m_scheduler = sched; - init(); - return this; - } - - protected: - - abstract_event_based_actor(); - - // ownership flag + pointer - typedef std::unique_ptr> - stack_element; - - std::vector m_loop_stack; - - // current position in mailbox - mailbox_cache_type::iterator m_mailbox_pos; - - // provoke compiler errors for usage of receive() and related functions - - /** - * @brief Provokes a compiler error to ensure that an event-based actor - * does not accidently uses receive() instead of become(). - */ - template - void receive(Args&&...) - { - static_assert((sizeof...(Args) + 1) < 1, - "You shall not use receive in an event-based actor. " - "Use become() instead."); - } - - /** - * @brief Provokes a compiler error. - */ - template - void receive_loop(Args&&... args) - { - receive(std::forward(args)...); - } - - /** - * @brief Provokes a compiler error. - */ - template - void receive_while(Args&&... args) - { - receive(std::forward(args)...); - } - - /** - * @brief Provokes a compiler error. - */ - template - void do_receive(Args&&... args) - { - receive(std::forward(args)...); - } - - private: - - bool handle_message(queue_node& iter); - bool invoke_from_cache(); - -}; - -} // namespace cppa - -#endif // EVENT_DRIVEN_ACTOR_HPP diff --git a/cppa/actor.hpp b/cppa/actor.hpp index 26730737d4..9cd6ae8f4e 100644 --- a/cppa/actor.hpp +++ b/cppa/actor.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef ACTOR_HPP -#define ACTOR_HPP +#ifndef CPPA_ACTOR_HPP +#define CPPA_ACTOR_HPP #include #include @@ -47,17 +47,27 @@ namespace cppa { class serializer; class deserializer; +class actor; + +/** + * @brief A unique actor ID. + * @relates actor + */ typedef std::uint32_t actor_id; /** * @brief Base class for all actor implementations. */ -class actor : public channel -{ +class actor : public channel { public: - ~actor(); + /** + * @brief Enqueues @p msg to the actor's mailbox and returns true if + * this actor is an scheduled actor that successfully changed + * its state to @p pending. + */ + virtual bool chained_enqueue(actor* sender, any_tuple msg); /** * @brief Attaches @p ptr to this actor. @@ -97,22 +107,6 @@ class actor : public channel std::is_base_of::value >::type* = 0); - /** - * @brief Forces this actor to subscribe to the group @p what. - * - * The group will be unsubscribed if the actor finishes execution. - * @param what Group instance that should be joined. - */ - void join(group_ptr& what); - - /** - * @brief Forces this actor to leave the group @p what. - * @param what Joined group that should be leaved. - * @note Groups are leaved automatically if the Actor finishes - * execution. - */ - void leave(const group_ptr& what); - /** * @brief Links this actor to @p other. * @param other Actor instance that whose execution is coupled to the @@ -150,7 +144,7 @@ class actor : public channel void link_to(intrusive_ptr&& other); /** - * @copydoc unlink_from(intrusive_ptr&) + * @copydoc :unlink_from(intrusive_ptr&) */ void unlink_from(intrusive_ptr&& other); @@ -210,6 +204,7 @@ class actor : public channel /** * @brief A smart pointer type that manages instances of {@link actor}. + * @relates actor */ typedef intrusive_ptr actor_ptr; @@ -217,23 +212,19 @@ typedef intrusive_ptr actor_ptr; * inline and template member function implementations * ******************************************************************************/ -inline const process_information& actor::parent_process() const -{ +inline const process_information& actor::parent_process() const { return *m_parent_process; } -inline process_information_ptr actor::parent_process_ptr() const -{ +inline process_information_ptr actor::parent_process_ptr() const { return m_parent_process; } -inline std::uint32_t actor::id() const -{ +inline std::uint32_t actor::id() const { return m_id; } -inline bool actor::is_proxy() const -{ +inline bool actor::is_proxy() const { return m_is_proxy; } @@ -241,43 +232,37 @@ template bool actor::attach(std::unique_ptr&& ptr, typename std::enable_if< std::is_base_of::value - >::type*) -{ + >::type*) { return attach(static_cast(ptr.release())); } template -class functor_attachable : public attachable -{ +class functor_attachable : public attachable { F m_functor; public: template - functor_attachable(FArg&& arg) : m_functor(std::forward(arg)) - { + functor_attachable(FArg&& arg) : m_functor(std::forward(arg)) { } - void actor_exited(std::uint32_t reason) - { + void actor_exited(std::uint32_t reason) { m_functor(reason); } - bool matches(const attachable::token&) - { + bool matches(const attachable::token&) { return false; } }; template -bool actor::attach_functor(F&& ftor) -{ +bool actor::attach_functor(F&& ftor) { typedef typename util::rm_ref::type f_type; return attach(new functor_attachable(std::forward(ftor))); } } // namespace cppa -#endif // ACTOR_HPP +#endif // CPPA_ACTOR_HPP diff --git a/cppa/actor_proxy.hpp b/cppa/actor_proxy.hpp index f58146e28d..481d629dd5 100644 --- a/cppa/actor_proxy.hpp +++ b/cppa/actor_proxy.hpp @@ -28,25 +28,24 @@ \******************************************************************************/ -#ifndef ACTOR_PROXY_HPP -#define ACTOR_PROXY_HPP +#ifndef CPPA_ACTOR_PROXY_HPP +#define CPPA_ACTOR_PROXY_HPP #include "cppa/actor.hpp" -#include "cppa/abstract_actor.hpp" +#include "cppa/detail/abstract_actor.hpp" namespace cppa { #ifdef CPPA_DOCUMENTATION /** - * @brief Represents a remote Actor. + * @brief Represents a remote actor. */ class actor_proxy : public actor { }; #else // CPPA_DOCUMENTATION -class actor_proxy : public abstract_actor -{ +class actor_proxy : public detail::abstract_actor { typedef abstract_actor super; @@ -54,19 +53,17 @@ class actor_proxy : public abstract_actor actor_proxy(std::uint32_t mid, const process_information_ptr& parent); - void enqueue(actor* sender, any_tuple&& msg); - - void enqueue(actor* sender, const any_tuple& msg); + void enqueue(actor* sender, any_tuple msg); void link_to(intrusive_ptr& other); - // do not cause to send this actor an ":Unlink" message + // do not cause to send this actor an "UNLINK" message // to the "original" remote actor void local_link_to(intrusive_ptr& other); void unlink_from(intrusive_ptr& other); - // do not cause to send this actor an ":Unlink" message + // do not cause to send this actor an "UNLINK" message // to the "original" remote actor void local_unlink_from(intrusive_ptr& other); @@ -76,15 +73,18 @@ class actor_proxy : public abstract_actor public: - void forward_message(const process_information_ptr&, - actor*, const any_tuple&); + void forward_message(const process_information_ptr&, actor*, any_tuple&&); }; #endif // CPPA_DOCUMENTATION +/** + * @brief A smart pointer to an {@link actor_proxy} instance. + * @relates actor_proxy + */ typedef intrusive_ptr actor_proxy_ptr; } // namespace cppa -#endif // ACTOR_PROXY_HPP +#endif // CPPA_ACTOR_PROXY_HPP diff --git a/cppa/announce.hpp b/cppa/announce.hpp index 2569ff8a14..1bdac7262e 100644 --- a/cppa/announce.hpp +++ b/cppa/announce.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef ANNOUNCE_HPP -#define ANNOUNCE_HPP +#ifndef CPPA_ANNOUNCE_HPP +#define CPPA_ANNOUNCE_HPP #include @@ -110,40 +110,55 @@ bool announce(const std::type_info& tinfo, uniform_type_info* utype); */ template std::pair*> -compound_member(C Parent::*c_ptr, const Args&... args) -{ - return { c_ptr, new detail::default_uniform_type_info_impl(args...) }; +compound_member(C Parent::*c_ptr, const Args&... args) { + return {c_ptr, new detail::default_uniform_type_info_impl(args...)}; } // deals with getter returning a mutable reference +/** + * @brief Creates meta informations for a non-trivial member accessed + * via a getter returning a mutable reference. + * @param getter Member function pointer to the getter. + * @param args "Sub-members" of @p c_ptr + * @see {@link announce_example_4.cpp announce example 4} + * @returns A pair of @p c_ptr and the created meta informations. + */ template std::pair*> -compound_member(C& (Parent::*c_ptr)(), const Args&... args) -{ - return { c_ptr, new detail::default_uniform_type_info_impl(args...) }; +compound_member(C& (Parent::*getter)(), const Args&... args) { + return {getter, new detail::default_uniform_type_info_impl(args...)}; } // deals with getter/setter pair +/** + * @brief Creates meta informations for a non-trivial member accessed + * via a getter/setter pair. + * @param gspair A pair of two member function pointers representing + * getter and setter. + * @param args "Sub-members" of @p c_ptr + * @see {@link announce_example_4.cpp announce example 4} + * @returns A pair of @p c_ptr and the created meta informations. + */ template std::pair, util::abstract_uniform_type_info::type>*> -compound_member(const std::pair& gspair, - const Args&... args) -{ - return { gspair, new detail::default_uniform_type_info_impl::type>(args...) }; +compound_member(const std::pair& gspair, + const Args&... args) { + typedef typename util::rm_ref::type mtype; + return {gspair, new detail::default_uniform_type_info_impl(args...)}; } /** * @brief Adds a new type mapping for @p T to the libcppa type system. * @param args Members of @p T. - * @returns @c true if @p T was added to the libcppa type system; - * otherwise @c false. + * @returns @c true if @p T was added to the libcppa type system, + * @c false otherwise. */ template -inline bool announce(const Args&... args) -{ +inline bool announce(const Args&... args) { return announce(typeid(T), new detail::default_uniform_type_info_impl(args...)); } @@ -154,4 +169,4 @@ inline bool announce(const Args&... args) } // namespace cppa -#endif // ANNOUNCE_HPP +#endif // CPPA_ANNOUNCE_HPP diff --git a/cppa/any_tuple.hpp b/cppa/any_tuple.hpp index a9df0f74c0..49722f9411 100644 --- a/cppa/any_tuple.hpp +++ b/cppa/any_tuple.hpp @@ -28,16 +28,17 @@ \******************************************************************************/ -#ifndef ANY_TUPLE_HPP -#define ANY_TUPLE_HPP +#ifndef CPPA_ANY_TUPLE_HPP +#define CPPA_ANY_TUPLE_HPP #include -#include "cppa/cow_tuple.hpp" #include "cppa/config.hpp" #include "cppa/cow_ptr.hpp" +#include "cppa/cow_tuple.hpp" #include "cppa/util/rm_ref.hpp" +#include "cppa/util/comparable.hpp" #include "cppa/util/is_iterable.hpp" #include "cppa/detail/tuple_view.hpp" @@ -51,11 +52,11 @@ namespace cppa { * @brief Describes a fixed-length copy-on-write tuple * with elements of any type. */ -class any_tuple -{ +class any_tuple { public: + typedef cow_ptr value_ptr; typedef detail::abstract_tuple::const_iterator const_iterator; /** @@ -75,8 +76,6 @@ class any_tuple template any_tuple(cow_tuple&& t) : m_vals(std::move(t.m_vals)) { } - explicit any_tuple(detail::abstract_tuple*); - /** * @brief Move constructor. */ @@ -110,13 +109,13 @@ class any_tuple /** * @brief Gets a const pointer to the element at position @p p. */ - void const* at(size_t p) const; + const void* at(size_t p) const; /** * @brief Gets {@link uniform_type_info uniform type information} * of the element at position @p p. */ - uniform_type_info const* type_at(size_t p) const; + const uniform_type_info* type_at(size_t p) const; /** * @brief Returns @c true if *this == other, otherwise false. @@ -129,15 +128,13 @@ class any_tuple inline bool empty() const { return size() == 0; } template - inline const T& get_as(size_t p) const - { + inline const T& get_as(size_t p) const { CPPA_REQUIRE(*(type_at(p)) == typeid(T)); - return *reinterpret_cast(at(p)); + return *reinterpret_cast(at(p)); } template - inline T& get_as_mutable(size_t p) - { + inline T& get_as_mutable(size_t p) { CPPA_REQUIRE(*(type_at(p)) == typeid(T)); return *reinterpret_cast(mutable_at(p)); } @@ -146,17 +143,15 @@ class any_tuple inline const_iterator end() const { return m_vals->end(); } - inline cow_ptr& vals() { return m_vals; } - inline const cow_ptr& vals() const { return m_vals; } - inline const cow_ptr& cvals() const { return m_vals; } + inline value_ptr& vals() { return m_vals; } + inline const value_ptr& vals() const { return m_vals; } + inline const value_ptr& cvals() const { return m_vals; } - inline std::type_info const* type_token() const - { + inline const std::type_info* type_token() const { return m_vals->type_token(); } - inline detail::tuple_impl_info impl_type() const - { + inline detail::tuple_impl_info impl_type() const { return m_vals->impl_type(); } @@ -166,9 +161,8 @@ class any_tuple util::is_iterable< typename util::rm_ref::type >::value - >::type* = 0) - { - static constexpr bool can_optimize = std::is_reference::value + >::type* = 0) { + static constexpr bool can_optimize = std::is_reference::value && !std::is_const::value; std::integral_constant token; return any_tuple{container_view(std::forward(value), token)}; @@ -180,79 +174,68 @@ class any_tuple util::is_iterable< typename util::rm_ref::type >::value == false - >::type* = 0) - { + >::type* = 0) { typedef typename util::rm_ref::type vtype; typedef typename detail::implicit_conversions::type converted; static_assert(util::is_legal_tuple_type::value, "T is not a valid tuple type"); + typedef typename std::remove_reference::type plain_type; static constexpr bool can_optimize = - std::is_same::value - && std::is_reference::value - && !std::is_const::type>::value; + std::is_same::value + && std::is_reference::value + && !std::is_const::value; std::integral_constant token; return any_tuple{simple_view(std::forward(value), token)}; } - void force_detach() - { - m_vals.detach(); - } + inline void force_detach() { m_vals.detach(); } void reset(); + explicit any_tuple(detail::abstract_tuple*); + private: - cow_ptr m_vals; + value_ptr m_vals; - explicit any_tuple(const cow_ptr& vals); + explicit any_tuple(const value_ptr& vals); - typedef detail::abstract_tuple* tup_ptr; + typedef detail::abstract_tuple* abstract_ptr; template - static inline tup_ptr simple_view(T& value, - std::integral_constant) - { + static inline abstract_ptr simple_view(T& value, std::true_type) { return new detail::tuple_view(&value); } template - static inline tup_ptr simple_view(std::pair& p, - std::integral_constant) - { + static inline abstract_ptr simple_view(std::pair& p, + std::true_type) { return new detail::tuple_view(&p.first, &p.second); } template - static inline tup_ptr simple_view(T&& value, - std::integral_constant) - { + static inline abstract_ptr simple_view(T&& value, std::false_type) { typedef typename util::rm_ref::type vtype; typedef typename detail::implicit_conversions::type converted; return new detail::tuple_vals(std::forward(value)); } template - static inline any_tuple view(std::pair p, - std::integral_constant) - { + static inline any_tuple view(std::pair p, std::false_type) { return new detail::tuple_vals(std::move(p.first), std::move(p.second)); } template - static inline detail::abstract_tuple* container_view(T& value, - std::integral_constant) - { + static inline abstract_ptr container_view(T& value, std::true_type) { return new detail::container_tuple_view(&value); } template - static inline detail::abstract_tuple* container_view(T&& value, - std::integral_constant) - { + static inline abstract_ptr container_view(T&& value, std::false_type) { typedef typename util::rm_ref::type ctype; - return new detail::container_tuple_view(new ctype(std::forward(value)), true); + auto cptr = new ctype(std::forward(value)); + return new detail::container_tuple_view(cptr, true); } }; @@ -260,19 +243,26 @@ class any_tuple /** * @relates any_tuple */ -inline bool operator==(const any_tuple& lhs, const any_tuple& rhs) -{ +inline bool operator==(const any_tuple& lhs, const any_tuple& rhs) { return lhs.equals(rhs); } /** * @relates any_tuple */ -inline bool operator!=(const any_tuple& lhs, const any_tuple& rhs) -{ +inline bool operator!=(const any_tuple& lhs, const any_tuple& rhs) { return !(lhs == rhs); } +/** + * @brief Creates an {@link any_tuple} containing the elements @p args. + * @param args Values to initialize the tuple elements. + */ +template +inline any_tuple make_any_tuple(Args&&... args) { + return make_cow_tuple(std::forward(args)...); +} + } // namespace cppa -#endif // ANY_TUPLE_HPP +#endif // CPPA_ANY_TUPLE_HPP diff --git a/cppa/anything.hpp b/cppa/anything.hpp index abe7639264..15a445d943 100644 --- a/cppa/anything.hpp +++ b/cppa/anything.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef LIBCPPA_ANYTHING_HPP -#define LIBCPPA_ANYTHING_HPP +#ifndef CPPA_ANYTHING_HPP +#define CPPA_ANYTHING_HPP #include @@ -40,23 +40,29 @@ namespace cppa { */ struct anything { }; -inline bool operator==(const anything&, const anything&) -{ - return true; -} +/** + * @brief Compares two instances of {@link anything}. + * @returns @p false + * @relates anything + */ +inline bool operator==(const anything&, const anything&) { return true; } -inline bool operator!=(const anything&, const anything&) -{ - return false; -} +/** + * @brief Compares two instances of {@link anything}. + * @returns @p false + * @relates anything + */ +inline bool operator!=(const anything&, const anything&) { return false; } +/** + * @brief Checks wheter @p T is {@link anything}. + */ template -struct is_anything -{ +struct is_anything { static constexpr bool value = std::is_same::value; }; } // namespace cppa -#endif // ANYTHING_HPP +#endif // CPPA_ANYTHING_HPP diff --git a/cppa/atom.hpp b/cppa/atom.hpp index ebdbef380b..72eb86a68d 100644 --- a/cppa/atom.hpp +++ b/cppa/atom.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef ATOM_HPP -#define ATOM_HPP +#ifndef CPPA_ATOM_HPP +#define CPPA_ATOM_HPP #include @@ -37,16 +37,25 @@ namespace cppa { +/** + * @brief The value type of atoms. + */ enum class atom_value : std::uint64_t { dirty_little_hack = 37337 }; -std::string to_string(const atom_value& a); +/** + * @brief Returns @p what as a string representation. + * @param what Compact representation of an atom. + * @returns @p what as string. + */ +std::string to_string(const atom_value& what); /** * @brief Creates an atom from given string literal. + * @param str String constant representing an atom. + * @returns A compact representation of @p str. */ template -constexpr atom_value atom(char const (&str) [Size]) -{ +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)); @@ -54,4 +63,4 @@ constexpr atom_value atom(char const (&str) [Size]) } // namespace cppa -#endif // ATOM_HPP +#endif // CPPA_ATOM_HPP diff --git a/cppa/attachable.hpp b/cppa/attachable.hpp index a4839e68c8..2b4d8b62ed 100644 --- a/cppa/attachable.hpp +++ b/cppa/attachable.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef ATTACHABLE_HPP -#define ATTACHABLE_HPP +#ifndef CPPA_ATTACHABLE_HPP +#define CPPA_ATTACHABLE_HPP #include #include @@ -39,8 +39,7 @@ namespace cppa { /** * @brief Callback utility class. */ -class attachable -{ +class attachable { attachable(const attachable&) = delete; attachable& operator=(const attachable&) = delete; @@ -54,8 +53,7 @@ class attachable /** * @brief Represents a pointer to a value with its RTTI. */ - struct token - { + struct token { /** * @brief Denotes the type of @c ptr. */ @@ -63,10 +61,9 @@ class attachable /** * @brief Any value, used to identify @c attachable instances. */ - void const* ptr; - inline token(const std::type_info& msubtype, void const* mptr) - : subtype(msubtype), ptr(mptr) - { + const void* ptr; + inline token(const std::type_info& msubtype, const void* mptr) + : subtype(msubtype), ptr(mptr) { } }; @@ -91,4 +88,4 @@ class attachable } // namespace cppa -#endif // ATTACHABLE_HPP +#endif // CPPA_ATTACHABLE_HPP diff --git a/cppa/behavior.hpp b/cppa/behavior.hpp index 590120c45f..ac417eaab1 100644 --- a/cppa/behavior.hpp +++ b/cppa/behavior.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef BEHAVIOR_HPP -#define BEHAVIOR_HPP +#ifndef CPPA_BEHAVIOR_HPP +#define CPPA_BEHAVIOR_HPP #include #include @@ -49,58 +49,56 @@ namespace cppa { /** * @brief Describes the behavior of an actor. */ -class behavior -{ +class behavior { friend behavior operator,(partial_function&& lhs, behavior&& rhs); - behavior(const behavior&) = delete; - behavior& operator=(const behavior&) = delete; - public: behavior() = default; behavior(behavior&&) = default; + behavior(const behavior&) = default; + behavior& operator=(behavior&&) = default; + behavior& operator=(const behavior&) = default; - inline behavior(partial_function&& fun) : m_fun(std::move(fun)) - { - } + inline behavior(partial_function&& fun) : m_fun(std::move(fun)) { } template behavior(const match_expr& me) : m_fun(me) { } inline behavior(util::duration tout, std::function&& handler) - : m_timeout(tout), m_timeout_handler(std::move(handler)) - { + : m_timeout(tout), m_timeout_handler(std::move(handler)) { } - behavior& operator=(behavior&&) = default; - - //behavior& operator=(partial_function&& pfun) - //{ - // m_fun = std::move(pfun); - // return *this; - //} - - inline void handle_timeout() const - { + inline void handle_timeout() const { m_timeout_handler(); } - inline const util::duration& timeout() const - { + inline const util::duration& timeout() const { return m_timeout; } - inline partial_function& get_partial_function() - { + inline partial_function& get_partial_function() { return m_fun; } - private: + inline bool operator()(any_tuple& value) { + return m_fun(value); + } - // terminates recursion - inline behavior& splice() { return *this; } + inline bool operator()(const any_tuple& value) { + return m_fun(value); + } + + inline bool operator()(any_tuple&& value) { + return m_fun(std::move(value)); + } + + inline bool undefined() const { + return m_fun.undefined() && m_timeout.valid() == false; + } + + private: partial_function m_fun; util::duration m_timeout; @@ -108,23 +106,24 @@ class behavior }; +/** + * @brief Concatenates a match expression and a timeout specification + * represented by an rvalue behavior object. + */ template -behavior operator,(const match_expr& lhs, - behavior&& rhs) -{ +behavior operator,(const match_expr& lhs, behavior&& rhs) { + CPPA_REQUIRE(rhs.get_partial_function().undefined()); rhs.get_partial_function() = lhs; return std::move(rhs); } template -behavior bhvr_collapse(Arg0&& arg) -{ +behavior bhvr_collapse(Arg0&& arg) { return {std::forward(arg)}; } template -behavior bhvr_collapse(Arg0&& arg0, Arg1&& arg1, Args&&... args) -{ +behavior bhvr_collapse(Arg0&& arg0, Arg1&& arg1, Args&&... args) { return bhvr_collapse((std::forward(arg0), std::forward(arg1)), std::forward(args)...); } @@ -134,8 +133,7 @@ typename std::enable_if< util::disjunction...>::value, behavior >::type -match_expr_concat(Args&&... args) -{ +match_expr_concat(Args&&... args) { return bhvr_collapse(std::forward(args)...); } @@ -149,26 +147,22 @@ typename std::enable_if< >::value == false, partial_function >::type -match_expr_concat(Args&&... args) -{ +match_expr_concat(Args&&... args) { return mexpr_concat_convert(std::forward(args)...); } -inline partial_function match_expr_concat(partial_function&& pfun) -{ +inline partial_function match_expr_concat(partial_function&& pfun) { return std::move(pfun); } -inline behavior match_expr_concat(behavior&& bhvr) -{ +inline behavior match_expr_concat(behavior&& bhvr) { return std::move(bhvr); } namespace detail { template -struct select_bhvr -{ +struct select_bhvr { static constexpr bool timed = util::disjunction...>::value; typedef typename util::if_else_c #include "cppa/serializer.hpp" @@ -42,8 +42,7 @@ namespace detail { class binary_writer; } * @brief Implements the serializer interface with * a binary serialization protocol. */ -class binary_serializer : public serializer -{ +class binary_serializer : public serializer { friend class detail::binary_writer; @@ -70,13 +69,7 @@ class binary_serializer : public serializer void write_value(const primitive_variant& value); - void write_tuple(size_t size, primitive_variant const* values); - - /** - * @brief Takes the internal buffer and returns it. - * - */ - std::pair take_buffer(); + void write_tuple(size_t size, const primitive_variant* values); /** * @brief Returns the number of written bytes. @@ -86,7 +79,11 @@ class binary_serializer : public serializer /** * @brief Returns a pointer to the internal buffer. */ - char const* data() const; + const char* data() const; + + size_t sendable_size() const; + + const char* sendable_data(); /** * @brief Resets the internal buffer. @@ -97,4 +94,4 @@ class binary_serializer : public serializer } // namespace cppa -#endif // BINARY_SERIALIZER_HPP +#endif // CPPA_BINARY_SERIALIZER_HPP diff --git a/cppa/channel.hpp b/cppa/channel.hpp index 9a5d2efa39..d1aba53247 100644 --- a/cppa/channel.hpp +++ b/cppa/channel.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef CHANNEL_HPP -#define CHANNEL_HPP +#ifndef CPPA_CHANNEL_HPP +#define CPPA_CHANNEL_HPP #include "cppa/ref_counted.hpp" #include "cppa/intrusive_ptr.hpp" @@ -47,8 +47,7 @@ class any_tuple; * This interface describes an entity that can receive messages * and is implemented by {@link actor} and {@link group}. */ -class channel : public ref_counted -{ +class channel : public ref_counted { friend class actor; friend class group; @@ -60,9 +59,7 @@ class channel : public ref_counted /** * @brief Enqueues @p msg to the list of received messages. */ - virtual void enqueue(actor* sender, const any_tuple& msg) = 0; - - virtual void enqueue(actor* sender, any_tuple&& msg) = 0; + virtual void enqueue(actor* sender, any_tuple msg) = 0; private: @@ -74,9 +71,10 @@ class channel : public ref_counted /** * @brief A smart pointer type that manages instances of {@link channel}. + * @relates channel */ typedef intrusive_ptr channel_ptr; } // namespace cppa -#endif // CHANNEL_HPP +#endif // CPPA_CHANNEL_HPP diff --git a/cppa/config.hpp b/cppa/config.hpp index a1c1659f89..d3b6f68ed6 100644 --- a/cppa/config.hpp +++ b/cppa/config.hpp @@ -31,9 +31,8 @@ #ifndef CPPA_CONFIG_HPP #define CPPA_CONFIG_HPP -// uncomment this line or use -// ./configure CXXFLAGS="-DCPPA_DISABLE_CONTEXT_SWITCHING" -// if ucontext_t is not available on your platform +// uncomment this line or use define CPPA_DISABLE_CONTEXT_SWITCHING using CMAKE +// if boost.context is not available on your platform //#define CPPA_DISABLE_CONTEXT_SWITCHING #if defined(__GNUC__) @@ -53,22 +52,10 @@ # error Plattform and/or compiler not supportet #endif -#if defined(__amd64__) || defined(__LP64__) -# define CPPA_64BIT -#endif - -#ifdef CPPA_MACOS -# include -# define CPPA_MEMORY_BARRIER() OSMemoryBarrier() -#elif defined(CPPA_GCC) -# define CPPA_MEMORY_BARRIER() __sync_synchronize() -#else -# error Plattform and/or compiler not supportet -#endif - -#ifdef CPPA_DEBUG #include #include + +#ifdef CPPA_DEBUG #include #define CPPA_REQUIRE__(stmt, file, line) \ @@ -87,4 +74,11 @@ #define CPPA_REQUIRE(unused) ((void) 0) #endif // CPPA_DEBUG +#define CPPA_CRITICAL__(error, file, line) { \ + printf("%s:%u: critical error: '%s'\n", file, line, error); \ + exit(7); \ + } ((void) 0) + +#define CPPA_CRITICAL(error) CPPA_CRITICAL__(error, __FILE__, __LINE__) + #endif // CPPA_CONFIG_HPP diff --git a/cppa/detail/yielding_actor.hpp b/cppa/context_switching_actor.hpp similarity index 55% rename from cppa/detail/yielding_actor.hpp rename to cppa/context_switching_actor.hpp index 7962a01f1b..74dea4cf8e 100644 --- a/cppa/detail/yielding_actor.hpp +++ b/cppa/context_switching_actor.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef YIELDING_ACTOR_HPP -#define YIELDING_ACTOR_HPP +#ifndef CPPA_CONTEXT_SWITCHING_ACTOR_HPP +#define CPPA_CONTEXT_SWITCHING_ACTOR_HPP #include "cppa/config.hpp" @@ -40,59 +40,87 @@ #include "cppa/either.hpp" #include "cppa/pattern.hpp" +#include "cppa/detail/receive_policy.hpp" +#include "cppa/detail/behavior_stack.hpp" #include "cppa/detail/yield_interface.hpp" +#include "cppa/detail/stacked_actor_mixin.hpp" #include "cppa/detail/abstract_scheduled_actor.hpp" -namespace cppa { namespace detail { +namespace cppa { -class yielding_actor : public abstract_scheduled_actor -{ +#ifdef CPPA_DOCUMENTATION - typedef abstract_scheduled_actor super; - typedef super::queue_node queue_node; - typedef super::queue_node_ptr queue_node_ptr; +/** + * @brief Context-switching actor implementation. + */ +class context_switching_actor : public scheduled_actor { - util::fiber m_fiber; - scheduled_actor* m_behavior; + protected: + + /** + * @brief Implements the actor's behavior. + * Reimplemented this function for a class-based actor. + * Returning from this member function will end the + * execution of the actor. + */ + virtual void run(); + +}; + +#else // CPPA_DOCUMENTATION - static void run(void* _this); +class context_switching_actor : public detail::stacked_actor_mixin< + context_switching_actor, + detail::abstract_scheduled_actor> { - void exec_loop_stack(); + friend class detail::receive_policy; - void yield_until_not_empty(); + typedef detail::stacked_actor_mixin< + context_switching_actor, + detail::abstract_scheduled_actor> super; public: - yielding_actor(scheduled_actor* behavior, scheduler* sched); + context_switching_actor(std::function fun); - ~yielding_actor(); //override + resume_result resume(util::fiber* from); //override - void dequeue(behavior& bhvr); //override + scheduled_actor_type impl_type(); - void dequeue(partial_function& fun); //override + protected: - void resume(util::fiber* from, resume_callback* callback); //override + context_switching_actor(); private: - template - void dequeue_impl(Fun rm_fun) - { - auto& mbox_cache = m_mailbox.cache(); - auto mbox_end = mbox_cache.end(); - auto iter = std::find_if(mbox_cache.begin(), mbox_end, rm_fun); - while (iter == mbox_end) - { - yield_until_not_empty(); - iter = std::find_if(m_mailbox.try_fetch_more(), mbox_end, rm_fun); - } - mbox_cache.erase(iter); + // required by detail::nestable_receive_policy + static const detail::receive_policy_flag receive_flag = detail::rp_nestable; + detail::recursive_queue_node* receive_node(); + inline int init_timeout(const util::duration& timeout) { + // request timeout message + request_timeout(timeout); + return 0; + } + inline detail::recursive_queue_node* try_receive_node() { + return m_mailbox.try_pop(); } + inline detail::recursive_queue_node* try_receive_node(int) { + // timeout is triggered from an explicit timeout message + return receive_node(); + } + + // required by util::fiber + static void trampoline(void* _this); + + // members + util::fiber m_fiber; }; -} } // namespace cppa::detail +#endif // CPPA_DOCUMENTATION + +} // namespace cppa #endif // CPPA_DISABLE_CONTEXT_SWITCHING -#endif // YIELDING_ACTOR_HPP +#endif // CPPA_CONTEXT_SWITCHING_ACTOR_HPP diff --git a/cppa/cow_ptr.hpp b/cppa/cow_ptr.hpp index 29016461d8..0fe0e8253c 100644 --- a/cppa/cow_ptr.hpp +++ b/cppa/cow_ptr.hpp @@ -28,13 +28,15 @@ \******************************************************************************/ -#ifndef COW_PTR_HPP -#define COW_PTR_HPP +#ifndef CPPA_COW_PTR_HPP +#define CPPA_COW_PTR_HPP +#include #include #include #include "cppa/intrusive_ptr.hpp" +#include "cppa/util/comparable.hpp" namespace cppa { @@ -46,92 +48,93 @@ namespace cppa { * {@link ref_counted}. */ template -class cow_ptr -{ +class cow_ptr : util::comparable >, + util::comparable, const T*>, + util::comparable, std::nullptr_t> { public: - template - explicit cow_ptr(Y* raw_ptr) : m_ptr(raw_ptr) { } + typedef T* pointer; + typedef const T* const_pointer; + typedef T element_type; + typedef T& reference; + typedef const T& const_reference; - explicit cow_ptr(T* raw_ptr) : m_ptr(raw_ptr) { } + constexpr cow_ptr() : m_ptr() { } - cow_ptr(cow_ptr&& other) : m_ptr(std::move(other.m_ptr)) { } + cow_ptr(pointer raw_ptr) : m_ptr(raw_ptr) { } - cow_ptr(const cow_ptr& other) : m_ptr(other.m_ptr) { } + 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(const cow_ptr& other) : m_ptr(const_cast(other.get())) { } - - inline void swap(cow_ptr& other) - { - m_ptr.swap(other.m_ptr); + cow_ptr(cow_ptr other) : m_ptr(other.m_ptr.release()) { + static_assert(std::is_convertible::value, + "Y* is not assignable to T*"); } - cow_ptr& operator=(cow_ptr&& other) - { - swap(other); - return *this; - } - - cow_ptr& operator=(const cow_ptr& other) - { - cow_ptr tmp{other}; - swap(tmp); - return *this; - } + inline void swap(cow_ptr& other) { m_ptr.swap(other.m_ptr); } template - cow_ptr& operator=(const cow_ptr& other) - { - cow_ptr tmp{other}; - swap(tmp); + cow_ptr& operator=(cow_ptr other) { + m_ptr = std::move(other.m_ptr); return *this; } - void detach() - { - (void) detached_ptr(); - } + void detach() { static_cast(get_detached()); } inline void reset(T* value = nullptr) { m_ptr.reset(value); } - inline T* get() { return (m_ptr) ? detached_ptr() : nullptr; } - - inline T& operator*() { return *detached_ptr(); } - - inline T* operator->() { return detached_ptr(); } - - inline T const* get() const { return ptr(); } - - inline const T& operator*() const { return *ptr(); } - - inline T const* operator->() const { return ptr(); } + // non-const access (detaches this pointer) + inline pointer get() { return (m_ptr) ? get_detached() : nullptr; } + inline pointer operator->() { return get_detached(); } + inline reference operator*() { return *get_detached(); } + // const access (does not detach this pointer) + inline const_pointer get() const { return m_ptr.get(); } + inline const_pointer operator->() const { return get(); } + inline const_reference operator*() const { return *get(); } inline explicit operator bool() const { return static_cast(m_ptr); } + template + inline ptrdiff_t compare(Arg&& what) const { + return m_ptr.compare(std::forward(what)); + } + private: intrusive_ptr m_ptr; - T* detached_ptr() - { - T* ptr = m_ptr.get(); - if (!ptr->unique()) - { - //T* new_ptr = detail::copy_of(ptr, copy_of_token()); - T* new_ptr = ptr->copy(); - cow_ptr tmp(new_ptr); - swap(tmp); + pointer get_detached() { + auto ptr = m_ptr.get(); + if (!ptr->unique()) { + pointer new_ptr = ptr->copy(); + reset(new_ptr); return new_ptr; } return ptr; } - inline T const* ptr() const { return m_ptr.get(); } - }; +/** + * @relates cow_ptr + */ +template +inline bool operator==(const cow_ptr& lhs, const cow_ptr& rhs) { + return lhs.get() == rhs.get(); +} + +/** + * @relates cow_ptr + */ +template +inline bool operator!=(const cow_ptr& lhs, const cow_ptr& rhs) { + return !(lhs == rhs); +} + } // namespace cppa -#endif // COW_PTR_HPP +#endif // CPPA_COW_PTR_HPP diff --git a/cppa/cow_tuple.hpp b/cppa/cow_tuple.hpp index d4134deebd..4010fe43ca 100644 --- a/cppa/cow_tuple.hpp +++ b/cppa/cow_tuple.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef CPPA_TUPLE_HPP -#define CPPA_TUPLE_HPP +#ifndef CPPA_COW_TUPLE_HPP +#define CPPA_COW_TUPLE_HPP #include #include @@ -43,7 +43,6 @@ #include "cppa/util/at.hpp" #include "cppa/util/fixed_vector.hpp" -#include "cppa/util/replace_type.hpp" #include "cppa/util/is_comparable.hpp" #include "cppa/util/compare_tuples.hpp" #include "cppa/util/is_legal_tuple_type.hpp" @@ -63,8 +62,7 @@ class local_actor; * @brief A fixed-length copy-on-write cow_tuple. */ template -class cow_tuple -{ +class cow_tuple { static_assert(sizeof...(ElementTypes) > 0, "tuple is empty"); @@ -94,24 +92,21 @@ class cow_tuple /** * @brief Initializes each element with its default constructor. */ - cow_tuple() : m_vals(new data_type) - { + cow_tuple() : m_vals(new data_type) { } /** * @brief Initializes the cow_tuple with @p args. * @param args Initialization values. */ - cow_tuple(const ElementTypes&... args) : m_vals(new data_type(args...)) - { + cow_tuple(const ElementTypes&... args) : m_vals(new data_type(args...)) { } /** * @brief Initializes the cow_tuple with @p args. * @param args Initialization values. */ - cow_tuple(ElementTypes&&... args) : m_vals(new data_type(std::move(args)...)) - { + cow_tuple(ElementTypes&&... args) : m_vals(new data_type(std::move(args)...)) { } cow_tuple(cow_tuple&&) = default; @@ -119,19 +114,16 @@ class cow_tuple cow_tuple& operator=(cow_tuple&&) = default; cow_tuple& operator=(const cow_tuple&) = default; - inline static cow_tuple from(cow_ptr_type ptr) - { + inline static cow_tuple from(cow_ptr_type ptr) { return {priv_ctor{}, std::move(ptr)}; } inline static cow_tuple from(cow_ptr_type ptr, - const util::fixed_vector& mv) - { + const util::fixed_vector& mv) { return {priv_ctor{}, decorated_type::create(std::move(ptr), mv)}; } - inline static cow_tuple offset_subtuple(cow_ptr_type ptr, size_t offset) - { + inline static cow_tuple offset_subtuple(cow_ptr_type ptr, size_t offset) { CPPA_REQUIRE(offset > 0); return {priv_ctor{}, decorated_type::create(std::move(ptr), offset)}; } @@ -139,24 +131,21 @@ class cow_tuple /** * @brief Gets the size of this cow_tuple. */ - inline size_t size() const - { + inline size_t size() const { return sizeof...(ElementTypes); } /** * @brief Gets a const pointer to the element at position @p p. */ - inline void const* at(size_t p) const - { + inline const void* at(size_t p) const { return m_vals->at(p); } /** * @brief Gets a mutable pointer to the element at position @p p. */ - inline void* mutable_at(size_t p) - { + inline void* mutable_at(size_t p) { return m_vals->mutable_at(p); } @@ -164,13 +153,11 @@ class cow_tuple * @brief Gets {@link uniform_type_info uniform type information} * of the element at position @p p. */ - inline uniform_type_info const* type_at(size_t p) const - { + inline const uniform_type_info* type_at(size_t p) const { return m_vals->type_at(p); } - inline const cow_ptr& vals() const - { + inline const cow_ptr& vals() const { return m_vals; } @@ -180,8 +167,7 @@ template struct cow_tuple_from_type_list; template -struct cow_tuple_from_type_list< util::type_list > -{ +struct cow_tuple_from_type_list< util::type_list > { typedef cow_tuple type; }; @@ -223,23 +209,20 @@ cow_tuple make_cow_tuple(Args&&... args); #else template -const typename util::at::type& get(const cow_tuple& tup) -{ +const typename util::at::type& get(const cow_tuple& tup) { typedef typename util::at::type result_type; - return *reinterpret_cast(tup.at(N)); + return *reinterpret_cast(tup.at(N)); } template -typename util::at::type& get_ref(cow_tuple& tup) -{ +typename util::at::type& get_ref(cow_tuple& tup) { typedef typename util::at::type result_type; return *reinterpret_cast(tup.mutable_at(N)); } template cow_tuple::type...> -make_cow_tuple(Args&&... args) -{ +make_cow_tuple(Args&&... args) { return {std::forward(args)...}; } @@ -254,8 +237,7 @@ make_cow_tuple(Args&&... args) */ template inline bool operator==(const cow_tuple& lhs, - const cow_tuple& rhs) -{ + const cow_tuple& rhs) { return util::compare_tuples(lhs, rhs); } @@ -268,11 +250,10 @@ inline bool operator==(const cow_tuple& lhs, */ template inline bool operator!=(const cow_tuple& lhs, - const cow_tuple& rhs) -{ + const cow_tuple& rhs) { return !(lhs == rhs); } } // namespace cppa -#endif +#endif // CPPA_COW_TUPLE_HPP diff --git a/cppa/cppa.hpp b/cppa/cppa.hpp index c3f96bd63a..b9d73cb635 100644 --- a/cppa/cppa.hpp +++ b/cppa/cppa.hpp @@ -32,24 +32,27 @@ #define CPPA_HPP #include +#include #include +#include #include #include "cppa/on.hpp" #include "cppa/atom.hpp" #include "cppa/self.hpp" -#include "cppa/cow_tuple.hpp" #include "cppa/actor.hpp" #include "cppa/channel.hpp" #include "cppa/receive.hpp" +#include "cppa/factory.hpp" #include "cppa/behavior.hpp" #include "cppa/announce.hpp" +#include "cppa/sb_actor.hpp" #include "cppa/scheduler.hpp" #include "cppa/to_string.hpp" #include "cppa/any_tuple.hpp" -#include "cppa/fsm_actor.hpp" -#include "cppa/local_actor.hpp" +#include "cppa/cow_tuple.hpp" #include "cppa/exit_reason.hpp" +#include "cppa/local_actor.hpp" #include "cppa/scheduled_actor.hpp" #include "cppa/scheduling_hint.hpp" #include "cppa/event_based_actor.hpp" @@ -69,41 +72,45 @@ * * 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 using C++. + * of both concurrent and distributed software. * * @p libcppa 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 @p libcppa requires a minimum of gluecode. - * You don't have to derive a particular class to implement an actor and + * Writing applications in @p libcppa requires a minimum of gluecode and * each context is an actor. Even main is implicitly - * converted to an actor if needed, as the following example shows: - * - * It's recommended to read at least the - * {@link MessageHandling message handling} - * section of this documentation. + * converted to an actor if needed. * * @section GettingStarted Getting Started * - * To build @p libcppa, you need GCC >= 4.6, @p Automake - * and the Boost.Thread library. + * To build @p libcppa, you need GCC >= 4.7 or Clang >= 3.2, + * @p CMake and the Boost.Thread library. * * The usual build steps on Linux and Mac OS X are: * - * - autoreconf -i - * - ./configure - * - make - * - make install (as root, optionally) + *- mkdir build + *- cd build + *- cmake .. + *- make + *- make install (as root, optionally) + * + * Please run the unit tests as well to verify that @p libcppa works properly. * - * Use ./configure --help if the script doesn't auto-select - * the correct @p GCC binary or doesn't find your Boost.Thread - * installation. + *- ./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 @p libcppa. * + * Please read the Manual for an introduction to @p libcppa. + * It is available online at + * http://neverlord.github.com/libcppa/manual/index.html or as PDF version at + * http://neverlord.github.com/libcppa/manual/libcppa_manual.pdf + * * @section IntroHelloWorld Hello World Example * * @include hello_world_example.cpp @@ -117,24 +124,32 @@ * features. * * @namespace cppa - * @brief This is the root namespace of libcppa. - * - * Thie @b cppa namespace contains all functions and classes to - * implement Actor based applications. + * @brief Root namespace of libcppa. * * @namespace cppa::util - * @brief This namespace contains utility classes and metaprogramming + * @brief Contains utility classes and metaprogramming * utilities used by the libcppa implementation. * * @namespace cppa::intrusive - * @brief This namespace contains intrusive container implementations. + * @brief Contains intrusive container implementations. + * + * @namespace cppa::factory + * @brief Contains factory functions to create actors from lambdas or + * other functors. + * + * @namespace cppa::exit_reason + * @brief Contains all predefined exit reasons. + * + * @namespace cppa::placeholders + * @brief Contains the guard placeholders @p _x1 to @p _x9. * * @defgroup CopyOnWrite Copy-on-write optimization. * @p libcppa uses a copy-on-write optimization for its message * passing implementation. * - * {@link cppa::tuple Tuples} should @b always be used with by-value semantic, - * since tuples use a copy-on-write smart pointer internally. Let's assume two + * {@link cppa::cow_tuple Tuples} should @b always be used with by-value + * semantic,since tuples use a copy-on-write smart pointer internally. + * Let's assume two * tuple @p x and @p y, whereas @p y is a copy of @p x: * * @code @@ -178,8 +193,8 @@ * The first argument is the receiver of the message followed by any number * of values. @p send creates a tuple from the given values and enqueues the * tuple to the receivers mailbox. Thus, send should @b not be used to send - * a message to multiple receivers. You should use the @p enqueue - * member function of the receivers instead as in the following example: + * a message to multiple receivers. You should use @p operator<< + * instead as in the following example: * * @code * // spawn some actors @@ -192,20 +207,20 @@ * * // send a message to a1, a2 and a3 * auto msg = make_cow_tuple(atom("compute"), 1, 2, 3); - * auto s = self; // cache self pointer + * * // note: this is more efficient then using send() three times because * // send() would create a new tuple each time; * // this safes both time and memory thanks to libcppa's copy-on-write - * a1->enqueue(s, msg); - * a2->enqueue(s, msg); - * a3->enqueue(s, msg); + * a1 << msg; + * a2 << msg; + * a3 << msg; * * // modify msg and send it again * // (msg becomes detached due to copy-on-write optimization) * get_ref<1>(msg) = 10; // msg is now { atom("compute"), 10, 2, 3 } - * a1->enqueue(s, msg); - * a2->enqueue(s, msg); - * a3->enqueue(s, msg); + * a1 << msg; + * a2 << msg; + * a3 << msg; * @endcode * * @section Receive Receive messages @@ -216,11 +231,11 @@ * @code * receive * ( - * on() >> [](const std::string& msg) + * on(atom("hello"), arg_match) >> [](const std::string& msg) * { * cout << "received hello message: " << msg << endl; * }, - * on() >> [](int i0, int i1, int i2) + * on(atom("compute"), arg_match) >> [](int i0, int i1, int i2) * { * // send our result back to the sender of this messages * reply(atom("result"), i0 + i1 + i2); @@ -228,30 +243,7 @@ * ); * @endcode * - * The function @p on creates a pattern. - * It provides two ways of defining patterns: - * either by template parameters (prefixed by up to four atoms) or by arguments. - * The first way matches for types only (exept for the prefixing atoms). - * The second way compares values. - * Use the template function @p val to match for the type only. - * - * This example is equivalent to the previous one but uses the second way - * to define patterns: - * - * @code - * receive - * ( - * on(atom("hello"), val()) >> [](const std::string& msg) - * { - * cout << "received hello message: " << msg << endl; - * }, - * on(atom("compute"), val(), val(), val()>() >> [](int i0, int i1, int i2) - * { - * // send our result back to the sender of this messages - * reply(atom("result"), i0 + i1 + i2); - * } - * ); - * @endcode + * Please read the manual for further details about pattern matching. * * @section Atoms Atoms * @@ -263,16 +255,12 @@ * * Example actor: * @code - * void math_actor() - * { - * receive_loop - * ( - * on() >> [](int a, int b) - * { + * void math_actor() { + * receive_loop ( + * on(atom("plus"), arg_match) >> [](int a, int b) { * reply(atom("result"), a + b); * }, - * on() >> [](int a, int b) - * { + * on(atom("minus"), arg_match) >> [](int a, int b) { * reply(atom("result"), a - b); * } * ); @@ -300,10 +288,8 @@ * @code * // receive two integers * vector received_values; - * receive_while([&]() { return received_values.size() < 2; }) - * ( - * on() >> [](int value) - * { + * receive_while([&]() { return received_values.size() < 2; }) ( + * on() >> [](int value) { * received_values.push_back(value); * } * ); @@ -315,8 +301,7 @@ * @code * std::vector vec {1, 2, 3, 4}; * auto i = vec.begin(); - * receive_for(i, vec.end()) - * ( + * receive_for(i, vec.end()) ( * on(atom("get")) >> [&]() { reply(atom("result"), *i); } * ); * @endcode @@ -328,10 +313,8 @@ * @code * // receive ints until zero was received * vector received_values; - * do_receive - * ( - * on() >> [](int value) - * { + * do_receive ( + * on() >> [](int value) { * received_values.push_back(value); * } * ) @@ -341,20 +324,18 @@ * * @section FutureSend Send delayed messages * - * The function @p future_send provides a simple way to delay a message. + * The function @p delayed_send provides a simple way to delay a message. * This is particularly useful for recurring events, e.g., periodical polling. * Usage example: * * @code - * future_send(self, std::chrono::seconds(1), atom("poll")); - * receive_loop - * ( + * delayed_send(self, std::chrono::seconds(1), atom("poll")); + * receive_loop ( * // ... - * on() >> []() - * { + * on(atom("poll")) >> []() { * // ... poll something ... * // and do it again after 1sec - * future_send(self, std::chrono::seconds(1), atom("poll")); + * delayed_send(self, std::chrono::seconds(1), atom("poll")); * } * ); * @endcode @@ -365,7 +346,7 @@ * * The message passing of @p libcppa prohibits pointers in messages because * it enforces network transparent messaging. - * Unfortunately, string literals in @p C++ have the type char const*, + * Unfortunately, string literals in @p C++ have the type const char*, * resp. const char[]. Since @p libcppa is a user-friendly library, * it silently converts string literals and C-strings to @p std::string objects. * It also converts unicode literals to the corresponding STL container. @@ -375,7 +356,7 @@ * // sends an std::string containing "hello actor!" to itself * send(self, "hello actor!"); * - * char const* cstring = "cstring"; + * const char* cstring = "cstring"; * // sends an std::string containing "cstring" to itself * send(self, cstring); * @@ -385,14 +366,13 @@ * // x has the type cppa::tuple * auto x = make_cow_tuple("hello", "tuple"); * - * receive - * ( + * receive ( * // equal to: on(std::string("hello actor!")) * on("hello actor!") >> []() { } * ); * @endcode * - * @defgroup ActorManagement Actor management. + * @defgroup ActorCreation Actor creation. * */ @@ -410,7 +390,7 @@ */ /** - * @brief A simple example for a future_send based application. + * @brief A simple example for a delayed_send based application. * @example dancing_kirby.cpp */ @@ -421,295 +401,252 @@ namespace cppa { -/** - * @ingroup ActorManagement - * @brief Links @p lhs and @p rhs; - * @pre lhs != rhs - */ -void link(actor_ptr& lhs, actor_ptr& rhs); - -/** - * @copydoc link(actor_ptr&,actor_ptr&) - */ -void link(actor_ptr&& lhs, actor_ptr& rhs); - -/** - * @copydoc link(actor_ptr&,actor_ptr&) - */ -void link(actor_ptr&& lhs, actor_ptr&& rhs); - -/** - * @copydoc link(actor_ptr&,actor_ptr&) - */ -void link(actor_ptr& lhs, actor_ptr&& rhs); +namespace detail { -/** - * @ingroup ActorManagement - * @brief Unlinks @p lhs from @p rhs; - * @pre lhs != rhs - */ -void unlink(actor_ptr& lhs, actor_ptr& rhs); +template +inline void send_impl(T* whom, any_tuple&& what) { + if (whom) self->send_message(whom, std::move(what)); +} -/** - * @ingroup ActorManagement - * @brief Adds a unidirectional @p monitor to @p whom. - * @note Each calls to @p monitor creates a new, independent monitor. - * @pre The calling actor receives a ":Down" message from @p whom when - * it terminates. - */ -void monitor(actor_ptr& whom); +template +inline void send_tpl_impl(T* whom, Args&&... what) { + if (whom) self->send_message(whom, + make_any_tuple(std::forward(what)...)); +} -void monitor(actor_ptr&& whom); +} // namespace detail /** - * @ingroup ActorManagement - * @brief Removes a monitor from @p whom. + * @ingroup MessageHandling + * @{ */ -void demonitor(actor_ptr& whom); /** - * @ingroup ActorManagement - * @brief Spans a new context-switching actor. - * @returns A pointer to the spawned {@link actor Actor}. + * @brief Sends a message to @p whom. + * + * Usage example: + * @code + * self << make_any_tuple(1, 2, 3); + * @endcode + * @param whom Receiver of the message. + * @param what Message as instance of {@link any_tuple}. + * @returns @p whom. */ -inline actor_ptr spawn(scheduled_actor* what) -{ - return get_scheduler()->spawn(what, scheduled); +template +inline typename std::enable_if::value, + const intrusive_ptr& >::type +operator<<(const intrusive_ptr& whom, any_tuple what) { + detail::send_impl(whom.get(), std::move(what)); + return whom; } /** - * @ingroup ActorManagement - * @brief Spans a new context-switching actor. - * @tparam Hint Hint to the scheduler for the best scheduling strategy. - * @returns A pointer to the spawned {@link actor Actor}. + * @brief Sends {what...} as a message to @p whom. + * @param whom Receiver of the message. + * @param what Message elements. + * @pre sizeof...(Args) > 0 */ -template -inline actor_ptr spawn(scheduled_actor* what) -{ - return get_scheduler()->spawn(what, Hint); +template +inline typename std::enable_if::value>::type +send(const intrusive_ptr& whom, Args&&... what) { + static_assert(sizeof...(Args) > 0, "no message to send"); + detail::send_tpl_impl(whom.get(), std::forward(what)...); } -/** - * @ingroup ActorManagement - * @brief Spans a new event-based actor. - * @returns A pointer to the spawned {@link actor Actor}. - */ -inline actor_ptr spawn(abstract_event_based_actor* what) -{ - return get_scheduler()->spawn(what); -} /** - * @ingroup ActorManagement - * @brief Spawns a new actor that executes @p what with given arguments. - * @tparam Hint Hint to the scheduler for the best scheduling strategy. - * @param what Function or functor that the spawned Actor should execute. - * @param args Arguments needed to invoke @p what. - * @returns A pointer to the spawned {@link actor actor}. + * @brief Sends a message to the sender of the last received message. + * @param what Message elements. + * @note Equal to send(self->last_received(), what...). */ -template -auto //actor_ptr -spawn(F&& what, const Args&... args) --> typename std::enable_if< - !std::is_convertible::type, scheduled_actor*>::value - && !std::is_convertible::type, event_based_actor*>::value, - actor_ptr - >::type -{ - typedef typename util::rm_ref::type ftype; - std::integral_constant::value> is_fun; - auto ptr = detail::get_behavior(is_fun, std::forward(what), args...); - return get_scheduler()->spawn(ptr, Hint); +template +inline void reply(Args&&... what) { + send(self->last_sender(), std::forward(what)...); } /** - * @ingroup ActorManagement - * @brief Alias for spawn(what, args...). + * @brief Sends a message to @p whom that is delayed by @p rel_time. + * @param whom Receiver of the message. + * @param rel_time Relative time duration to delay the message in + * microseconds, milliseconds, seconds or minutes. + * @param what Message elements. */ -template -auto // actor_ptr -spawn(F&& what, const Args&... args) --> typename std::enable_if< - !std::is_convertible::type, scheduled_actor*>::value - && !std::is_convertible::type, event_based_actor*>::value, - actor_ptr - >::type -{ - return spawn(std::forward(what), args...); +template +inline void delayed_send(const channel_ptr& whom, + const std::chrono::duration& rel_time, + Args&&... what) { + if (whom) { + get_scheduler()->delayed_send(whom, rel_time, + std::forward(what)...); + } } -#ifdef CPPA_DOCUMENTATION - /** - * @ingroup MessageHandling - * @brief Sends {arg0, args...} as a message to @p whom. - */ -template -void send(channel_ptr& whom, const Arg0& arg0, const Args&... args); - -/** - * @ingroup MessageHandling - * @brief Send a message to @p whom. - * - * Usage example: - * @code - * self << make_cow_tuple(1, 2, 3); - * @endcode - * @returns @p whom. + * @brief Sends a reply message that is delayed by @p rel_time. + * @param rel_time Relative time duration to delay the message in + * microseconds, milliseconds, seconds or minutes. + * @param what Message elements. + * @note Equal to delayed_send(self->last_sender(), rel_time, what...). + * @see delayed_send() */ -channel_ptr& operator<<(channel_ptr& whom, const any_tuple& what); - -#else - -template -void send(intrusive_ptr& whom, const Arg0& arg0, const Args&... args) -{ - static_assert(std::is_base_of::value, "C is not a channel"); - if (whom) whom->enqueue(self, make_cow_tuple(arg0, args...)); +template +inline void delayed_reply(const std::chrono::duration& rel_time, + Args&&... what) { + delayed_send(self->last_sender(), rel_time, std::forward(what)...); } -template -void send(intrusive_ptr&& whom, const Arg0& arg0, const Args&... args) -{ - static_assert(std::is_base_of::value, "C is not a channel"); - intrusive_ptr tmp(std::move(whom)); - if (tmp) tmp->enqueue(self, make_cow_tuple(arg0, args...)); -} +/** @} */ -// matches "send(this, ...)" in event-based actors +#ifndef CPPA_DOCUMENTATION +// matches "send(this, ...)" and "send(self, ...)" template -void send(local_actor* whom, const Arg0& arg0, const Args&... args) -{ - whom->enqueue(whom, make_cow_tuple(arg0, args...)); +inline void send(local_actor* whom, Arg0&& arg0, Args&&... args) { + detail::send_tpl_impl(whom, + std::forward(arg0), + std::forward(args)...); } - - -// matches send(self, ...); -template -inline void send(const self_type&, const Arg0& arg0, const Args&... args) -{ - send(static_cast(self), arg0, args...); +inline const self_type& operator<<(const self_type& s, any_tuple what) { + detail::send_impl(s.get(), std::move(what)); + return s; } +#endif // CPPA_DOCUMENTATION -template -typename std::enable_if< - std::is_base_of::value, - intrusive_ptr& ->::type -operator<<(intrusive_ptr& whom, const any_tuple& what) -{ - if (whom) whom->enqueue(self, what); - return whom; -} +/** + * @ingroup ActorCreation + * @{ + */ -template -typename std::enable_if< - std::is_base_of::value, - intrusive_ptr ->::type -operator<<(intrusive_ptr&& whom, const any_tuple& what) -{ - intrusive_ptr tmp(std::move(whom)); - if (tmp) tmp->enqueue(self, what); - return std::move(tmp); -} -template -typename std::enable_if< - std::is_base_of::value, - intrusive_ptr& ->::type -operator<<(intrusive_ptr& whom, any_tuple&& what) -{ - if (whom) whom->enqueue(self, std::move(what)); - return whom; +/** + * @brief Spawns a new context-switching or thread-mapped {@link actor} + * that executes fun(args...). + * @param fun A function implementing the actor's behavior. + * @param args Optional function parameters for @p fun. + * @tparam Hint A hint to the scheduler for the best scheduling strategy. + * @returns An {@link actor_ptr} to the spawned {@link actor}. + */ +template +actor_ptr spawn(Fun&& fun, Args&&... args) { + return get_scheduler()->spawn_impl(Hint, + std::forward(fun), + std::forward(args)...); } -template -typename std::enable_if< - std::is_base_of::value, - intrusive_ptr ->::type -operator<<(intrusive_ptr&& whom, any_tuple&& what) -{ - intrusive_ptr tmp(std::move(whom)); - if (tmp) tmp->enqueue(self, std::move(what)); - return std::move(tmp); +/** + * @brief Spawns a new context-switching {@link actor} + * that executes fun(args...). + * @param fun A function implementing the actor's behavior. + * @param args Optional function parameters for @p fun. + * @returns An {@link actor_ptr} to the spawned {@link actor}. + * @note This function is equal to spawn(fun, args...). + */ +template +actor_ptr spawn(Fun&& fun, Args&&... args) { + return spawn(std::forward(fun), + std::forward(args)...); } -const self_type& operator<<(const self_type& s, const any_tuple& what); - -const self_type& operator<<(const self_type& s, any_tuple&& what); - -#endif // CPPA_DOCUMENTATION +/** + * @brief Spawns a new context-switching or thread-mapped {@link actor} + * that executes fun(args...) and + * joins @p grp immediately. + * @param fun A function implementing the actor's behavior. + * @param args Optional function parameters for @p fun. + * @tparam Hint A hint to the scheduler for the best scheduling strategy. + * @returns An {@link actor_ptr} to the spawned {@link actor}. + * @note The spawned actor joins @p grp after its + * {@link local_actor::init() init} member function is called but + * before it is executed. Hence, the spawned actor already joined + * the group before this function returns. + */ +template +actor_ptr spawn_in_group(const group_ptr& grp, Fun&& fun, Args&&... args) { + return get_scheduler()->spawn_cb_impl(Hint, + [grp](local_actor* ptr) { + ptr->join(grp); + }, + std::forward(fun), + std::forward(args)...); +} /** - * @ingroup MessageHandling - * @brief Sends a message to the sender of the last received message. + * @brief Spawns a new context-switching {@link actor} + * that executes fun(args...) and + * joins @p grp immediately. + * @param fun A function implementing the actor's behavior. + * @param args Optional function parameters for @p fun. + * @returns An {@link actor_ptr} to the spawned {@link actor}. + * @note The spawned actor joins @p grp after its + * {@link local_actor::init() init} member function is called but + * before it is executed. Hence, the spawned actor already joined + * the group before this function returns. + * @note This function is equal to + * spawn_in_group(fun, args...). */ -template -void reply(const Arg0& arg0, const Args&... args) -{ - send(self->last_sender(), arg0, args...); +template +actor_ptr spawn_in_group(Fun&& fun, Args&&... args) { + return spawn_in_group(std::forward(fun), + std::forward(args)...); } /** - * @ingroup MessageHandling - * @brief Sends a message to @p whom that is delayed by @p rel_time. - * @param whom Receiver of the message. - * @param rel_time Relative time duration to delay the message. - * @param data Any number of values for the message content. + * @brief Spawns an actor of type @p ActorImpl. + * @param args Optional constructor arguments. + * @tparam ActorImpl Subtype of {@link event_based_actor} or {@link sb_actor}. + * @returns An {@link actor_ptr} to the spawned {@link actor}. */ -template -void future_send(actor_ptr whom, const Duration& rel_time, const Data&... data) -{ - get_scheduler()->future_send(whom, rel_time, data...); +template +actor_ptr spawn(Args&&... args) { + return get_scheduler()->spawn(new ActorImpl(std::forward(args)...)); } /** - * @ingroup MessageHandling - * @brief Sends a reply message that is delayed by @p rel_time. - * @see future_send() + * @brief Spawns an actor of type @p ActorImpl that joins @p grp immediately. + * @param grp The group that the newly created actor shall join. + * @param args Optional constructor arguments. + * @tparam ActorImpl Subtype of {@link event_based_actor} or {@link sb_actor}. + * @returns An {@link actor_ptr} to the spawned {@link actor}. + * @note The spawned actor joins @p grp after its + * {@link local_actor::init() init} member function is called but + * before it is executed. Hence, the spawned actor already joined + * the group before this function returns. */ -template -void delayed_reply(const Duration& rel_time, Data const... data) -{ - future_send(self->last_sender(), rel_time, data...); +template +actor_ptr spawn_in_group(const group_ptr& grp, Args&&... args) { + return get_scheduler()->spawn(new ActorImpl(std::forward(args)...), + [&grp](local_actor* ptr) { ptr->join(grp); }); } +/** @} */ + /** * @brief Blocks execution of this actor until all * other actors finished execution. - * @warning This function will cause a deadlock if - * called from multiple actors. + * @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_others_done() -{ +inline void await_all_others_done() { detail::actor_count_wait_until((self.unchecked() == nullptr) ? 0 : 1); } /** - * @brief Publishes @p whom at given @p port. + * @brief Publishes @p whom at @p port. * * The connection is automatically closed if the lifetime of @p whom ends. - * @param whom Actor that should be published at given @p port. + * @param whom Actor that should be published at @p port. * @param port Unused TCP port. * @throws bind_failure */ -void publish(actor_ptr& whom, std::uint16_t port); - -/** - * @copydoc publish(actor_ptr&,std::uint16_t) - */ -void publish(actor_ptr&& whom, std::uint16_t port); +void publish(actor_ptr whom, std::uint16_t port); /** * @brief Establish a new connection to the actor at @p host on given @p port. * @param host Valid hostname or IP address. * @param port TCP port. - * @returns A pointer to the proxy instance that represents the remote Actor. + * @returns An {@link actor_ptr} to the proxy instance + * representing a remote actor. */ -actor_ptr remote_actor(char const* host, std::uint16_t port); +actor_ptr remote_actor(const char* host, std::uint16_t port); } // namespace cppa diff --git a/cppa/deserializer.hpp b/cppa/deserializer.hpp index 69e83e9b12..283d7b15ce 100644 --- a/cppa/deserializer.hpp +++ b/cppa/deserializer.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef DESERIALIZER_HPP -#define DESERIALIZER_HPP +#ifndef CPPA_DESERIALIZER_HPP +#define CPPA_DESERIALIZER_HPP #include #include @@ -45,8 +45,7 @@ class object; * @ingroup TypeSystem * @brief Technology-independent deserialization interface. */ -class deserializer -{ +class deserializer { deserializer(const deserializer&) = delete; deserializer& operator=(const deserializer&) = delete; @@ -106,13 +105,20 @@ class deserializer * @param storage Array of size @p num, storing the result of this function. */ virtual void read_tuple(size_t num, - primitive_type const* ptypes, + const primitive_type* ptypes, primitive_variant* storage ) = 0; }; -deserializer& operator>>(deserializer& d, object& what); +/** + * @brief Deserializes a value and stores the result in @p storage. + * @param d A valid deserializer. + * @param storage An that should contain the deserialized value. + * @returns @p d + * @relates deserializer + */ +deserializer& operator>>(deserializer& d, object& storage); } // namespace cppa -#endif // DESERIALIZER_HPP +#endif // CPPA_DESERIALIZER_HPP diff --git a/cppa/abstract_actor.hpp b/cppa/detail/abstract_actor.hpp similarity index 64% rename from cppa/abstract_actor.hpp rename to cppa/detail/abstract_actor.hpp index d9208998f7..dc2cc60910 100644 --- a/cppa/abstract_actor.hpp +++ b/cppa/detail/abstract_actor.hpp @@ -28,15 +28,17 @@ \******************************************************************************/ -#ifndef ABSTRACT_ACTOR_HPP -#define ABSTRACT_ACTOR_HPP +#ifndef CPPA_ABSTRACT_ACTOR_HPP +#define CPPA_ABSTRACT_ACTOR_HPP #include "cppa/config.hpp" #include +#include #include #include #include +#include #include #include "cppa/atom.hpp" @@ -44,9 +46,14 @@ #include "cppa/local_actor.hpp" #include "cppa/attachable.hpp" #include "cppa/exit_reason.hpp" -#include "cppa/detail/thread.hpp" +#include "cppa/util/shared_spinlock.hpp" -namespace cppa { +#include "cppa/detail/recursive_queue_node.hpp" +#include "cppa/intrusive/single_reader_queue.hpp" + +namespace cppa { class self_type; } + +namespace cppa { namespace detail { /** * @brief Implements linking and monitoring for actors. @@ -54,57 +61,30 @@ namespace cppa { * or {@link cppa::local_actor local_actor}. */ template -class abstract_actor : public Base -{ +class abstract_actor : public Base { + + friend class self_type; typedef std::unique_ptr attachable_ptr; - typedef detail::lock_guard guard_type; + typedef std::lock_guard guard_type; public: - struct queue_node - { - queue_node* next; // intrusive next pointer - bool marked; // denotes if this node is currently processed - actor_ptr sender; - any_tuple msg; - queue_node() : next(nullptr), marked(false) { } - queue_node(actor* from, any_tuple content) - : next(nullptr), marked(false), sender(from), msg(std::move(content)) - { - } - }; - - struct queue_node_guard - { - queue_node* m_node; - queue_node_guard(queue_node* ptr) : m_node(ptr) { ptr->marked = true; } - inline void release() { m_node = nullptr; } - ~queue_node_guard() { if (m_node) m_node->marked = false; } - }; - - typedef intrusive::single_reader_queue mailbox_type; - typedef std::unique_ptr queue_node_ptr; - typedef typename mailbox_type::cache_type mailbox_cache_type; - typedef typename mailbox_cache_type::iterator queue_node_iterator; - - bool attach(attachable* ptr) /*override*/ - { - if (ptr == nullptr) - { + typedef detail::recursive_queue_node mailbox_element; + typedef intrusive::single_reader_queue mailbox_type; + + bool attach(attachable* ptr) { // override + if (ptr == nullptr) { guard_type guard(m_mtx); return m_exit_reason.load() == exit_reason::not_exited; } - else - { + else { attachable_ptr uptr(ptr); std::uint32_t reason; - // lifetime scope of guard - { + { // lifetime scope of guard guard_type guard(m_mtx); reason = m_exit_reason.load(); - if (reason == exit_reason::not_exited) - { + if (reason == exit_reason::not_exited) { m_attachables.push_back(std::move(uptr)); return true; } @@ -114,18 +94,15 @@ class abstract_actor : public Base } } - void detach(const attachable::token& what) /*override*/ - { + void detach(const attachable::token& what) { // override attachable_ptr uptr; - // lifetime scope of guard - { + { // lifetime scope of guard guard_type guard(m_mtx); auto end = m_attachables.end(); auto i = std::find_if( m_attachables.begin(), end, [&](attachable_ptr& p) { return p->matches(what); }); - if (i != end) - { + if (i != end) { uptr = std::move(*i); m_attachables.erase(i); } @@ -133,24 +110,19 @@ class abstract_actor : public Base // uptr will be destroyed here, without locked mutex } - void link_to(intrusive_ptr& other) /*override*/ - { + void link_to(intrusive_ptr& other) { // override (void) link_to_impl(other); } - void unlink_from(intrusive_ptr& other) /*override*/ - { + void unlink_from(intrusive_ptr& other) { // override (void) unlink_from_impl(other); } - bool remove_backlink(intrusive_ptr& other) /*override*/ - { - if (other && other != this) - { + bool remove_backlink(intrusive_ptr& other) { // override + if (other && other != this) { guard_type guard(m_mtx); auto i = std::find(m_links.begin(), m_links.end(), other); - if (i != m_links.end()) - { + if (i != m_links.end()) { m_links.erase(i); return true; } @@ -158,27 +130,22 @@ class abstract_actor : public Base return false; } - bool establish_backlink(intrusive_ptr& other) /*override*/ - { + bool establish_backlink(intrusive_ptr& other) { // override std::uint32_t reason = exit_reason::not_exited; - if (other && other != this) - { + if (other && other != this) { guard_type guard(m_mtx); reason = m_exit_reason.load(); - if (reason == exit_reason::not_exited) - { + if (reason == exit_reason::not_exited) { auto i = std::find(m_links.begin(), m_links.end(), other); - if (i == m_links.end()) - { + if (i == m_links.end()) { m_links.push_back(other); return true; } } } // send exit message without lock - if (reason != exit_reason::not_exited) - { - other->enqueue(this, make_cow_tuple(atom(":Exit"), reason)); + if (reason != exit_reason::not_exited) { + other->enqueue(this, make_cow_tuple(atom("EXIT"), reason)); } return false; } @@ -186,29 +153,59 @@ class abstract_actor : public Base protected: mailbox_type m_mailbox; + util::fixed_vector m_nodes; + util::shared_spinlock m_nodes_lock; + + typedef std::lock_guard lock_type; + + inline mailbox_element* fetch_node(actor* sender, any_tuple msg) { + mailbox_element* result = nullptr; + { // lifetime scope of guard + lock_type guard{m_nodes_lock}; + if (m_nodes.not_empty()) { + result = m_nodes.back(); + m_nodes.pop_back(); + } + } + if (result) { + result->next = nullptr; + result->marked = false; + result->sender = sender; + result->msg = std::move(msg); + } + else { + result = new mailbox_element(sender, std::move(msg)); + } + return result; + } - template - inline queue_node* fetch_node(actor* sender, T&& msg) - { - return new queue_node(sender, std::forward(msg)); + inline void release_node(mailbox_element* node) { + { // lifetime scope of guard + lock_type guard{m_nodes_lock}; + if (m_nodes.full() == false) { + m_nodes.push_back(node); + return; + } + } + delete node; } template abstract_actor(Args&&... args) : Base(std::forward(args)...) - , m_exit_reason(exit_reason::not_exited) - { + , m_exit_reason(exit_reason::not_exited) { + // pre-allocate some nodes + for (size_t i = 0; i < m_nodes.max_size() / 2; ++i) { + m_nodes.push_back(new mailbox_element); + } } - void cleanup(std::uint32_t reason) - { + void cleanup(std::uint32_t reason) { if (reason == exit_reason::not_exited) return; decltype(m_links) mlinks; decltype(m_attachables) mattachables; - // lifetime scope of guard - { + { // lifetime scope of guard guard_type guard(m_mtx); - if (m_exit_reason != exit_reason::not_exited) - { + if (m_exit_reason != exit_reason::not_exited) { // already exited return; } @@ -220,31 +217,25 @@ class abstract_actor : public Base m_attachables.clear(); } // send exit messages - for (actor_ptr& aptr : mlinks) - { - aptr->enqueue(this, make_cow_tuple(atom(":Exit"), reason)); + for (actor_ptr& aptr : mlinks) { + aptr->enqueue(this, make_cow_tuple(atom("EXIT"), reason)); } - for (attachable_ptr& ptr : mattachables) - { + for (attachable_ptr& ptr : mattachables) { ptr->actor_exited(reason); } } - bool link_to_impl(intrusive_ptr& other) - { - if (other && other != this) - { + bool link_to_impl(intrusive_ptr& other) { + if (other && other != this) { guard_type guard(m_mtx); // send exit message if already exited - if (exited()) - { - other->enqueue(this, make_cow_tuple(atom(":Exit"), + if (exited()) { + other->enqueue(this, make_cow_tuple(atom("EXIT"), m_exit_reason.load())); } // add link if not already linked to other // (checked by establish_backlink) - else if (other->establish_backlink(this)) - { + else if (other->establish_backlink(this)) { m_links.push_back(other); return true; } @@ -252,12 +243,10 @@ class abstract_actor : public Base return false; } - bool unlink_from_impl(intrusive_ptr& other) - { + bool unlink_from_impl(intrusive_ptr& other) { guard_type guard(m_mtx); // remove_backlink returns true if this actor is linked to other - if (other && !exited() && other->remove_backlink(this)) - { + if (other && !exited() && other->remove_backlink(this)) { auto i = std::find(m_links.begin(), m_links.end(), other); CPPA_REQUIRE(i != m_links.end()); m_links.erase(i); @@ -269,15 +258,14 @@ class abstract_actor : public Base private: // @pre m_mtx.locked() - bool exited() const - { + bool exited() const { return m_exit_reason.load() != exit_reason::not_exited; } // true if the associated thread has finished execution std::atomic m_exit_reason; // guards access to m_exited, m_subscriptions and m_links - detail::mutex m_mtx; + std::mutex m_mtx; // links to other actors std::vector m_links; // code that is executed on cleanup @@ -285,6 +273,6 @@ class abstract_actor : public Base }; -} // namespace cppa +} } // namespace cppa::detail -#endif // ABSTRACT_ACTOR_HPP +#endif // CPPA_ABSTRACT_ACTOR_HPP diff --git a/cppa/detail/abstract_scheduled_actor.hpp b/cppa/detail/abstract_scheduled_actor.hpp index 5b463cdf72..a483e3b39e 100644 --- a/cppa/detail/abstract_scheduled_actor.hpp +++ b/cppa/detail/abstract_scheduled_actor.hpp @@ -28,79 +28,97 @@ \******************************************************************************/ -#ifndef SCHEDULED_ACTOR_HPP -#define SCHEDULED_ACTOR_HPP +#ifndef CPPA_SCHEDULED_ACTOR_HPP +#define CPPA_SCHEDULED_ACTOR_HPP +#include + +#include + +#include "cppa/any_tuple.hpp" #include "cppa/scheduler.hpp" #include "cppa/local_actor.hpp" -#include "cppa/abstract_actor.hpp" +#include "cppa/detail/abstract_actor.hpp" #include "cppa/scheduled_actor.hpp" #include "cppa/util/fiber.hpp" - -#include "cppa/intrusive/singly_linked_list.hpp" +#include "cppa/detail/filter_result.hpp" +#include "cppa/detail/recursive_queue_node.hpp" #include "cppa/intrusive/single_reader_queue.hpp" -namespace cppa { class scheduler; } namespace cppa { namespace detail { // A spawned, scheduled Actor. -class abstract_scheduled_actor : public abstract_actor -{ - - friend class intrusive::single_reader_queue; +class abstract_scheduled_actor : public abstract_actor { - abstract_scheduled_actor* next; // intrusive next pointer - - void enqueue_node(queue_node* node); + typedef abstract_actor super; protected: std::atomic m_state; - scheduler* m_scheduler; - - typedef abstract_actor super; - typedef super::queue_node_guard queue_node_guard; - typedef super::queue_node queue_node; - typedef super::queue_node_ptr queue_node_ptr; - - enum dq_result - { - dq_done, - dq_indeterminate, - dq_timeout_occured - }; - - enum filter_result - { - normal_exit_signal, - expired_timeout_message, - timeout_message, - ordinary_message - }; - - filter_result filter_msg(const any_tuple& msg); - - auto dq(queue_node& node, partial_function& rules) -> dq_result; - - bool has_pending_timeout() - { + + filter_result filter_msg(const any_tuple& msg) { + auto& arr = detail::static_types_array::arr; + if ( msg.size() == 2 + && msg.type_at(0) == arr[0] + && msg.type_at(1) == arr[1]) { + auto v0 = *reinterpret_cast(msg.at(0)); + auto v1 = *reinterpret_cast(msg.at(1)); + if (v0 == atom("EXIT")) { + if (this->m_trap_exit == false) { + if (v1 != exit_reason::normal) { + quit(v1); + } + return normal_exit_signal; + } + } + else if (v0 == atom("TIMEOUT")) { + return (v1 == m_active_timeout_id) ? timeout_message + : expired_timeout_message; + } + } + return ordinary_message; + } + + bool has_pending_timeout() { return m_has_pending_timeout_request; } - void request_timeout(const util::duration& d); + void request_timeout(const util::duration& d) { + if (d.valid()) { + if (d.is_zero()) { + // immediately enqueue timeout + enqueue(nullptr, make_any_tuple(atom("TIMEOUT"), + ++m_active_timeout_id)); + } + else { + get_scheduler()->delayed_send(this, d, atom("TIMEOUT"), + ++m_active_timeout_id); + m_has_pending_timeout_request = true; + } + } + } - void reset_timeout() - { - if (m_has_pending_timeout_request) - { + void reset_timeout() { + if (m_has_pending_timeout_request) { ++m_active_timeout_id; m_has_pending_timeout_request = false; } } - private: + inline void handle_timeout(behavior& bhvr) { + bhvr.handle_timeout(); + reset_timeout(); + } + + inline void push_timeout() { + ++m_active_timeout_id; + } + + inline void pop_timeout() { + --m_active_timeout_id; + } bool m_has_pending_timeout_request; std::uint32_t m_active_timeout_id; @@ -110,46 +128,73 @@ class abstract_scheduled_actor : public abstract_actor static constexpr int ready = 0x00; static constexpr int done = 0x01; static constexpr int blocked = 0x02; + static constexpr int pending = 0x03; static constexpr int about_to_block = 0x04; - abstract_scheduled_actor(int state = done); - - abstract_scheduled_actor(scheduler* sched); - - void quit(std::uint32_t reason); + abstract_scheduled_actor(int state = done) + : super(true), m_state(state) + , m_has_pending_timeout_request(false) + , m_active_timeout_id(0) { + } - void enqueue(actor* sender, any_tuple&& msg); + bool pending_enqueue(actor* sender, any_tuple msg) { + return enqueue_node(super::fetch_node(sender, std::move(msg)), pending); + } - void enqueue(actor* sender, const any_tuple& msg); + void quit(std::uint32_t reason = exit_reason::normal) { + this->cleanup(reason); + throw actor_exited(reason); + } - int compare_exchange_state(int expected, int new_value); + void enqueue(actor* sender, any_tuple msg) { + enqueue_node(super::fetch_node(sender, std::move(msg))); + } - struct resume_callback - { - virtual ~resume_callback(); - // called if an actor finished execution - virtual void exec_done() = 0; - }; + int compare_exchange_state(int expected, int new_value) { + int e = expected; + do { + if (m_state.compare_exchange_weak(e, new_value)) { + return new_value; + } + } + while (e == expected); + return e; + } - // from = calling worker - virtual void resume(util::fiber* from, resume_callback* callback) = 0; + private: -}; + bool enqueue_node(typename super::mailbox_element* node, + int next_state = ready) { + CPPA_REQUIRE(node->marked == false); + if (this->m_mailbox._push_back(node)) { + for (;;) { + int state = m_state.load(); + switch (state) { + case blocked: { + if (m_state.compare_exchange_weak(state, next_state)) { + CPPA_REQUIRE(this->m_scheduler != nullptr); + if (next_state == ready) { + this->m_scheduler->enqueue(this); + } + return true; + } + break; + } + case about_to_block: { + if (m_state.compare_exchange_weak(state, ready)) { + return false; + } + break; + } + default: return false; + } + } + } + return false; + } -struct scheduled_actor_dummy : abstract_scheduled_actor -{ - void resume(util::fiber*, resume_callback*); - void quit(std::uint32_t); - void dequeue(behavior&); - void dequeue(partial_function&); - void link_to(intrusive_ptr&); - void unlink_from(intrusive_ptr&); - bool establish_backlink(intrusive_ptr&); - bool remove_backlink(intrusive_ptr&); - void detach(const attachable::token&); - bool attach(attachable*); }; } } // namespace cppa::detail -#endif // SCHEDULED_ACTOR_HPP +#endif // CPPA_SCHEDULED_ACTOR_HPP diff --git a/cppa/detail/abstract_tuple.hpp b/cppa/detail/abstract_tuple.hpp index dbda7ad148..ad91ebe5ad 100644 --- a/cppa/detail/abstract_tuple.hpp +++ b/cppa/detail/abstract_tuple.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef ABSTRACT_TUPLE_HPP -#define ABSTRACT_TUPLE_HPP +#ifndef CPPA_ABSTRACT_TUPLE_HPP +#define CPPA_ABSTRACT_TUPLE_HPP #include #include @@ -44,14 +44,12 @@ namespace cppa { namespace detail { -enum tuple_impl_info -{ +enum tuple_impl_info { statically_typed, dynamically_typed }; -class abstract_tuple : public ref_counted -{ +class abstract_tuple : public ref_counted { tuple_impl_info m_impl_type; @@ -67,12 +65,12 @@ class abstract_tuple : public ref_counted // accessors virtual size_t size() const = 0; virtual abstract_tuple* copy() const = 0; - virtual void const* at(size_t pos) const = 0; - virtual uniform_type_info const* type_at(size_t pos) const = 0; + virtual const void* at(size_t pos) const = 0; + virtual const uniform_type_info* type_at(size_t pos) const = 0; // returns either tdata<...> object or nullptr (default) if tuple // is not a 'native' implementation - virtual void const* native_data() const; + virtual const void* native_data() const; // Identifies the type of the implementation. // A statically typed tuple implementation can use some optimizations, @@ -83,56 +81,49 @@ class abstract_tuple : public ref_counted // uniquely identifies this category (element types) of messages // override this member function only if impl_type() == statically_typed // (default returns &typeid(void)) - virtual std::type_info const* type_token() const; + virtual const std::type_info* type_token() const; bool equals(const abstract_tuple& other) const; typedef tuple_iterator const_iterator; - inline const_iterator begin() const { return {this}; } + inline const_iterator begin() const { return {this}; } inline const_iterator cbegin() const { return {this}; } - inline const_iterator end() const { return {this, size()}; } + inline const_iterator end() const { return {this, size()}; } inline const_iterator cend() const { return {this, size()}; } }; -struct full_eq_type -{ +struct full_eq_type { constexpr full_eq_type() { } template inline bool operator()(const tuple_iterator& lhs, - const tuple_iterator& rhs) const - { + const tuple_iterator& rhs) const { return lhs.type() == rhs.type() && lhs.type()->equals(lhs.value(), rhs.value()); } }; -struct types_only_eq_type -{ +struct types_only_eq_type { constexpr types_only_eq_type() { } template inline bool operator()(const tuple_iterator& lhs, - uniform_type_info const* rhs ) const - { + const uniform_type_info* rhs ) const { return lhs.type() == rhs; } template - inline bool operator()(uniform_type_info const* lhs, - const tuple_iterator& rhs) const - { + inline bool operator()(const uniform_type_info* lhs, + const tuple_iterator& rhs) const { return lhs == rhs.type(); } }; namespace { - constexpr full_eq_type full_eq; constexpr types_only_eq_type types_only_eq; - } // namespace } } // namespace cppa::detail -#endif // ABSTRACT_TUPLE_HPP +#endif // CPPA_ABSTRACT_TUPLE_HPP diff --git a/cppa/detail/actor_count.hpp b/cppa/detail/actor_count.hpp index 840ca4872b..418595b0cf 100644 --- a/cppa/detail/actor_count.hpp +++ b/cppa/detail/actor_count.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef ACTOR_COUNT_HPP -#define ACTOR_COUNT_HPP +#ifndef CPPA_ACTOR_COUNT_HPP +#define CPPA_ACTOR_COUNT_HPP #include @@ -45,4 +45,4 @@ void actor_count_wait_until(size_t expected); } } // namespace cppa::detail -#endif // ACTOR_COUNT_HPP +#endif // CPPA_ACTOR_COUNT_HPP diff --git a/cppa/detail/actor_proxy_cache.hpp b/cppa/detail/actor_proxy_cache.hpp index c34af11897..20e57784b8 100644 --- a/cppa/detail/actor_proxy_cache.hpp +++ b/cppa/detail/actor_proxy_cache.hpp @@ -28,63 +28,69 @@ \******************************************************************************/ -#ifndef ACTOR_PROXY_CACHE_HPP -#define ACTOR_PROXY_CACHE_HPP +#ifndef CPPA_ACTOR_PROXY_CACHE_HPP +#define CPPA_ACTOR_PROXY_CACHE_HPP +#include +#include #include +#include +#include #include #include "cppa/actor_proxy.hpp" #include "cppa/process_information.hpp" +#include "cppa/util/shared_spinlock.hpp" + namespace cppa { namespace detail { -class actor_proxy_cache -{ +class actor_proxy_cache { public: - typedef std::tuple // node id - key_tuple; - - typedef std::function new_proxy_callback; + actor_proxy_ptr get(actor_id aid, std::uint32_t process_id, + const process_information::node_id_type& node_id); + + // @returns true if pptr was successfully removed, false otherwise + bool erase(const actor_proxy_ptr& pptr); + + template + void erase_all(const process_information::node_id_type& nid, + std::uint32_t process_id, + Fun fun) { + key_tuple lb{nid, process_id, std::numeric_limits::min()}; + key_tuple ub{nid, process_id, std::numeric_limits::max()}; + { // lifetime scope of guard + std::lock_guard guard(m_lock); + auto e = m_entries.end(); + auto first = m_entries.lower_bound(lb); + if (first != e) { + auto last = m_entries.upper_bound(ub); + for (auto i = first; i != last; ++i) { + fun(i->second); + } + m_entries.erase(first, last); + } + } + } private: - std::map m_pinfos; - std::map m_proxies; - - new_proxy_callback m_new_cb; - - process_information_ptr get_pinfo(const key_tuple& key); - - public: - - // this callback is called if a new proxy instance is created - template - void set_new_proxy_callback(F&& cb) - { - m_new_cb = std::forward(cb); - } - - actor_proxy_ptr get(const key_tuple& key); + typedef std::tuple // (remote) actor id + key_tuple; - void add(actor_proxy_ptr& pptr); + struct key_tuple_less { + bool operator()(const key_tuple& lhs, const key_tuple& rhs) const; + }; - size_t size() const; + util::shared_spinlock m_lock; + std::map m_entries; - void erase(const actor_proxy_ptr& pptr); + actor_proxy_ptr get_impl(const key_tuple& key); - template - void for_each(F&& fun) - { - for (auto i = m_proxies.begin(); i != m_proxies.end(); ++i) - { - fun(i->second); - } - } }; @@ -93,4 +99,4 @@ actor_proxy_cache& get_actor_proxy_cache(); } } // namespace cppa::detail -#endif // ACTOR_PROXY_CACHE_HPP +#endif // CPPA_ACTOR_PROXY_CACHE_HPP diff --git a/cppa/detail/actor_registry.hpp b/cppa/detail/actor_registry.hpp index f01013352a..d6db032f9d 100644 --- a/cppa/detail/actor_registry.hpp +++ b/cppa/detail/actor_registry.hpp @@ -28,22 +28,23 @@ \******************************************************************************/ -#ifndef ACTOR_REGISTRY_HPP -#define ACTOR_REGISTRY_HPP +#ifndef CPPA_ACTOR_REGISTRY_HPP +#define CPPA_ACTOR_REGISTRY_HPP #include +#include +#include #include #include +#include #include "cppa/actor.hpp" #include "cppa/attachable.hpp" -#include "cppa/detail/thread.hpp" #include "cppa/util/shared_spinlock.hpp" namespace cppa { namespace detail { -class actor_registry -{ +class actor_registry { public: @@ -75,8 +76,8 @@ class actor_registry std::atomic m_running; std::atomic m_ids; - mutex m_running_mtx; - condition_variable m_running_cv; + std::mutex m_running_mtx; + std::condition_variable m_running_cv; mutable util::shared_spinlock m_instances_mtx; std::map m_instances; @@ -85,4 +86,4 @@ class actor_registry } } // namespace cppa::detail -#endif // ACTOR_REGISTRY_HPP +#endif // CPPA_ACTOR_REGISTRY_HPP diff --git a/cppa/detail/addressed_message.hpp b/cppa/detail/addressed_message.hpp index d2ad7165a6..cd0497248a 100644 --- a/cppa/detail/addressed_message.hpp +++ b/cppa/detail/addressed_message.hpp @@ -28,32 +28,24 @@ \******************************************************************************/ -#ifndef ADDRESSED_MESSAGE_HPP -#define ADDRESSED_MESSAGE_HPP +#ifndef CPPA_ADDRESSED_MESSAGE_HPP +#define CPPA_ADDRESSED_MESSAGE_HPP #include "cppa/actor.hpp" -#include "cppa/cow_tuple.hpp" #include "cppa/channel.hpp" #include "cppa/any_tuple.hpp" +#include "cppa/cow_tuple.hpp" +#include "cppa/any_tuple.hpp" #include "cppa/ref_counted.hpp" #include "cppa/intrusive_ptr.hpp" -#include "cppa/detail/channel.hpp" - namespace cppa { namespace detail { -class addressed_message -{ +class addressed_message { public: - addressed_message(const actor_ptr& from, - const channel_ptr& to, - const any_tuple& ut); - - addressed_message(const actor_ptr& from, - const channel_ptr& to, - any_tuple&& ut); + addressed_message(actor_ptr from, channel_ptr to, any_tuple ut); addressed_message() = default; addressed_message(addressed_message&&) = default; @@ -61,38 +53,31 @@ class addressed_message addressed_message& operator=(addressed_message&&) = default; addressed_message& operator=(const addressed_message&) = default; - inline actor_ptr& sender() - { + inline actor_ptr& sender() { return m_sender; } - inline const actor_ptr& sender() const - { + inline const actor_ptr& sender() const { return m_sender; } - inline channel_ptr& receiver() - { + inline channel_ptr& receiver() { return m_receiver; } - inline const channel_ptr& receiver() const - { + inline const channel_ptr& receiver() const { return m_receiver; } - inline any_tuple& content() - { + inline any_tuple& content() { return m_content; } - inline const any_tuple& content() const - { + inline const any_tuple& content() const { return m_content; } - inline bool empty() const - { + inline bool empty() const { return m_content.empty(); } @@ -106,11 +91,10 @@ class addressed_message bool operator==(const addressed_message& lhs, const addressed_message& rhs); -inline bool operator!=(const addressed_message& lhs, const addressed_message& rhs) -{ +inline bool operator!=(const addressed_message& lhs, const addressed_message& rhs) { return !(lhs == rhs); } } } // namespace cppa::detail -#endif // ADDRESSED_MESSAGE_HPP +#endif // CPPA_ADDRESSED_MESSAGE_HPP diff --git a/cppa/detail/atom_val.hpp b/cppa/detail/atom_val.hpp index f5218dcf66..980ea98ef0 100644 --- a/cppa/detail/atom_val.hpp +++ b/cppa/detail/atom_val.hpp @@ -28,14 +28,15 @@ \******************************************************************************/ -#ifndef ATOM_VAL_HPP -#define ATOM_VAL_HPP +#ifndef CPPA_ATOM_VAL_HPP +#define CPPA_ATOM_VAL_HPP -namespace cppa { namespace detail { namespace { +namespace cppa { namespace detail { + +namespace { // encodes ASCII characters to 6bit encoding -constexpr char encoding_table[] = -{ +constexpr char encoding_table[] = { /* ..0 ..1 ..2 ..3 ..4 ..5 ..6 ..7 ..8 ..9 ..A ..B ..C ..D ..E ..F */ /* 0.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -52,19 +53,19 @@ constexpr char decoding_table[] = " 0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" "abcdefghijklmnopqrstuvwxyz"; -constexpr std::uint64_t next_interim(std::uint64_t current, size_t char_code) -{ +} // namespace + +constexpr std::uint64_t next_interim(std::uint64_t current, size_t char_code) { return (current << 6) | encoding_table[(char_code <= 0x7F) ? char_code : 0]; } -constexpr std::uint64_t atom_val(char const* cstr, std::uint64_t interim = 0) -{ +constexpr std::uint64_t atom_val(const char* cstr, std::uint64_t interim = 0) { return (*cstr == '\0') ? interim : atom_val(cstr + 1, next_interim(interim, static_cast(*cstr))); } -} } } // namespace cppa::detail:: +} } // namespace cppa::detail -#endif // ATOM_VAL_HPP +#endif // CPPA_ATOM_VAL_HPP diff --git a/cppa/stacked_event_based_actor.hpp b/cppa/detail/behavior_stack.hpp similarity index 70% rename from cppa/stacked_event_based_actor.hpp rename to cppa/detail/behavior_stack.hpp index a6f252c528..112d222903 100644 --- a/cppa/stacked_event_based_actor.hpp +++ b/cppa/detail/behavior_stack.hpp @@ -28,39 +28,52 @@ \******************************************************************************/ -#ifndef STACKED_EVENT_BASED_ACTOR_HPP -#define STACKED_EVENT_BASED_ACTOR_HPP +#ifndef BEHAVIOR_STACK_HPP +#define BEHAVIOR_STACK_HPP -#include "cppa/event_based_actor_base.hpp" +#include +#include -namespace cppa { +#include "cppa/behavior.hpp" +#include "cppa/detail/disablable_delete.hpp" -/** - * @brief A base class for event-based actors using a behavior stack. - */ -class stacked_event_based_actor : public event_based_actor_base +namespace cppa { namespace detail { + +class behavior_stack { - friend class event_based_actor_base; + behavior_stack(const behavior_stack&) = delete; + behavior_stack& operator=(const behavior_stack&) = delete; + + public: + + behavior_stack() = default; + + typedef detail::disablable_delete deleter; + typedef std::unique_ptr value_type; + + inline bool empty() const { return m_elements.empty(); } + + inline behavior& back() { return *m_elements.back(); } + + // executes the behavior stack + void exec(); + + void pop_back(); - typedef abstract_event_based_actor::stack_element stack_element; + void push_back(behavior* what, bool has_ownership); - void do_become(behavior* behavior, bool has_ownership); + void cleanup(); - protected: + void clear(); - /** - * @brief Restores the last behavior. - */ - void unbecome(); + private: - /** - * @brief Terminates this actor with normal exit reason. - */ - void become_void(); + std::vector m_elements; + std::vector m_erased_elements; }; -} // namespace cppa +} } // namespace cppa::detail -#endif // STACKED_EVENT_BASED_ACTOR_HPP +#endif // BEHAVIOR_STACK_HPP diff --git a/cppa/detail/boxed.hpp b/cppa/detail/boxed.hpp index 0ed59145ef..1d06c77906 100644 --- a/cppa/detail/boxed.hpp +++ b/cppa/detail/boxed.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef BOXED_HPP -#define BOXED_HPP +#ifndef CPPA_BOXED_HPP +#define CPPA_BOXED_HPP #include "cppa/anything.hpp" #include "cppa/util/wrapped.hpp" @@ -37,53 +37,45 @@ namespace cppa { namespace detail { template -struct boxed -{ +struct boxed { typedef util::wrapped type; }; template -struct boxed< util::wrapped > -{ +struct boxed< util::wrapped > { typedef util::wrapped type; }; template<> -struct boxed -{ +struct boxed { typedef anything type; }; template -struct is_boxed -{ +struct is_boxed { static constexpr bool value = false; }; template -struct is_boxed< util::wrapped > -{ +struct is_boxed< util::wrapped > { static constexpr bool value = true; }; template -struct is_boxed()> -{ +struct is_boxed()> { static constexpr bool value = true; }; template -struct is_boxed(&)()> -{ +struct is_boxed(&)()> { static constexpr bool value = true; }; template -struct is_boxed(*)()> -{ +struct is_boxed(*)()> { static constexpr bool value = true; }; } } // namespace cppa::detail -#endif // BOXED_HPP +#endif // CPPA_BOXED_HPP diff --git a/cppa/detail/buffer.hpp b/cppa/detail/buffer.hpp index 74dc9ebf7c..746ea1b0c1 100644 --- a/cppa/detail/buffer.hpp +++ b/cppa/detail/buffer.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef BUFFER_HPP -#define BUFFER_HPP +#ifndef CPPA_BUFFER_HPP +#define CPPA_BUFFER_HPP #include // std::ios_base::failure #include @@ -41,8 +41,7 @@ namespace cppa { namespace detail { template -class buffer -{ +class buffer { DataType* m_data; size_t m_written; @@ -50,33 +49,25 @@ class buffer size_t m_final_size; template - bool append_impl(F&& fun, bool throw_on_error) - { + bool append_impl(F&& fun, bool throw_on_error) { auto recv_result = fun(); - if (recv_result == 0) - { + if (recv_result == 0) { // connection closed - if (throw_on_error) - { - std::ios_base::failure("cannot read from a closed pipe/socket"); + if (throw_on_error) { + throw std::ios_base::failure("cannot read from a closed pipe/socket"); } return false; } - else if (recv_result < 0) - { - switch (errno) - { - case EAGAIN: - { + else if (recv_result < 0) { + switch (errno) { + case EAGAIN: { // rdflags or sfd is set to non-blocking, // this is not treated as error return true; } - default: - { + default: { // a "real" error occured; - if (throw_on_error) - { + if (throw_on_error) { char* cstr = strerror(errno); std::string errmsg = cstr; free(cstr); @@ -92,45 +83,36 @@ class buffer public: - buffer() : m_data(nullptr), m_written(0), m_allocated(0), m_final_size(0) - { + buffer() : m_data(nullptr), m_written(0), m_allocated(0), m_final_size(0) { } buffer(buffer&& other) : m_data(other.m_data), m_written(other.m_written) - , m_allocated(other.m_allocated), m_final_size(other.m_final_size) - { + , m_allocated(other.m_allocated), m_final_size(other.m_final_size) { other.m_data = nullptr; other.m_written = other.m_allocated = other.m_final_size = 0; } - ~buffer() - { + ~buffer() { delete[] m_data; } - void clear() - { + void clear() { m_written = 0; } - void reset(size_t new_final_size = 0) - { + void reset(size_t new_final_size = 0) { m_written = 0; m_final_size = new_final_size; - if (new_final_size > m_allocated) - { - if (new_final_size > MaxBufferSize) - { + if (new_final_size > m_allocated) { + if (new_final_size > MaxBufferSize) { throw std::ios_base::failure("maximum buffer size exceeded"); } auto remainder = (new_final_size % ChunkSize); - if (remainder == 0) - { + if (remainder == 0) { m_allocated = new_final_size; } - else - { + else { m_allocated = (new_final_size - remainder) + ChunkSize; } delete[] m_data; @@ -138,59 +120,51 @@ class buffer } } - bool ready() - { + bool ready() { return m_written == m_final_size; } // pointer to the current write position - DataType* wr_ptr() - { + DataType* wr_ptr() { return m_data + m_written; } - size_t size() - { + size_t size() { return m_written; } - size_t final_size() - { + size_t final_size() { return m_final_size; } - size_t remaining() - { + size_t remaining() { return m_final_size - m_written; } - void inc_written(size_t value) - { + void inc_written(size_t value) { m_written += value; } - DataType* data() - { + DataType* data() { return m_data; } - bool append_from_file_descriptor(int fd, bool throw_on_error = false) - { - auto _this = this; - auto fun = [_this, fd]() -> int - { - return ::read(fd, _this->wr_ptr(), _this->remaining()); + inline bool full() { + return remaining() == 0; + } + + bool append_from_file_descriptor(int fd, bool throw_on_error = false) { + auto fun = [=]() -> int { + return ::read(fd, this->wr_ptr(), this->remaining()); }; return append_impl(fun, throw_on_error); } - bool append_from(native_socket_type sfd, int rdflags, - bool throw_on_error = false) - { - auto _this = this; - auto fun = [_this, sfd, rdflags]() -> int - { - return ::recv(sfd, _this->wr_ptr(), _this->remaining(), rdflags); + bool append_from(native_socket_type sfd, + int rdflags = 0, + bool throw_on_error = false) { + auto fun = [=]() -> int { + return ::recv(sfd, this->wr_ptr(), this->remaining(), rdflags); }; return append_impl(fun, throw_on_error); } @@ -199,4 +173,4 @@ class buffer } } // namespace cppa::detail -#endif // BUFFER_HPP +#endif // CPPA_BUFFER_HPP diff --git a/cppa/detail/channel.hpp b/cppa/detail/channel.hpp index 87e9628825..9f5bafa660 100644 --- a/cppa/detail/channel.hpp +++ b/cppa/detail/channel.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef CHANNEL_HPP -#define CHANNEL_HPP +#ifndef CPPA_CHANNEL_HPP +#define CPPA_CHANNEL_HPP #include "cppa/ref_counted.hpp" @@ -38,11 +38,10 @@ namespace cppa { class message; } namespace cppa { namespace detail { // public part of the actor interface -struct channel : ref_counted -{ - virtual void enqueue_msg(const message& msg) = 0; +struct channel : ref_counted { + virtual void enqueue_msg(const message& msg) = 0; }; } } // namespace cppa::detail -#endif // CHANNEL_HPP +#endif // CPPA_CHANNEL_HPP diff --git a/cppa/detail/container_tuple_view.hpp b/cppa/detail/container_tuple_view.hpp index 244bfe1216..b16a97f235 100644 --- a/cppa/detail/container_tuple_view.hpp +++ b/cppa/detail/container_tuple_view.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef CONTAINER_TUPLE_VIEW_HPP -#define CONTAINER_TUPLE_VIEW_HPP +#ifndef CPPA_CONTAINER_TUPLE_VIEW_HPP +#define CPPA_CONTAINER_TUPLE_VIEW_HPP #include @@ -41,8 +41,7 @@ namespace cppa { namespace detail { template -class container_tuple_view : public abstract_tuple -{ +class container_tuple_view : public abstract_tuple { typedef abstract_tuple super; @@ -51,40 +50,34 @@ class container_tuple_view : public abstract_tuple typedef typename Container::value_type value_type; container_tuple_view(Container* c, bool take_ownership = false) - : super(tuple_impl_info::dynamically_typed), m_ptr(c) - { + : super(tuple_impl_info::dynamically_typed), m_ptr(c) { CPPA_REQUIRE(c != nullptr); if (!take_ownership) m_ptr.get_deleter().disable(); } - size_t size() const - { + size_t size() const { return m_ptr->size(); } - abstract_tuple* copy() const - { + abstract_tuple* copy() const { return new container_tuple_view{new Container(*m_ptr), true}; } - void const* at(size_t pos) const - { + const void* at(size_t pos) const { CPPA_REQUIRE(pos < size()); auto i = m_ptr->begin(); std::advance(i, pos); return &(*i); } - void* mutable_at(size_t pos) - { + void* mutable_at(size_t pos) { CPPA_REQUIRE(pos < size()); auto i = m_ptr->begin(); std::advance(i, pos); return &(*i); } - uniform_type_info const* type_at(size_t) const - { + const uniform_type_info* type_at(size_t) const { return static_types_array::arr[0]; } @@ -96,4 +89,4 @@ class container_tuple_view : public abstract_tuple } } // namespace cppa::detail -#endif // CONTAINER_TUPLE_VIEW_HPP +#endif // CPPA_CONTAINER_TUPLE_VIEW_HPP diff --git a/cppa/detail/decorated_tuple.hpp b/cppa/detail/decorated_tuple.hpp index c39c259233..6349f917da 100644 --- a/cppa/detail/decorated_tuple.hpp +++ b/cppa/detail/decorated_tuple.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef DECORATED_TUPLE_HPP -#define DECORATED_TUPLE_HPP +#ifndef CPPA_DECORATED_TUPLE_HPP +#define CPPA_DECORATED_TUPLE_HPP #include #include @@ -50,8 +50,7 @@ namespace cppa { namespace detail { template -class decorated_tuple : public abstract_tuple -{ +class decorated_tuple : public abstract_tuple { typedef abstract_tuple super; @@ -65,47 +64,39 @@ class decorated_tuple : public abstract_tuple typedef cow_ptr cow_pointer_type; static inline cow_pointer_type create(cow_pointer_type d, - const vector_type& v) - { + const vector_type& v) { return cow_pointer_type{new decorated_tuple(std::move(d), v)}; } // creates a subtuple form @p d with an offset - static inline cow_pointer_type create(cow_pointer_type d, size_t offset) - { + static inline cow_pointer_type create(cow_pointer_type d, size_t offset) { return cow_pointer_type{new decorated_tuple(std::move(d), offset)}; } - virtual void* mutable_at(size_t pos) - { + virtual void* mutable_at(size_t pos) { CPPA_REQUIRE(pos < size()); return m_decorated->mutable_at(m_mapping[pos]); } - virtual size_t size() const - { + virtual size_t size() const { return sizeof...(ElementTypes); } - virtual decorated_tuple* copy() const - { + virtual decorated_tuple* copy() const { return new decorated_tuple(*this); } - virtual void const* at(size_t pos) const - { + virtual const void* at(size_t pos) const { CPPA_REQUIRE(pos < size()); return m_decorated->at(m_mapping[pos]); } - virtual uniform_type_info const* type_at(size_t pos) const - { + virtual const uniform_type_info* type_at(size_t pos) const { CPPA_REQUIRE(pos < size()); return m_decorated->type_at(m_mapping[pos]); } - std::type_info const* type_token() const - { + const std::type_info* type_token() const { return static_type_list::list; } @@ -116,8 +107,7 @@ class decorated_tuple : public abstract_tuple decorated_tuple(cow_pointer_type d, const vector_type& v) : super(tuple_impl_info::statically_typed) - , m_decorated(std::move(d)), m_mapping(v) - { + , m_decorated(std::move(d)), m_mapping(v) { # ifdef CPPA_DEBUG const cow_pointer_type& ptr = m_decorated; // prevent detaching # endif @@ -127,8 +117,7 @@ class decorated_tuple : public abstract_tuple } decorated_tuple(cow_pointer_type d, size_t offset) - : super(tuple_impl_info::statically_typed), m_decorated(std::move(d)) - { + : super(tuple_impl_info::statically_typed), m_decorated(std::move(d)) { # ifdef CPPA_DEBUG const cow_pointer_type& ptr = m_decorated; // prevent detaching # endif @@ -149,11 +138,10 @@ template struct decorated_cow_tuple_from_type_list; template -struct decorated_cow_tuple_from_type_list< util::type_list > -{ +struct decorated_cow_tuple_from_type_list< util::type_list > { typedef decorated_tuple type; }; } } // namespace cppa::detail -#endif // DECORATED_TUPLE_HPP +#endif // CPPA_DECORATED_TUPLE_HPP diff --git a/cppa/detail/default_uniform_type_info_impl.hpp b/cppa/detail/default_uniform_type_info_impl.hpp index 63661c52f6..ff05b5ca4a 100644 --- a/cppa/detail/default_uniform_type_info_impl.hpp +++ b/cppa/detail/default_uniform_type_info_impl.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP -#define DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP +#ifndef CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP +#define CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP #include "cppa/anything.hpp" @@ -48,18 +48,15 @@ namespace cppa { namespace detail { template -class is_stl_compliant_list -{ +class is_stl_compliant_list { template - static bool cmp_help_fun - ( + static bool cmp_help_fun ( // mutable pointer C* mc, // check if there's a 'void push_back()' that takes C::value_type decltype(mc->push_back(typename C::value_type()))* = nullptr - ) - { + ) { return true; } @@ -76,18 +73,15 @@ class is_stl_compliant_list }; template -class is_stl_compliant_map -{ +class is_stl_compliant_map { template - static bool cmp_help_fun - ( + static bool cmp_help_fun ( // mutable pointer C* mc, // check if there's an 'insert()' that takes C::value_type decltype(mc->insert(typename C::value_type()))* = nullptr - ) - { + ) { return true; } @@ -103,35 +97,31 @@ class is_stl_compliant_map }; template -class default_uniform_type_info_impl : public util::abstract_uniform_type_info -{ +class default_uniform_type_info_impl : public util::abstract_uniform_type_info { template - struct is_invalid - { + struct is_invalid { static constexpr bool value = !util::is_primitive::value && !is_stl_compliant_map::value && !is_stl_compliant_list::value; }; - class member - { + class member { uniform_type_info* m_meta; - std::function m_serialize; - std::function m_deserialize; member(const member&) = delete; member& operator=(const member&) = delete; - void swap(member& other) - { + void swap(member& other) { std::swap(m_meta, other.m_meta); std::swap(m_serialize, other.m_serialize); std::swap(m_deserialize, other.m_deserialize); @@ -141,25 +131,21 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info(s)) - , m_deserialize(std::forward(d)) - { + , m_deserialize(std::forward(d)) { } public: template - member(uniform_type_info* mtptr, R C::*mem_ptr) : m_meta(mtptr) - { - m_serialize = [mem_ptr] (uniform_type_info const* mt, - void const* obj, - serializer* s) - { - mt->serialize(&(*reinterpret_cast(obj).*mem_ptr), s); + member(uniform_type_info* mtptr, R C::*mem_ptr) : m_meta(mtptr) { + m_serialize = [mem_ptr] (const uniform_type_info* mt, + const void* obj, + serializer* s) { + mt->serialize(&(*reinterpret_cast(obj).*mem_ptr), s); }; - m_deserialize = [mem_ptr] (uniform_type_info const* mt, + m_deserialize = [mem_ptr] (const uniform_type_info* mt, void* obj, - deserializer* d) - { + deserializer* d) { mt->deserialize(&(*reinterpret_cast(obj).*mem_ptr), d); }; } @@ -167,69 +153,57 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info member(uniform_type_info* mtptr, GRes (C::*getter)() const, - SRes (C::*setter)(SArg)) : m_meta(mtptr) - { + SRes (C::*setter)(SArg)) : m_meta(mtptr) { typedef typename util::rm_ref::type getter_result; typedef typename util::rm_ref::type setter_arg; static_assert(std::is_same::value, "getter result doesn't match setter argument"); - m_serialize = [getter] (uniform_type_info const* mt, - void const* obj, - serializer* s) - { - GRes v = (*reinterpret_cast(obj).*getter)(); + m_serialize = [getter] (const uniform_type_info* mt, + const void* obj, + serializer* s) { + GRes v = (*reinterpret_cast(obj).*getter)(); mt->serialize(&v, s); }; - m_deserialize = [setter] (uniform_type_info const* mt, + m_deserialize = [setter] (const uniform_type_info* mt, void* obj, - deserializer* d) - { + deserializer* d) { setter_arg value; - mt->deserialize(&value, d); - (*reinterpret_cast(obj).*setter)(value); + mt->deserialize(&value, d); (*reinterpret_cast(obj).*setter)(value); }; } - member(member&& other) : m_meta(nullptr) - { + member(member&& other) : m_meta(nullptr) { swap(other); } // a member that's not a member at all, but "forwards" // the 'self' pointer to make use of *_member implementations - static member fake_member(uniform_type_info* mtptr) - { + static member fake_member(uniform_type_info* mtptr) { return { mtptr, - [] (uniform_type_info const* mt, void const* obj, serializer* s) - { + [] (const uniform_type_info* mt, const void* obj, serializer* s) { mt->serialize(obj, s); }, - [] (uniform_type_info const* mt, void* obj, deserializer* d) - { + [] (const uniform_type_info* mt, void* obj, deserializer* d) { mt->deserialize(obj, d); } }; } - ~member() - { + ~member() { delete m_meta; } - member& operator=(member&& other) - { + member& operator=(member&& other) { swap(other); return *this; } - inline void serialize(void const* parent, serializer* s) const - { + inline void serialize(const void* parent, serializer* s) const { m_serialize(m_meta, parent, s); } - inline void deserialize(void* parent, deserializer* d) const - { + inline void deserialize(void* parent, deserializer* d) const { m_deserialize(m_meta, parent, d); } @@ -244,8 +218,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info void push_back(std::pair*> pr, - Args&&... args) - { + Args&&... args) { m_members.push_back({ pr.second, pr.first }); push_back(std::forward(args)...); } @@ -254,8 +227,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info void push_back(const std::pair, util::abstract_uniform_type_info::type>*>& pr, - Args&&... args) - { + Args&&... args) { m_members.push_back({ pr.second, pr.first.first, pr.first.second }); push_back(std::forward(args)...); } @@ -265,8 +237,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info typename std::enable_if::type>::value>::type push_back(const std::pair& pr, - Args&&... args) - { + Args&&... args) { typedef typename util::rm_ref::type memtype; m_members.push_back({ new primitive_member(), pr.first, pr.second }); push_back(std::forward(args)...); @@ -274,58 +245,50 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info typename std::enable_if::value>::type - push_back(R C::*mem_ptr, Args&&... args) - { + push_back(R C::*mem_ptr, Args&&... args) { m_members.push_back({ new primitive_member(), mem_ptr }); push_back(std::forward(args)...); } template< typename R, class C,typename... Args> typename std::enable_if::value>::type - push_back(R C::*mem_ptr, Args&&... args) - { + push_back(R C::*mem_ptr, Args&&... args) { m_members.push_back({ new list_member(), mem_ptr }); push_back(std::forward(args)...); } template typename std::enable_if::value>::type - push_back(R C::*mem_ptr, Args&&... args) - { + push_back(R C::*mem_ptr, Args&&... args) { m_members.push_back({ new map_member(), mem_ptr }); push_back(std::forward(args)...); } template typename std::enable_if::value>::type - push_back(R C::*mem_ptr, Args&&... args) - { + push_back(R C::*, Args&&...) { static_assert(util::is_primitive::value, "T is neither a primitive type nor a " "stl-compliant list/map"); } template - void init_(typename std::enable_if::value>::type* = 0) - { + void init_(typename std::enable_if::value>::type* = 0) { m_members.push_back(member::fake_member(new primitive_member

())); } template - void init_(typename std::enable_if::value>::type* = 0) - { + void init_(typename std::enable_if::value>::type* = 0) { m_members.push_back(member::fake_member(new map_member)); } template - void init_(typename std::enable_if::value>::type* = 0) - { + void init_(typename std::enable_if::value>::type* = 0) { m_members.push_back(member::fake_member(new list_member)); } template - void init_(typename std::enable_if::value>::type* = 0) - { + void init_(typename std::enable_if::value>::type* = 0) { // T is neither primitive nor a STL compliant list/map, // so it has to be an announced type static_assert(util::is_primitive::value, @@ -336,40 +299,32 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info - default_uniform_type_info_impl(Args&&... args) - { + default_uniform_type_info_impl(Args&&... args) { push_back(std::forward(args)...); } - default_uniform_type_info_impl() - { + default_uniform_type_info_impl() { init_(); - if (m_members.size() != 1) - { + if (m_members.size() != 1) { throw std::logic_error("no fake member added"); } } - void serialize(void const* obj, serializer* s) const - { + void serialize(const void* obj, serializer* s) const { s->begin_object(this->name()); - for (auto& m : m_members) - { + for (auto& m : m_members) { m.serialize(obj, s); } s->end_object(); } - void deserialize(void* obj, deserializer* d) const - { + void deserialize(void* obj, deserializer* d) const { std::string cname = d->seek_object(); - if (cname != this->name()) - { + if (cname != this->name()) { throw std::logic_error("wrong type name found"); } d->begin_object(this->name()); - for (auto& m : m_members) - { + for (auto& m : m_members) { m.deserialize(obj, d); } d->end_object(); @@ -379,4 +334,4 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info namespace cppa { namespace detail { -std::string demangle(char const* typeid_name); +std::string demangle(const char* typeid_name); } } // namespace cppa::detail -#endif // DEMANGLE_HPP +#endif // CPPA_DEMANGLE_HPP diff --git a/cppa/detail/disablable_delete.hpp b/cppa/detail/disablable_delete.hpp index c21d0f6c6b..45550483be 100644 --- a/cppa/detail/disablable_delete.hpp +++ b/cppa/detail/disablable_delete.hpp @@ -28,14 +28,13 @@ \******************************************************************************/ -#ifndef DISABLABLE_DELETE_HPP -#define DISABLABLE_DELETE_HPP +#ifndef CPPA_DISABLABLE_DELETE_HPP +#define CPPA_DISABLABLE_DELETE_HPP namespace cppa { namespace detail { template -class disablable_delete -{ +class disablable_delete { bool m_enabled; @@ -45,8 +44,7 @@ class disablable_delete inline void disable() { m_enabled = false; } - inline void operator()(T* ptr) - { + inline void operator()(T* ptr) { if (m_enabled) delete ptr; } @@ -54,4 +52,4 @@ class disablable_delete } } // namespace cppa::detail -#endif // DISABLABLE_DELETE_HPP +#endif // CPPA_DISABLABLE_DELETE_HPP diff --git a/cppa/detail/empty_tuple.hpp b/cppa/detail/empty_tuple.hpp index d23578e9bd..f6ad195f03 100644 --- a/cppa/detail/empty_tuple.hpp +++ b/cppa/detail/empty_tuple.hpp @@ -28,15 +28,16 @@ \******************************************************************************/ -#ifndef EMPTY_TUPLE_HPP -#define EMPTY_TUPLE_HPP +#ifndef CPPA_EMPTY_TUPLE_HPP +#define CPPA_EMPTY_TUPLE_HPP #include "cppa/detail/abstract_tuple.hpp" namespace cppa { namespace detail { -struct empty_tuple : abstract_tuple -{ +class empty_tuple : public abstract_tuple { + + public: using abstract_tuple::const_iterator; @@ -44,13 +45,13 @@ struct empty_tuple : abstract_tuple size_t size() const; void* mutable_at(size_t); abstract_tuple* copy() const; - void const* at(size_t) const; + const void* at(size_t) const; bool equals(const abstract_tuple& other) const; - uniform_type_info const* type_at(size_t) const; - std::type_info const* type_token() const; + const uniform_type_info* type_at(size_t) const; + const std::type_info* type_token() const; }; } } // namespace cppa::detail -#endif // EMPTY_TUPLE_HPP +#endif // CPPA_EMPTY_TUPLE_HPP diff --git a/cppa/detail/event_based_actor_factory.hpp b/cppa/detail/event_based_actor_factory.hpp new file mode 100644 index 0000000000..602053314d --- /dev/null +++ b/cppa/detail/event_based_actor_factory.hpp @@ -0,0 +1,142 @@ +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + + +#ifndef CPPA_EVENT_BASED_ACTOR_FACTORY_HPP +#define CPPA_EVENT_BASED_ACTOR_FACTORY_HPP + +#include + +#include "cppa/scheduler.hpp" +#include "cppa/event_based_actor.hpp" + +#include "cppa/detail/tdata.hpp" +#include "cppa/util/type_list.hpp" + +namespace cppa { namespace detail { + +template +class event_based_actor_impl : public event_based_actor { + + public: + + template + event_based_actor_impl(InitFun fun, CleanupFun cfun, Args&&... args) + : m_init(std::move(fun)), m_on_exit(std::move(cfun)) + , m_members(std::forward(args)...) { } + + void init() { apply(m_init); } + + void on_exit() { + typedef typename util::get_arg_types::types arg_types; + std::integral_constant token; + on_exit_impl(m_on_exit, token); + } + + private: + + InitFun m_init; + CleanupFun m_on_exit; + tdata m_members; + + template + void apply(F& f, typename std::add_pointer::type... args) { + f(args...); + } + + template + void apply(F& f, Args... args) { + apply(f, args..., &get_ref(m_members)); + } + + typedef std::integral_constant zero_t; + + template + typename std::enable_if::value>::type + on_exit_impl(OnExit& fun, Token) { + fun(); + } + + template + typename std::enable_if::value == false>::type + on_exit_impl(OnExit& fun, Token) { + apply(fun); + } + +}; + +template +class event_based_actor_factory { + + public: + + typedef event_based_actor_impl impl; + + event_based_actor_factory(InitFun fun, CleanupFun cfun) + : m_init(std::move(fun)), m_on_exit(std::move(cfun)) { } + + template + actor_ptr spawn(Args&&... args) { + return get_scheduler()->spawn(new impl(m_init, m_on_exit, + std::forward(args)...)); + } + + private: + + InitFun m_init; + CleanupFun m_on_exit; + +}; + +// event-based actor factory from type list +template +struct ebaf_from_type_list; + +template +struct ebaf_from_type_list > { + typedef event_based_actor_factory type; +}; + +template +struct ebaf_from_functor { + typedef typename util::get_arg_types::types arg_types; + typedef typename util::get_arg_types::types arg_types2; + static_assert(util::tl_forall::value, + "First functor takes non-pointer arguments"); + static_assert( std::is_same::value + || std::is_same, arg_types2>::value, + "Second functor must provide either the same signature " + " as the first one or must take zero arguments"); + typedef typename util::tl_map::type mems; + typedef typename ebaf_from_type_list::type type; +}; + +} } // namespace cppa::detail + +#endif // CPPA_EVENT_BASED_ACTOR_FACTORY_HPP diff --git a/src/invokable.cpp b/cppa/detail/filter_result.hpp similarity index 87% rename from src/invokable.cpp rename to cppa/detail/filter_result.hpp index dda2b6960b..6d8c243fd4 100644 --- a/src/invokable.cpp +++ b/cppa/detail/filter_result.hpp @@ -28,20 +28,18 @@ \******************************************************************************/ -#include "cppa/detail/invokable.hpp" +#ifndef CPPA_FILTER_RESULT_HPP +#define CPPA_FILTER_RESULT_HPP namespace cppa { namespace detail { -invokable::~invokable() -{ -} - -bool invokable::invoke(any_tuple&) const { return false; } - -bool invokable::unsafe_invoke(any_tuple&) const { return false; } - -bool invokable::types_match(const any_tuple&) const { return false; } - -bool invokable::could_invoke(const any_tuple&) const { return false; } +enum filter_result { + normal_exit_signal, + expired_timeout_message, + timeout_message, + ordinary_message +}; } } // namespace cppa::detail + +#endif // CPPA_FILTER_RESULT_HPP diff --git a/cppa/detail/get_behavior.hpp b/cppa/detail/get_behavior.hpp index f60837044f..bc4cd06b09 100644 --- a/cppa/detail/get_behavior.hpp +++ b/cppa/detail/get_behavior.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef GET_BEHAVIOR_HPP -#define GET_BEHAVIOR_HPP +#ifndef CPPA_GET_BEHAVIOR_HPP +#define CPPA_GET_BEHAVIOR_HPP #include @@ -43,8 +43,7 @@ namespace cppa { namespace detail { // default: template -class ftor_behavior : public scheduled_actor -{ +class ftor_behavior : public scheduled_actor { F m_fun; @@ -57,8 +56,7 @@ class ftor_behavior : public scheduled_actor }; template -class ftor_behavior : public scheduled_actor -{ +class ftor_behavior : public scheduled_actor { static_assert(sizeof...(Args) > 0, "sizeof...(Args) == 0"); @@ -80,8 +78,7 @@ class ftor_behavior : public scheduled_actor }; template -class ftor_behavior : public scheduled_actor -{ +class ftor_behavior : public scheduled_actor { F m_fun; @@ -96,8 +93,7 @@ class ftor_behavior : public scheduled_actor }; template -class ftor_behavior : public scheduled_actor -{ +class ftor_behavior : public scheduled_actor { static_assert(sizeof...(Args) > 0, "sizeof...(Args) == 0"); @@ -112,13 +108,11 @@ class ftor_behavior : public scheduled_actor public: - ftor_behavior(const F& f, const Args&... args) : m_fun(f), m_args(args...) - { + ftor_behavior(const F& f, const Args&... args) : m_fun(f), m_args(args...) { } ftor_behavior(F&& f,const Args&... args) : m_fun(std::move(f)) - , m_args(args...) - { + , m_args(args...) { } virtual void act() { util::apply_tuple(m_fun, m_args); } @@ -126,8 +120,7 @@ class ftor_behavior : public scheduled_actor }; template -scheduled_actor* get_behavior(std::integral_constant, R (*fptr)()) -{ +scheduled_actor* get_behavior(std::integral_constant, R (*fptr)()) { static_assert(std::is_convertible::value == false, "Spawning a function returning an actor_behavior? " "Are you sure that you do not want to spawn the behavior " @@ -136,8 +129,7 @@ scheduled_actor* get_behavior(std::integral_constant, R (*fptr)()) } template -scheduled_actor* get_behavior(std::integral_constant, F&& ftor) -{ +scheduled_actor* get_behavior(std::integral_constant, F&& ftor) { static_assert(std::is_convertible::value == false, "Spawning a functor returning an actor_behavior? " "Are you sure that you do not want to spawn the behavior " @@ -150,8 +142,7 @@ template scheduled_actor* get_behavior(std::integral_constant, F fptr, const Arg0& arg0, - const Args&... args) -{ + const Args&... args) { static_assert(std::is_convertible::value == false, "Spawning a function returning an actor_behavior? " "Are you sure that you do not want to spawn the behavior " @@ -164,8 +155,7 @@ template scheduled_actor* get_behavior(std::integral_constant, F ftor, const Arg0& arg0, - const Args&... args) -{ + const Args&... args) { static_assert(std::is_convertible::value == false, "Spawning a functor returning an actor_behavior? " "Are you sure that you do not want to spawn the behavior " @@ -177,4 +167,4 @@ scheduled_actor* get_behavior(std::integral_constant, } } // namespace cppa::detail -#endif // GET_BEHAVIOR_HPP +#endif // CPPA_GET_BEHAVIOR_HPP diff --git a/cppa/detail/group_manager.hpp b/cppa/detail/group_manager.hpp index 2e619a1a23..1a98261fee 100644 --- a/cppa/detail/group_manager.hpp +++ b/cppa/detail/group_manager.hpp @@ -28,19 +28,19 @@ \******************************************************************************/ -#ifndef GROUP_MANAGER_HPP -#define GROUP_MANAGER_HPP +#ifndef CPPA_GROUP_MANAGER_HPP +#define CPPA_GROUP_MANAGER_HPP #include +#include +#include #include "cppa/group.hpp" -#include "cppa/detail/thread.hpp" #include "cppa/util/shared_spinlock.hpp" namespace cppa { namespace detail { -class group_manager -{ +class group_manager { public: @@ -58,10 +58,10 @@ class group_manager typedef std::map< std::string, std::unique_ptr > modules_map; modules_map m_mmap; - detail::mutex m_mmap_mtx; + std::mutex m_mmap_mtx; }; } } // namespace cppa::detail -#endif // GROUP_MANAGER_HPP +#endif // CPPA_GROUP_MANAGER_HPP diff --git a/cppa/detail/implicit_conversions.hpp b/cppa/detail/implicit_conversions.hpp index 460c1e89bc..658f7d150f 100644 --- a/cppa/detail/implicit_conversions.hpp +++ b/cppa/detail/implicit_conversions.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef IMPLICIT_CONVERSIONS_HPP -#define IMPLICIT_CONVERSIONS_HPP +#ifndef CPPA_IMPLICIT_CONVERSIONS_HPP +#define CPPA_IMPLICIT_CONVERSIONS_HPP #include #include @@ -46,42 +46,53 @@ namespace cppa { class local_actor; } namespace cppa { namespace detail { template -struct implicit_conversions -{ - typedef typename util::replace_type, - std::is_same, - util::is_array_of, - util::is_array_of >::type +struct implicit_conversions { + + typedef typename util::replace_type< + T, + std::string, + std::is_same, + std::is_same, + util::is_array_of, + util::is_array_of + >::type subtype1; - typedef typename util::replace_type, - std::is_same, - util::is_array_of>::type + typedef typename util::replace_type< + subtype1, + std::u16string, + std::is_same, + std::is_same, + util::is_array_of + >::type subtype2; - typedef typename util::replace_type, - std::is_same, - util::is_array_of>::type + typedef typename util::replace_type< + subtype2, + std::u32string, + std::is_same, + std::is_same, + util::is_array_of + >::type subtype3; - typedef typename util::replace_type, - std::is_convertible, - std::is_same>::type + typedef typename util::replace_type< + subtype3, + actor_ptr, + std::is_convertible, + std::is_convertible, + std::is_same + >::type type; }; template -struct strip_and_convert -{ +struct strip_and_convert { typedef typename implicit_conversions::type>::type type; }; } } // namespace cppa::detail -#endif // IMPLICIT_CONVERSIONS_HPP +#endif // CPPA_IMPLICIT_CONVERSIONS_HPP diff --git a/cppa/detail/invokable.hpp b/cppa/detail/invokable.hpp deleted file mode 100644 index 2a8ad885e9..0000000000 --- a/cppa/detail/invokable.hpp +++ /dev/null @@ -1,322 +0,0 @@ -/******************************************************************************\ - * ___ __ * - * /\_ \ __/\ \ * - * \//\ \ /\_\ \ \____ ___ _____ _____ __ * - * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * - * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * - * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * - * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * - * \ \_\ \ \_\ * - * \/_/ \/_/ * - * * - * Copyright (C) 2011, 2012 * - * Dominik Charousset * - * * - * This file is part of libcppa. * - * libcppa is free software: you can redistribute it and/or modify it under * - * the terms of the GNU Lesser General Public License as published by the * - * Free Software Foundation, either version 3 of the License * - * or (at your option) any later version. * - * * - * libcppa is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with libcppa. If not, see . * -\******************************************************************************/ - - -#ifndef INVOKABLE_HPP -#define INVOKABLE_HPP - -#include -#include -#include -#include - -#include "cppa/pattern.hpp" -#include "cppa/any_tuple.hpp" -#include "cppa/tuple_cast.hpp" -#include "cppa/util/duration.hpp" -#include "cppa/util/apply_tuple.hpp" -#include "cppa/util/fixed_vector.hpp" -#include "cppa/util/callable_trait.hpp" - -#include "cppa/detail/matches.hpp" - -namespace cppa { namespace detail { - -class invokable -{ - - invokable(const invokable&) = delete; - invokable& operator=(const invokable&) = delete; - - public: - - invokable* next; - - inline invokable() : next(nullptr) { } - virtual ~invokable(); - - // Checks whether the types of @p value match the pattern. - virtual bool types_match(const any_tuple& value) const; - // Checks whether this invokable could be invoked with @p value. - virtual bool could_invoke(const any_tuple& value) const; - - // Type checking. - virtual bool invoke(any_tuple& value) const; - // Suppress type checking. - virtual bool unsafe_invoke(any_tuple& value) const; - -}; - -enum mapping_policy -{ - do_not_map, - map_to_bool, - map_to_option -}; - -template // do_not_map -struct pattern_policy -{ - Pattern m_pattern; - template - pattern_policy(Args&&... args) : m_pattern(std::forward(args)...) { } - bool types_match(const any_tuple& value) const - { - return matches_types(value, m_pattern); - } - bool could_invoke(const any_tuple& value) const - { - return matches(value, m_pattern); - } - template - bool call(const Fun& fun, any_tuple& value) const - { - fun(value); - return true; - } - template - bool call_unsafe(const Fun& fun, any_tuple& value) const - { - fun(value); - return true; - } -}; - -template -struct pattern_policy -{ - Pattern m_pattern; - template - pattern_policy(Args&&... args) : m_pattern(std::forward(args)...) { } - bool types_match(const any_tuple& value) const - { - return matches_types(value, m_pattern); - } - bool could_invoke(const any_tuple& value) const - { - return matches(value, m_pattern); - } - template - bool call(const Fun& fun, any_tuple& value) const - { - auto result = moving_tuple_cast(value, m_pattern); - if (result) - { - util::apply_tuple(fun, *result); - return true; - } - return false; - } - template - bool call_unsafe(const Fun& fun, any_tuple& value) const - { - auto result = unsafe_tuple_cast(value, m_pattern); - if (result) - { - util::apply_tuple(fun, *result); - return true; - } - return false; - } -}; - -template -struct pattern_policy -{ - Pattern m_pattern; - template - pattern_policy(Args&&... args) : m_pattern(std::forward(args)...) { } - bool types_match(const any_tuple& value) const - { - return matches_types(value, m_pattern); - } - bool could_invoke(const any_tuple& value) const - { - return matches(value, m_pattern); - } - template - bool call(const Fun& fun, any_tuple& value) const - { - if (could_invoke(value)) - { - fun(); - return true; - } - return false; - } - template - bool call_unsafe(const Fun& fun, any_tuple& value) const - { - if (could_invoke(value)) - { - fun(); - return true; - } - return false; - } -}; - -struct dummy_policy -{ - inline bool types_match(const any_tuple&) const - { - return true; - } - inline bool could_invoke(const any_tuple&) const - { - return true; - } - template - inline bool call(const Fun& fun, any_tuple&) const - { - fun(); - return true; - } - template - inline bool call_unsafe(const Fun& fun, any_tuple&) const - { - fun(); - return true; - } -}; - -template -struct invokable_impl : public invokable -{ - - Fun m_fun; - Policy m_policy; - - template - invokable_impl(Arg0&& arg0, Args&&... args) - : m_fun(std::forward(arg0)) - , m_policy(std::forward(args)...) - { - } - - bool invoke(any_tuple& value) const - { - return m_policy.call(m_fun, value); - } - - bool unsafe_invoke(any_tuple& value) const - { - return m_policy.call_unsafe(m_fun, value); - } - - bool types_match(const any_tuple& value) const - { - return m_policy.types_match(value); - } - - bool could_invoke(const any_tuple& value) const - { - return m_policy.could_invoke(value); - } - -}; - -template -constexpr mapping_policy get_mapping_policy() -{ - return (ArgTypes::size == 0) - ? map_to_bool - : (( std::is_same::value - && ArgTypes::size == 1) - ? do_not_map - : map_to_option); -} - -template -struct filtered; - -template -struct filtered > -{ - typedef typename util::tl_filter_not, is_anything>::type - types; -}; - -template -struct filtered > -{ - typedef typename filtered>::types types; -}; - - -template -struct select_invokable_impl -{ - typedef typename util::get_arg_types::types qualified_arg_types; - typedef typename util::tl_map::type - arg_types; - static constexpr mapping_policy mp = get_mapping_policy(); - typedef invokable_impl > type; -}; - -template -struct select_invokable_impl > -{ - typedef typename util::get_arg_types::types qualified_arg_types; - typedef typename util::tl_map::type - arg_types; - typedef typename util::rm_ref::type arg0; - static_assert(arg_types::size < 2, "functor has too many arguments"); - static_assert( arg_types::size == 0 - || std::is_same::value, - "bad signature"); - typedef invokable_impl type; -}; - -template -std::unique_ptr get_invokable_impl(Fun&& fun, - std::unique_ptr&& vm) -{ - typedef std::unique_ptr result; - if (vm) - { - typedef typename select_invokable_impl::type impl1; - return result{new impl1{std::forward(fun), std::move(vm)}}; - } - typedef typename Pattern::types pattern_types; - typedef typename select_invokable_impl::type impl2; - return result{new impl2{std::forward(fun)}}; -} - -template -std::unique_ptr get_invokable_impl(Fun&& fun) -{ - typedef typename Pattern::types pattern_types; - typedef typename select_invokable_impl::type impl; - return std::unique_ptr{new impl(std::forward(fun))}; -} - -} } // namespace cppa::detail - -#endif // INVOKABLE_HPP diff --git a/cppa/detail/list_member.hpp b/cppa/detail/list_member.hpp index f9a3ebfdf3..f385af2609 100644 --- a/cppa/detail/list_member.hpp +++ b/cppa/detail/list_member.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef LIST_MEMBER_HPP -#define LIST_MEMBER_HPP +#ifndef CPPA_LIST_MEMBER_HPP +#define CPPA_LIST_MEMBER_HPP #include "cppa/util/is_primitive.hpp" #include "cppa/util/abstract_uniform_type_info.hpp" @@ -37,25 +37,20 @@ namespace cppa { namespace detail { template -struct list_member_util -{ +struct list_member_util { typedef typename List::value_type value_type; static constexpr primitive_type vptype = type_to_ptype::ptype; - void operator()(const List& list, serializer* s) const - { + void operator()(const List& list, serializer* s) const { s->begin_sequence(list.size()); - for (auto i = list.begin(); i != list.end(); ++i) - { + for (auto i = list.begin(); i != list.end(); ++i) { s->write_value(*i); } s->end_sequence(); } - void operator()(List& list, deserializer* d) const - { + void operator()(List& list, deserializer* d) const { list.clear(); auto size = d->begin_sequence(); - for (decltype(size) i = 0; i < size; ++i) - { + for (decltype(size) i = 0; i < size; ++i) { list.push_back(get(d->read_value(vptype))); } d->end_sequence(); @@ -63,33 +58,27 @@ struct list_member_util }; template -struct list_member_util -{ +struct list_member_util { typedef typename List::value_type value_type; - uniform_type_info const* m_value_type; + const uniform_type_info* m_value_type; - list_member_util() : m_value_type(uniform_typeid()) - { + list_member_util() : m_value_type(uniform_typeid()) { } - void operator()(const List& list, serializer* s) const - { + void operator()(const List& list, serializer* s) const { s->begin_sequence(list.size()); - for (auto i = list.begin(); i != list.end(); ++i) - { + for (auto i = list.begin(); i != list.end(); ++i) { m_value_type->serialize(&(*i), s); } s->end_sequence(); } - void operator()(List& list, deserializer* d) const - { + void operator()(List& list, deserializer* d) const { list.clear(); value_type tmp; auto size = d->begin_sequence(); - for (decltype(size) i = 0; i < size; ++i) - { + for (decltype(size) i = 0; i < size; ++i) { m_value_type->deserialize(&tmp, d); list.push_back(tmp); } @@ -98,22 +87,19 @@ struct list_member_util }; template -class list_member : public util::abstract_uniform_type_info -{ +class list_member : public util::abstract_uniform_type_info { typedef typename List::value_type value_type; list_member_util::value> m_helper; public: - void serialize(void const* obj, serializer* s) const - { - auto& list = *reinterpret_cast(obj); + void serialize(const void* obj, serializer* s) const { + auto& list = *reinterpret_cast(obj); m_helper(list, s); } - void deserialize(void* obj, deserializer* d) const - { + void deserialize(void* obj, deserializer* d) const { auto& list = *reinterpret_cast(obj); m_helper(list, d); } @@ -122,4 +108,4 @@ class list_member : public util::abstract_uniform_type_info } } // namespace cppa::detail -#endif // LIST_MEMBER_HPP +#endif // CPPA_LIST_MEMBER_HPP diff --git a/cppa/detail/mailman.hpp b/cppa/detail/mailman.hpp index 3dea481744..3cbb0abeee 100644 --- a/cppa/detail/mailman.hpp +++ b/cppa/detail/mailman.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef MAILMAN_HPP -#define MAILMAN_HPP +#ifndef CPPA_MAILMAN_HPP +#define CPPA_MAILMAN_HPP #include "cppa/any_tuple.hpp" #include "cppa/actor_proxy.hpp" @@ -40,108 +40,8 @@ namespace cppa { namespace detail { -struct mailman_send_job -{ - process_information_ptr target_peer; - addressed_message msg; - inline mailman_send_job(process_information_ptr piptr, - const actor_ptr& from, - const channel_ptr& to, - const any_tuple& content) - : target_peer(piptr), msg(from, to, content) - { - } -}; - -struct mailman_add_peer -{ - native_socket_type sockfd; - process_information_ptr pinfo; - inline mailman_add_peer(native_socket_type fd, - const process_information_ptr& piptr) - : sockfd(fd), pinfo(piptr) - { - } -}; - -class mailman_job -{ - - friend class intrusive::singly_linked_list; - friend class intrusive::single_reader_queue; - - public: - - enum job_type - { - invalid_type, - send_job_type, - add_peer_type, - kill_type - }; - - inline mailman_job() : next(nullptr), m_type(invalid_type) { } - - mailman_job(process_information_ptr piptr, - const actor_ptr& from, - const channel_ptr& to, - const any_tuple& omsg); - - mailman_job(native_socket_type sockfd, const process_information_ptr& pinfo); - - static mailman_job* kill_job(); - - ~mailman_job(); - - inline mailman_send_job& send_job() - { - return m_send_job; - } - - inline mailman_add_peer& add_peer_job() - { - return m_add_socket; - } - - inline job_type type() const - { - return m_type; - } - - inline bool is_send_job() const - { - return m_type == send_job_type; - } - - inline bool is_add_peer_job() const - { - return m_type == add_peer_type; - } - - inline bool is_kill_job() const - { - return m_type == kill_type; - } - - private: - - mailman_job* next; - job_type m_type; - // unrestricted union - union - { - mailman_send_job m_send_job; - mailman_add_peer m_add_socket; - }; - - inline mailman_job(job_type jt) : next(nullptr), m_type(jt) { } - -}; - void mailman_loop(); -intrusive::single_reader_queue& mailman_queue(); - }} // namespace cppa::detail -#endif // MAILMAN_HPP +#endif // CPPA_MAILMAN_HPP diff --git a/cppa/detail/map_member.hpp b/cppa/detail/map_member.hpp index c7a8d4a2f1..5e621b5985 100644 --- a/cppa/detail/map_member.hpp +++ b/cppa/detail/map_member.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef MAP_MEMBER_HPP -#define MAP_MEMBER_HPP +#ifndef CPPA_MAP_MEMBER_HPP +#define CPPA_MAP_MEMBER_HPP #include #include "cppa/detail/pair_member.hpp" @@ -49,18 +49,15 @@ struct map_member_util; // std::set with primitive value template -struct map_member_util -{ +struct map_member_util { primitive_member impl; - void serialize_value(const T& what, serializer* s) const - { + void serialize_value(const T& what, serializer* s) const { impl.serialize(&what, s); } template - void deserialize_and_insert(M& map, deserializer* d) const - { + void deserialize_and_insert(M& map, deserializer* d) const { T value; impl.deserialize(&value, d); map.insert(std::move(value)); @@ -69,22 +66,18 @@ struct map_member_util // std::set with non-primitive value template -struct map_member_util -{ - uniform_type_info const* m_type; +struct map_member_util { + const uniform_type_info* m_type; - map_member_util() : m_type(uniform_typeid()) - { + map_member_util() : m_type(uniform_typeid()) { } - void serialize_value(const T& what, serializer* s) const - { + void serialize_value(const T& what, serializer* s) const { m_type->serialize(&what, s); } template - void deserialize_and_insert(M& map, deserializer* d) const - { + void deserialize_and_insert(M& map, deserializer* d) const { T value; m_type->deserialize(&value, d); map.insert(std::move(value)); @@ -93,8 +86,7 @@ struct map_member_util // std::map template -struct map_member_util -{ +struct map_member_util { // std::map defines its first half of value_type as const typedef typename std::remove_const::type first_type; @@ -103,16 +95,14 @@ struct map_member_util pair_member impl; - void serialize_value(const T& what, serializer* s) const - { + void serialize_value(const T& what, serializer* s) const { // impl needs a pair without const modifier std::pair p(what.first, what.second); impl.serialize(&p, s); } template - void deserialize_and_insert(M& map, deserializer* d) const - { + void deserialize_and_insert(M& map, deserializer* d) const { std::pair p; impl.deserialize(&p, d); std::pair v(std::move(p.first), @@ -123,8 +113,7 @@ struct map_member_util }; template -class map_member : public util::abstract_uniform_type_info -{ +class map_member : public util::abstract_uniform_type_info { typedef typename Map::key_type key_type; typedef typename Map::value_type value_type; @@ -135,24 +124,20 @@ class map_member : public util::abstract_uniform_type_info public: - void serialize(void const* obj, serializer* s) const - { - auto& mp = *reinterpret_cast(obj); + void serialize(const void* obj, serializer* s) const { + auto& mp = *reinterpret_cast(obj); s->begin_sequence(mp.size()); - for (const auto& val : mp) - { + for (const auto& val : mp) { m_helper.serialize_value(val, s); } s->end_sequence(); } - void deserialize(void* obj, deserializer* d) const - { + void deserialize(void* obj, deserializer* d) const { auto& mp = *reinterpret_cast(obj); mp.clear(); size_t mp_size = d->begin_sequence(); - for (size_t i = 0; i < mp_size; ++i) - { + for (size_t i = 0; i < mp_size; ++i) { m_helper.deserialize_and_insert(mp, d); } d->end_sequence(); @@ -162,4 +147,4 @@ class map_member : public util::abstract_uniform_type_info } } // namespace cppa::detail -#endif // MAP_MEMBER_HPP +#endif // CPPA_MAP_MEMBER_HPP diff --git a/cppa/detail/matches.hpp b/cppa/detail/matches.hpp index d286a040eb..805371aaf5 100644 --- a/cppa/detail/matches.hpp +++ b/cppa/detail/matches.hpp @@ -28,9 +28,10 @@ \******************************************************************************/ -#ifndef MATCHES_HPP -#define MATCHES_HPP +#ifndef CPPA_MATCHES_HPP +#define CPPA_MATCHES_HPP +#include #include "cppa/pattern.hpp" #include "cppa/any_tuple.hpp" @@ -42,19 +43,15 @@ template struct matcher; template -struct matcher -{ - static inline bool tmatch(const Tuple& tup) - { - if (tup.impl_type() == tuple_impl_info::statically_typed) - { +struct matcher { + static inline bool tmatch(const Tuple& tup) { + if (tup.impl_type() == tuple_impl_info::statically_typed) { // statically typed tuples return &typeid(type_list) // as type token return typeid(util::type_list) == *(tup.type_token()); } // always use a full dynamic match for dynamic typed tuples - else if (tup.size() == sizeof...(T)) - { + else if (tup.size() == sizeof...(T)) { auto& tarr = static_types_array::arr; return std::equal(tup.begin(), tup.end(), tarr.begin(), types_only_eq); @@ -63,10 +60,8 @@ struct matcher } static inline bool tmatch(const Tuple& tup, - util::fixed_vector& mv) - { - if (tmatch(tup)) - { + util::fixed_vector& mv) { + if (tmatch(tup)) { mv.resize(sizeof...(T)); std::iota(mv.begin(), mv.end(), 0); return true; @@ -74,22 +69,18 @@ struct matcher return false; } - static inline bool vmatch(const Tuple& tup, const pattern& ptrn) - { + static inline bool vmatch(const Tuple& tup, const pattern& ptrn) { CPPA_REQUIRE(tup.size() == sizeof...(T)); return ptrn._matches_values(tup); } }; template -struct matcher -{ +struct matcher { static constexpr size_t size = sizeof...(T) - 1; - static inline bool tmatch(const Tuple& tup) - { - if (tup.size() >= size) - { + static inline bool tmatch(const Tuple& tup) { + if (tup.size() >= size) { auto& tarr = static_types_array::arr; auto begin = tup.begin(); return std::equal(begin, begin + size, tarr.begin(), @@ -99,10 +90,8 @@ struct matcher } static inline bool tmatch(const Tuple& tup, - util::fixed_vector& mv) - { - if (tmatch(tup)) - { + util::fixed_vector& mv) { + if (tmatch(tup)) { mv.resize(size); std::iota(mv.begin(), mv.end(), 0); return true; @@ -110,54 +99,43 @@ struct matcher return false; } - static inline bool vmatch(const Tuple& tup, const pattern& ptrn) - { + static inline bool vmatch(const Tuple& tup, const pattern& ptrn) { return ptrn._matches_values(tup); } }; template -struct matcher -{ - static inline bool tmatch(const Tuple&) - { +struct matcher { + static inline bool tmatch(const Tuple&) { return true; } - static inline bool tmatch(const Tuple&, util::fixed_vector&) - { + static inline bool tmatch(const Tuple&, util::fixed_vector&) { return true; } - static inline bool vmatch(const Tuple&, const pattern&) - { + static inline bool vmatch(const Tuple&, const pattern&) { return true; } }; template -struct matcher -{ +struct matcher { static constexpr size_t size = sizeof...(T) - 1; - static inline bool tmatch(const Tuple& tup) - { + static inline bool tmatch(const Tuple& tup) { auto tup_size = tup.size(); - if (tup_size >= size) - { + if (tup_size >= size) { auto& tarr = static_types_array::arr; auto begin = tup.begin(); begin += (tup_size - size); - return std::equal(begin, tup.end(), - (tarr.begin() + 1), // skip 'anything' + return std::equal(begin, tup.end(), (tarr.begin() + 1), // skip 'anything' types_only_eq); } return false; } static inline bool tmatch(const Tuple& tup, - util::fixed_vector& mv) - { - if (tmatch(tup)) - { + util::fixed_vector& mv) { + if (tmatch(tup)) { mv.resize(size); std::iota(mv.begin(), mv.end(), tup.size() - size); return true; @@ -165,15 +143,13 @@ struct matcher return false; } - static inline bool vmatch(const Tuple& tup, const pattern& ptrn) - { + static inline bool vmatch(const Tuple& tup, const pattern& ptrn) { return ptrn._matches_values(tup); } }; template -struct matcher -{ +struct matcher { static constexpr int signed_wc_pos = util::tl_find, anything>::value; static constexpr size_t size = sizeof...(T); @@ -184,17 +160,14 @@ struct matcher && signed_wc_pos != (sizeof...(T) - 1), "illegal wildcard position"); - static inline bool tmatch(const Tuple& tup) - { + static inline bool tmatch(const Tuple& tup) { auto tup_size = tup.size(); - if (tup_size >= size) - { + if (tup_size >= size) { auto& tarr = static_types_array::arr; // first range [0, X1) auto begin = tup.begin(); auto end = begin + wc_pos; - if (std::equal(begin, end, tarr.begin(), types_only_eq)) - { + if (std::equal(begin, end, tarr.begin(), types_only_eq)) { // second range [X2, N) begin = end = tup.end(); begin -= (size - (wc_pos + 1)); @@ -206,10 +179,8 @@ struct matcher } static inline bool tmatch(const Tuple& tup, - util::fixed_vector& mv) - { - if (tmatch(tup)) - { + util::fixed_vector& mv) { + if (tmatch(tup)) { // first range mv.resize(size - 1); auto begin = mv.begin(); @@ -222,15 +193,13 @@ struct matcher return false; } - static inline bool vmatch(const Tuple& tup, const pattern& ptrn) - { + static inline bool vmatch(const Tuple& tup, const pattern& ptrn) { return ptrn._matches_values(tup); } }; template -struct matcher -{ +struct matcher { static constexpr size_t wc_count = util::tl_count, is_anything>::value; @@ -240,17 +209,13 @@ struct matcher class Push, class Commit, class Rollback> static bool match(TupleIter tbegin, TupleIter tend, PatternIter pbegin, PatternIter pend, - Push& push, Commit& commit, Rollback& rollback) - { - while (!(pbegin == pend && tbegin == tend)) - { - if (pbegin == pend) - { + Push& push, Commit& commit, Rollback& rollback) { + while (!(pbegin == pend && tbegin == tend)) { + if (pbegin == pend) { // reached end of pattern while some values remain unmatched return false; } - else if (*pbegin == nullptr) // nullptr == wildcard (anything) - { + else if (*pbegin == nullptr) { // nullptr == wildcard (anything) // perform submatching ++pbegin; // always true at the end of the pattern @@ -258,11 +223,9 @@ struct matcher // safe current mapping as fallback commit(); // iterate over tuple values until we found a match - for (; tbegin != tend; ++tbegin) - { + for (; tbegin != tend; ++tbegin) { if (match(tbegin, tend, pbegin, pend, - push, commit, rollback)) - { + push, commit, rollback)) { return true; } // restore mapping to fallback (delete invalid mappings) @@ -281,11 +244,9 @@ struct matcher return true; // pbegin == pend && tbegin == tend } - static inline bool tmatch(const Tuple& tup) - { + static inline bool tmatch(const Tuple& tup) { auto& tarr = static_types_array::arr; - if (tup.size() >= (sizeof...(T) - wc_count)) - { + if (tup.size() >= (sizeof...(T) - wc_count)) { auto fpush = [](const typename Tuple::const_iterator&) { }; auto fcommit = []() { }; auto frollback = []() { }; @@ -296,14 +257,11 @@ struct matcher } template - static inline bool tmatch(const Tuple& tup, MappingVector& mv) - { + static inline bool tmatch(const Tuple& tup, MappingVector& mv) { auto& tarr = static_types_array::arr; - if (tup.size() >= (sizeof...(T) - wc_count)) - { + if (tup.size() >= (sizeof...(T) - wc_count)) { size_t commited_size = 0; - auto fpush = [&](const typename Tuple::const_iterator& iter) - { + auto fpush = [&](const typename Tuple::const_iterator& iter) { mv.push_back(iter.position()); }; auto fcommit = [&]() { commited_size = mv.size(); }; @@ -316,31 +274,26 @@ struct matcher static inline bool vmatch(const Tuple& tup, const pattern& ptrn, - const typename pattern::mapping_vector& mv) - { + const typename pattern::mapping_vector& mv) { return ptrn._matches_values(tup, &mv); } }; // implementation for zero or one wildcards template -struct match_impl -{ - static inline bool _(const Tuple& tup) - { +struct match_impl { + static inline bool _(const Tuple& tup) { return matcher::tmatch(tup); } template static inline bool _(const Tuple& tup, - util::fixed_vector& mv) - { + util::fixed_vector& mv) { return matcher::tmatch(tup, mv); } static inline bool _(const Tuple& tup, - const pattern& p) - { + const pattern& p) { return matcher::tmatch(tup) && ( p.has_values() == false || matcher::vmatch(tup, p)); @@ -348,8 +301,7 @@ struct match_impl static inline bool _(const Tuple& tup, const pattern& p, - typename pattern::mapping_vector& mv) - { + typename pattern::mapping_vector& mv) { return matcher::tmatch(tup, mv) && ( p.has_values() == false || matcher::vmatch(tup, p)); @@ -358,26 +310,21 @@ struct match_impl // implementation for multiple wildcards template -struct match_impl -{ +struct match_impl { static constexpr auto PC = wildcard_position::multiple; - static inline bool _(const Tuple& tup) - { + static inline bool _(const Tuple& tup) { return matcher::tmatch(tup); } template static inline bool _(const Tuple& tup, - util::fixed_vector& mv) - { + util::fixed_vector& mv) { return matcher::tmatch(tup, mv); } - static inline bool _(const Tuple& tup, const pattern& p) - { - if (p.has_values()) - { + static inline bool _(const Tuple& tup, const pattern& p) { + if (p.has_values()) { typename pattern::mapping_vector mv; return matcher::tmatch(tup, mv) && matcher::vmatch(tup, p, mv); @@ -386,10 +333,8 @@ struct match_impl } static inline bool _(const Tuple& tup, const pattern& p, - typename pattern::mapping_vector& mv) - { - if (p.has_values()) - { + typename pattern::mapping_vector& mv) { + if (p.has_values()) { typename pattern::mapping_vector mv; return matcher::tmatch(tup, mv) && matcher::vmatch(tup, p, mv); @@ -399,11 +344,10 @@ struct match_impl }; template -class match_impl_from_type_list; +struct match_impl_from_type_list; template -struct match_impl_from_type_list > -{ +struct match_impl_from_type_list > { typedef match_impl >(), Tuple, Ts...> @@ -414,8 +358,7 @@ struct match_impl_from_type_list > * @brief Returns true if this tuple matches the pattern {Ts...}. */ template -bool matches(const any_tuple& tup) -{ +bool matches(const any_tuple& tup) { typedef util::type_list tl; return match_impl(), any_tuple, Ts...> ::_(tup); @@ -430,8 +373,7 @@ bool matches(const any_tuple& tup, size_t, util::tl_count_not< util::type_list, - is_anything>::value>& mv) -{ + is_anything>::value>& mv) { typedef util::type_list tl; return match_impl(), any_tuple, Ts...> ::_(tup, mv); @@ -441,8 +383,7 @@ bool matches(const any_tuple& tup, * @brief Returns true if this tuple matches @p pn. */ template -bool matches(const any_tuple& tup, const pattern& pn) -{ +bool matches(const any_tuple& tup, const pattern& pn) { typedef util::type_list tl; return match_impl(), any_tuple, Ts...> ::_(tup, pn); @@ -453,8 +394,7 @@ bool matches(const any_tuple& tup, const pattern& pn) */ template bool matches(const any_tuple& tup, const pattern& pn, - typename pattern::mapping_vector& mv) -{ + typename pattern::mapping_vector& mv) { typedef util::type_list tl; return match_impl(), any_tuple, Ts...> ::_(tup, pn, mv); @@ -462,8 +402,7 @@ bool matches(const any_tuple& tup, const pattern& pn, // support for type_list based matching template -inline bool matches(const any_tuple& tup, const util::type_list&) -{ +inline bool matches(const any_tuple& tup, const util::type_list&) { return matches(tup); } @@ -473,8 +412,7 @@ inline bool matches(const any_tuple& tup, const util::type_list&, size_t, util::tl_count_not< util::type_list, - is_anything>::value>& mv) -{ + is_anything>::value>& mv) { return matches(tup, mv); } @@ -483,17 +421,15 @@ inline bool matches(const any_tuple& tup, const util::type_list&, * (does not match for values). */ template -inline bool matches_types(const any_tuple& tup, const pattern&) -{ +inline bool matches_types(const any_tuple& tup, const pattern&) { return matches(tup); } template -inline bool matches_types(const any_tuple& tup, const util::type_list&) -{ +inline bool matches_types(const any_tuple& tup, const util::type_list&) { return matches(tup); } } } // namespace cppa::detail -#endif // MATCHES_HPP +#endif // CPPA_MATCHES_HPP diff --git a/cppa/detail/native_socket.hpp b/cppa/detail/native_socket.hpp index ba36704f32..ac626bcaec 100644 --- a/cppa/detail/native_socket.hpp +++ b/cppa/detail/native_socket.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef NATIVE_SOCKET_HPP -#define NATIVE_SOCKET_HPP +#ifndef CPPA_NATIVE_SOCKET_HPP +#define CPPA_NATIVE_SOCKET_HPP #include "cppa/config.hpp" @@ -46,12 +46,12 @@ namespace cppa { namespace detail { #ifdef CPPA_WINDOWS typedef SOCKET native_socket_type; - typedef char const* socket_send_ptr; + typedef const char* socket_send_ptr; typedef char* socket_recv_ptr; constexpr SOCKET invalid_socket = INVALID_SOCKET; #else typedef int native_socket_type; - typedef void const* socket_send_ptr; + typedef const void* socket_send_ptr; typedef void* socket_recv_ptr; constexpr int invalid_socket = -1; void closesocket(native_socket_type s); @@ -59,4 +59,4 @@ namespace cppa { namespace detail { } } // namespace cppa::detail -#endif // NATIVE_SOCKET_HPP +#endif // CPPA_NATIVE_SOCKET_HPP diff --git a/cppa/detail/network_manager.hpp b/cppa/detail/network_manager.hpp index 3c7933aed0..b988e6f98c 100644 --- a/cppa/detail/network_manager.hpp +++ b/cppa/detail/network_manager.hpp @@ -28,30 +28,28 @@ \******************************************************************************/ -#ifndef NETWORK_MANAGER_HPP -#define NETWORK_MANAGER_HPP +#ifndef CPPA_NETWORK_MANAGER_HPP +#define CPPA_NETWORK_MANAGER_HPP -#include "cppa/detail/mailman.hpp" -#include "cppa/detail/post_office_msg.hpp" +#include "cppa/detail/post_office.hpp" namespace cppa { namespace detail { -class network_manager -{ +class network_manager { public: virtual ~network_manager(); - virtual void write_to_pipe(const pipe_msg& what) = 0; - virtual void start() = 0; virtual void stop() = 0; - virtual intrusive::single_reader_queue& mailman_queue() = 0; + virtual void send_to_post_office(const po_message& msg) = 0; + + virtual void send_to_post_office(any_tuple msg) = 0; - virtual intrusive::single_reader_queue& post_office_queue() = 0; + virtual void send_to_mailman(any_tuple msg) = 0; static network_manager* create_singleton(); @@ -59,4 +57,4 @@ class network_manager } } // namespace cppa::detail -#endif // NETWORK_MANAGER_HPP +#endif // CPPA_NETWORK_MANAGER_HPP diff --git a/cppa/detail/object_array.hpp b/cppa/detail/object_array.hpp index 9b552d5cd0..8dd753cee8 100644 --- a/cppa/detail/object_array.hpp +++ b/cppa/detail/object_array.hpp @@ -28,19 +28,17 @@ \******************************************************************************/ -#ifndef OBJECT_ARRAY_HPP -#define OBJECT_ARRAY_HPP +#ifndef CPPA_OBJECT_ARRAY_HPP +#define CPPA_OBJECT_ARRAY_HPP #include #include "cppa/object.hpp" -#include "cppa/type_value_pair.hpp" #include "cppa/detail/abstract_tuple.hpp" namespace cppa { namespace detail { -class object_array : public abstract_tuple -{ +class object_array : public abstract_tuple { typedef abstract_tuple super; @@ -62,11 +60,11 @@ class object_array : public abstract_tuple abstract_tuple* copy() const; - void const* at(size_t pos) const; + const void* at(size_t pos) const; bool equals(const cppa::detail::abstract_tuple&) const; - uniform_type_info const* type_at(size_t pos) const; + const uniform_type_info* type_at(size_t pos) const; private: @@ -76,4 +74,4 @@ class object_array : public abstract_tuple } } // namespace cppa::detail -#endif // OBJECT_ARRAY_HPP +#endif // CPPA_OBJECT_ARRAY_HPP diff --git a/cppa/detail/object_impl.hpp b/cppa/detail/object_impl.hpp index 1cf1e10f6a..06a5de8c3e 100644 --- a/cppa/detail/object_impl.hpp +++ b/cppa/detail/object_impl.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef OBJECT_IMPL_HPP -#define OBJECT_IMPL_HPP +#ifndef CPPA_OBJECT_IMPL_HPP +#define CPPA_OBJECT_IMPL_HPP #include "cppa/object.hpp" @@ -43,25 +43,22 @@ const utype& uniform_type_info(); namespace cppa { namespace detail { template -struct obj_impl : object -{ - T m_value; - obj_impl() : m_value() { } - obj_impl(const T& v) : m_value(v) { } - virtual object* copy() const { return new obj_impl(m_value); } - virtual const utype& type() const { return uniform_type_info(); } - virtual void* mutable_value() { return &m_value; } - virtual void const* value() const { return &m_value; } - virtual void serialize(serializer& s) const - { - s << m_value; - } - virtual void deserialize(deserializer& d) - { - d >> m_value; - } +struct obj_impl : object { + T m_value; + obj_impl() : m_value() { } + obj_impl(const T& v) : m_value(v) { } + virtual object* copy() const { return new obj_impl(m_value); } + virtual const utype& type() const { return uniform_type_info(); } + virtual void* mutable_value() { return &m_value; } + virtual const void* value() const { return &m_value; } + virtual void serialize(serializer& s) const { + s << m_value; + } + virtual void deserialize(deserializer& d) { + d >> m_value; + } }; } } // namespace cppa::detail -#endif // OBJECT_IMPL_HPP +#endif // CPPA_OBJECT_IMPL_HPP diff --git a/cppa/detail/pair_member.hpp b/cppa/detail/pair_member.hpp index aca835db67..acf4029ec6 100644 --- a/cppa/detail/pair_member.hpp +++ b/cppa/detail/pair_member.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef PAIR_MEMBER_HPP -#define PAIR_MEMBER_HPP +#ifndef CPPA_PAIR_MEMBER_HPP +#define CPPA_PAIR_MEMBER_HPP #include @@ -42,8 +42,7 @@ namespace cppa { namespace detail { template -class pair_member : public util::abstract_uniform_type_info> -{ +class pair_member : public util::abstract_uniform_type_info> { static constexpr primitive_type ptype1 = type_to_ptype::ptype; static constexpr primitive_type ptype2 = type_to_ptype::ptype; @@ -55,15 +54,13 @@ class pair_member : public util::abstract_uniform_type_info> public: - void serialize(void const* obj, serializer* s) const - { - auto& p = *reinterpret_cast(obj); + void serialize(const void* obj, serializer* s) const { + auto& p = *reinterpret_cast(obj); primitive_variant values[2] = { p.first, p.second }; s->write_tuple(2, values); } - void deserialize(void* obj, deserializer* d) const - { + void deserialize(void* obj, deserializer* d) const { primitive_type ptypes[2] = { ptype1, ptype2 }; primitive_variant values[2]; d->read_tuple(2, ptypes, values); @@ -76,4 +73,4 @@ class pair_member : public util::abstract_uniform_type_info> } } // namespace cppa::detail -#endif // PAIR_MEMBER_HPP +#endif // CPPA_PAIR_MEMBER_HPP diff --git a/cppa/detail/post_office.hpp b/cppa/detail/post_office.hpp index fd5c610d3d..bc44ec00de 100644 --- a/cppa/detail/post_office.hpp +++ b/cppa/detail/post_office.hpp @@ -28,22 +28,27 @@ \******************************************************************************/ -#ifndef POST_OFFICE_HPP -#define POST_OFFICE_HPP +#ifndef CPPA_POST_OFFICE_HPP +#define CPPA_POST_OFFICE_HPP #include +#include "cppa/atom.hpp" #include "cppa/actor_proxy.hpp" #include "cppa/detail/native_socket.hpp" namespace cppa { namespace detail { -void post_office_loop(int pipe_read_handle, int pipe_write_handle); +struct po_message { + atom_value flag; + native_socket_type fd; + actor_id aid; +}; + +void post_office_loop(int input_fd); void post_office_add_peer(native_socket_type peer_socket, - const process_information_ptr& peer_ptr, - const actor_proxy_ptr& peer_actor_ptr, - std::unique_ptr&& peer_observer); + const process_information_ptr& peer_ptr); void post_office_publish(native_socket_type server_socket, const actor_ptr& published_actor); @@ -54,4 +59,4 @@ void post_office_close_socket(native_socket_type sfd); } } // namespace cppa::detail -#endif // POST_OFFICE_HPP +#endif // CPPA_POST_OFFICE_HPP diff --git a/cppa/detail/post_office_msg.hpp b/cppa/detail/post_office_msg.hpp index f8582197d4..59baac9216 100644 --- a/cppa/detail/post_office_msg.hpp +++ b/cppa/detail/post_office_msg.hpp @@ -40,24 +40,21 @@ namespace cppa { namespace detail { -class post_office_msg -{ +class post_office_msg { friend class intrusive::singly_linked_list; friend class intrusive::single_reader_queue; public: - enum msg_type - { + enum msg_type { invalid_type, add_peer_type, add_server_socket_type, proxy_exited_type }; - struct add_peer - { + struct add_peer { native_socket_type sockfd; process_information_ptr peer; @@ -71,8 +68,7 @@ class post_office_msg }; - struct add_server_socket - { + struct add_server_socket { native_socket_type server_sockfd; actor_ptr published_actor; @@ -81,8 +77,7 @@ class post_office_msg }; - struct proxy_exited - { + struct proxy_exited { actor_proxy_ptr proxy_ptr; inline proxy_exited(const actor_proxy_ptr& who) : proxy_ptr(who) { } }; @@ -98,33 +93,27 @@ class post_office_msg post_office_msg(const actor_proxy_ptr& proxy_ptr); - inline bool is_add_peer_msg() const - { + inline bool is_add_peer_msg() const { return m_type == add_peer_type; } - inline bool is_add_server_socket_msg() const - { + inline bool is_add_server_socket_msg() const { return m_type == add_server_socket_type; } - inline bool is_proxy_exited_msg() const - { + inline bool is_proxy_exited_msg() const { return m_type == proxy_exited_type; } - inline add_peer& as_add_peer_msg() - { + inline add_peer& as_add_peer_msg() { return m_add_peer_msg; } - inline add_server_socket& as_add_server_socket_msg() - { + inline add_server_socket& as_add_server_socket_msg() { return m_add_server_socket; } - inline proxy_exited& as_proxy_exited_msg() - { + inline proxy_exited& as_proxy_exited_msg() { return m_proxy_exited; } @@ -136,8 +125,7 @@ class post_office_msg msg_type m_type; - union - { + union { add_peer m_add_peer_msg; add_server_socket m_add_server_socket; proxy_exited m_proxy_exited; diff --git a/cppa/detail/primitive_member.hpp b/cppa/detail/primitive_member.hpp index 02e64dbe74..5ba0180f02 100644 --- a/cppa/detail/primitive_member.hpp +++ b/cppa/detail/primitive_member.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef PRIMITIVE_MEMBER_HPP -#define PRIMITIVE_MEMBER_HPP +#ifndef CPPA_PRIMITIVE_MEMBER_HPP +#define CPPA_PRIMITIVE_MEMBER_HPP #include "cppa/serializer.hpp" #include "cppa/deserializer.hpp" @@ -42,8 +42,7 @@ namespace cppa { namespace detail { // uniform_type_info implementation for primitive data types. template -class primitive_member : public util::abstract_uniform_type_info -{ +class primitive_member : public util::abstract_uniform_type_info { static constexpr primitive_type ptype = type_to_ptype::ptype; @@ -51,13 +50,11 @@ class primitive_member : public util::abstract_uniform_type_info public: - void serialize(void const* obj, serializer* s) const - { - s->write_value(*reinterpret_cast(obj)); + void serialize(const void* obj, serializer* s) const { + s->write_value(*reinterpret_cast(obj)); } - void deserialize(void* obj, deserializer* d) const - { + void deserialize(void* obj, deserializer* d) const { primitive_variant val(d->read_value(ptype)); *reinterpret_cast(obj) = std::move(get(val)); } @@ -66,4 +63,4 @@ class primitive_member : public util::abstract_uniform_type_info } } // namespace cppa::detail -#endif // PRIMITIVE_MEMBER_HPP +#endif // CPPA_PRIMITIVE_MEMBER_HPP diff --git a/cppa/detail/projection.hpp b/cppa/detail/projection.hpp index 13f44193db..92276582b3 100644 --- a/cppa/detail/projection.hpp +++ b/cppa/detail/projection.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef PROJECTION_HPP -#define PROJECTION_HPP +#ifndef CPPA_PROJECTION_HPP +#define CPPA_PROJECTION_HPP #include "cppa/option.hpp" #include "cppa/guard_expr.hpp" @@ -45,15 +45,12 @@ namespace cppa { namespace detail { template -struct projection_helper -{ +struct projection_helper { const PartialFun& fun; projection_helper(const PartialFun& pfun) : fun(pfun) { } template - bool operator()(Args&&... args) const - { - if (fun.defined_at(std::forward(args)...)) - { + bool operator()(Args&&... args) const { + if (fun.defined_at(std::forward(args)...)) { fun(std::forward(args)...); return true; } @@ -65,8 +62,7 @@ struct projection_helper * @brief Projection implemented by a set of functors. */ template -class projection -{ +class projection { public: @@ -84,8 +80,7 @@ class projection * @brief Invokes @p fun with a projection of args.... */ template - bool operator()(PartialFun& fun, Args... args) const - { + bool operator()(PartialFun& fun, Args... args) const { typedef typename util::tl_zip< typename util::tl_map< ProjectionFuns, @@ -101,8 +96,7 @@ class projection collected_args; typename tdata_from_type_list::type pargs; - if (collect(pargs, m_funs, std::forward(args)...)) - { + if (collect(pargs, m_funs, std::forward(args)...)) { projection_helper helper{fun}; return util::unchecked_apply_tuple(helper, pargs); } @@ -112,17 +106,14 @@ class projection private: template - static inline bool fetch_(Storage& storage, T&& value) - { + static inline bool fetch_(Storage& storage, T&& value) { storage = std::forward(value); return true; } template - static inline bool fetch_(Storage& storage, option&& value) - { - if (value) - { + static inline bool fetch_(Storage& storage, option&& value) { + if (value) { storage = std::move(*value); return true; } @@ -130,26 +121,22 @@ class projection } template - static inline bool fetch(Storage& storage, const Fun& fun, T&& arg) - { + static inline bool fetch(Storage& storage, const Fun& fun, T&& arg) { return fetch_(storage, fun(std::forward(arg))); } template - static inline bool fetch(Storage& storage, const util::void_type&, T&& arg) - { + static inline bool fetch(Storage& storage, const util::void_type&, T&& arg) { return fetch_(storage, std::forward(arg)); } - static inline bool collect(tdata<>&, const tdata<>&) - { + static inline bool collect(tdata<>&, const tdata<>&) { return true; } template static inline bool collect(TData& td, const Trans& tr, - T0&& arg0, Ts&&... args) - { + T0&& arg0, Ts&&... args) { return fetch(td.head, tr.head, std::forward(arg0)) && collect(td.tail(), tr.tail(), std::forward(args)...); } @@ -159,8 +146,7 @@ class projection }; template<> -class projection > -{ +class projection > { public: @@ -169,10 +155,8 @@ class projection > projection(const projection&) = default; template - bool operator()(PartialFun& fun) const - { - if (fun.defined_at()) - { + bool operator()(PartialFun& fun) const { + if (fun.defined_at()) { fun(); return true; } @@ -182,14 +166,13 @@ class projection > }; template -class projection_from_type_list; +struct projection_from_type_list; template -class projection_from_type_list > -{ +struct projection_from_type_list > { typedef projection type; }; } } // namespace cppa::detail -#endif // PROJECTION_HPP +#endif // CPPA_PROJECTION_HPP diff --git a/cppa/detail/pseudo_tuple.hpp b/cppa/detail/pseudo_tuple.hpp index 600cc49a18..83e12d1a1b 100644 --- a/cppa/detail/pseudo_tuple.hpp +++ b/cppa/detail/pseudo_tuple.hpp @@ -28,33 +28,29 @@ \******************************************************************************/ -#ifndef PSEUDO_TUPLE_HPP -#define PSEUDO_TUPLE_HPP +#ifndef CPPA_PSEUDO_TUPLE_HPP +#define CPPA_PSEUDO_TUPLE_HPP #include "cppa/util/at.hpp" namespace cppa { namespace detail { template -struct pseudo_tuple -{ +struct pseudo_tuple { typedef void* ptr_type; - typedef void const* const_ptr_type; + typedef const void* const_ptr_type; ptr_type data[sizeof...(T) > 0 ? sizeof...(T) : 1]; - inline const_ptr_type at(size_t p) const - { + inline const_ptr_type at(size_t p) const { return data[p]; } - inline ptr_type mutable_at(size_t p) - { + inline ptr_type mutable_at(size_t p) { return const_cast(data[p]); } - inline void*& operator[](size_t p) - { + inline void*& operator[](size_t p) { return data[p]; } }; @@ -63,8 +59,7 @@ template struct pseudo_tuple_from_type_list; template -struct pseudo_tuple_from_type_list > -{ +struct pseudo_tuple_from_type_list > { typedef pseudo_tuple type; }; @@ -73,19 +68,17 @@ struct pseudo_tuple_from_type_list > namespace cppa { template -const typename util::at::type& get(const detail::pseudo_tuple& tv) -{ +const typename util::at::type& get(const detail::pseudo_tuple& tv) { static_assert(N < sizeof...(Tn), "N >= tv.size()"); - return *reinterpret_cast::type const*>(tv.at(N)); + return *reinterpret_cast::type*>(tv.at(N)); } template -typename util::at::type& get_ref(detail::pseudo_tuple& tv) -{ +typename util::at::type& get_ref(detail::pseudo_tuple& tv) { static_assert(N < sizeof...(Tn), "N >= tv.size()"); return *reinterpret_cast::type*>(tv.mutable_at(N)); } } // namespace cppa -#endif // PSEUDO_TUPLE_HPP +#endif // CPPA_PSEUDO_TUPLE_HPP diff --git a/cppa/detail/ptype_to_type.hpp b/cppa/detail/ptype_to_type.hpp index eb492b10b4..8b47c5b601 100644 --- a/cppa/detail/ptype_to_type.hpp +++ b/cppa/detail/ptype_to_type.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef PTYPE_TO_TYPE_HPP -#define PTYPE_TO_TYPE_HPP +#ifndef CPPA_PTYPE_TO_TYPE_HPP +#define CPPA_PTYPE_TO_TYPE_HPP #include @@ -62,10 +62,9 @@ struct ptype_to_type : util::if_else_c > > > > > > > > > > > > > -{ + void > > > > > > > > > > > > > > { }; } } // namespace cppa::detail -#endif // PTYPE_TO_TYPE_HPP +#endif // CPPA_PTYPE_TO_TYPE_HPP diff --git a/cppa/detail/receive_loop_helper.hpp b/cppa/detail/receive_loop_helper.hpp index 745feae200..b989ca1b54 100644 --- a/cppa/detail/receive_loop_helper.hpp +++ b/cppa/detail/receive_loop_helper.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef RECEIVE_LOOP_HELPER_HPP -#define RECEIVE_LOOP_HELPER_HPP +#ifndef CPPA_RECEIVE_LOOP_HELPER_HPP +#define CPPA_RECEIVE_LOOP_HELPER_HPP #include @@ -41,45 +41,36 @@ #include "cppa/util/tbind.hpp" #include "cppa/util/type_list.hpp" -#include "cppa/detail/invokable.hpp" - - namespace cppa { namespace detail { template -struct receive_while_helper -{ +struct receive_while_helper { Statement m_stmt; template receive_while_helper(S&& stmt) : m_stmt(std::forward(stmt)) { } - void operator()(behavior& bhvr) - { + void operator()(behavior& bhvr) { local_actor* sptr = self; while (m_stmt()) sptr->dequeue(bhvr); } - void operator()(partial_function& fun) - { + void operator()(partial_function& fun) { local_actor* sptr = self; while (m_stmt()) sptr->dequeue(fun); } template - void operator()(Arg0&& arg0, Args&&... args) - { + void operator()(Arg0&& arg0, Args&&... args) { auto tmp = match_expr_concat(std::forward(arg0), - std::forward(args)...); - (*this)(tmp); + std::forward(args)...); (*this)(tmp); } }; template -class receive_for_helper -{ +class receive_for_helper { T& begin; T end; @@ -88,30 +79,25 @@ class receive_for_helper receive_for_helper(T& first, const T& last) : begin(first), end(last) { } - void operator()(behavior& bhvr) - { + void operator()(behavior& bhvr) { local_actor* sptr = self; for ( ; begin != end; ++begin) sptr->dequeue(bhvr); } - void operator()(partial_function& fun) - { + void operator()(partial_function& fun) { local_actor* sptr = self; for ( ; begin != end; ++begin) sptr->dequeue(fun); } template - void operator()(Arg0&& arg0, Args&&... args) - { + void operator()(Arg0&& arg0, Args&&... args) { auto tmp = match_expr_concat(std::forward(arg0), - std::forward(args)...); - (*this)(tmp); + std::forward(args)...); (*this)(tmp); } }; -class do_receive_helper -{ +class do_receive_helper { behavior m_bhvr; @@ -119,30 +105,24 @@ class do_receive_helper template do_receive_helper(Args&&... args) - : m_bhvr(match_expr_concat(std::forward(args)...)) - { + : m_bhvr(match_expr_concat(std::forward(args)...)) { } do_receive_helper(do_receive_helper&&) = default; template - void until(Statement&& stmt) - { + void until(Statement&& stmt) { static_assert(std::is_same::value, "functor or function does not return a boolean"); local_actor* sptr = self; - if (m_bhvr.timeout().valid()) - { - do - { + if (m_bhvr.timeout().valid()) { + do { sptr->dequeue(m_bhvr); } while (stmt() == false); } - else - { - do - { + else { + do { sptr->dequeue(m_bhvr.get_partial_function()); } while (stmt() == false); @@ -153,4 +133,4 @@ class do_receive_helper } } // namespace cppa::detail -#endif // RECEIVE_LOOP_HELPER_HPP +#endif // CPPA_RECEIVE_LOOP_HELPER_HPP diff --git a/cppa/detail/receive_policy.hpp b/cppa/detail/receive_policy.hpp new file mode 100644 index 0000000000..1529e148ee --- /dev/null +++ b/cppa/detail/receive_policy.hpp @@ -0,0 +1,251 @@ +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + + +#ifndef CPPA_NESTABLE_RECEIVE_POLICY_HPP +#define CPPA_NESTABLE_RECEIVE_POLICY_HPP + +#include +#include +#include + +#include "cppa/behavior.hpp" +#include "cppa/partial_function.hpp" +#include "cppa/detail/filter_result.hpp" +#include "cppa/detail/recursive_queue_node.hpp" + +namespace cppa { namespace detail { + +enum receive_policy_flag { + // blocking message processing: thread-mapped & context-switching actors + rp_nestable, + // callback-based message processing: event-based actors + rp_callback +}; + +class receive_policy { + + public: + + enum handle_message_result { + hm_timeout_msg, + hm_skip_msg, + hm_drop_msg, + hm_cache_msg, + hm_msg_handled + }; + + template + bool invoke_from_cache(Client* client, FunOrBehavior& fun) { + std::integral_constant token; + auto i = m_cache.begin(); + auto e = m_cache.end(); + while (i != e) { + switch (this->handle_message(client, *(*i), fun, token)) { + case hm_msg_handled: { + client->release_node(i->release()); + m_cache.erase(i); + return true; + } + case hm_drop_msg: { + client->release_node(i->release()); + i = m_cache.erase(i); + break; + } + case hm_skip_msg: + case hm_cache_msg: { + ++i; + break; + } + default: { + CPPA_CRITICAL("illegal result of handle_message"); + } + } + } + return false; + } + + template + bool invoke(Client* client, recursive_queue_node* node, FunOrBehavior& fun) { + std::integral_constant token; + switch (this->handle_message(client, *node, fun, token)) { + case hm_msg_handled: { + client->release_node(node); + return true; + } + case hm_drop_msg: { + client->release_node(node); + break; + } + case hm_cache_msg: { + m_cache.emplace_back(node); + break; + } + case hm_skip_msg: { + CPPA_CRITICAL("received a marked node"); + } + default: { + CPPA_CRITICAL("illegal result of handle_message"); + } + } + return false; + } + + template + void receive(Client* client, partial_function& fun) { + if (invoke_from_cache(client, fun) == false) { + while (invoke(client, client->receive_node(), fun) == false) { } + } + } + + template + void receive(Client* client, behavior& bhvr) { + auto& fun = bhvr.get_partial_function(); + if (bhvr.timeout().valid() == false) { + receive(client, fun); + } + else if (invoke_from_cache(client, fun) == false) { + if (bhvr.timeout().is_zero()) { + recursive_queue_node* e = nullptr; + while ((e = client->try_receive_node()) != nullptr) { + CPPA_REQUIRE(e->marked == false); + if (invoke(client, e, bhvr)) { + return; // done + } + } + handle_timeout(client, bhvr); + } + else { + auto timeout = client->init_timeout(bhvr.timeout()); + recursive_queue_node* e = nullptr; + while ((e = client->try_receive_node(timeout)) != nullptr) { + CPPA_REQUIRE(e->marked == false); + if (invoke(client, e, bhvr)) { + return; // done + } + } + handle_timeout(client, bhvr); + } + } + } + + private: + + typedef std::integral_constant nestable; + typedef std::integral_constant callback; + + std::list > m_cache; + + template + inline void handle_timeout(Client* client, behavior& bhvr) { + client->handle_timeout(bhvr); + } + + template + inline void handle_timeout(Client*, partial_function&) { + CPPA_CRITICAL("handle_timeout(partial_function&)"); + } + + template + handle_message_result handle_message(Client* client, + recursive_queue_node& node, + FunOrBehavior& fun, + nestable) { + if (node.marked) { + return hm_skip_msg; + } + switch (client->filter_msg(node.msg)) { + case normal_exit_signal: + case expired_timeout_message: { + return hm_drop_msg; + } + case timeout_message: { + handle_timeout(client, fun); + return hm_msg_handled; + } + case ordinary_message: { + std::swap(client->m_last_dequeued, node.msg); + std::swap(client->m_last_sender, node.sender); + client->push_timeout(); + node.marked = true; + if (fun(client->m_last_dequeued)) { + client->m_last_dequeued.reset(); + client->m_last_sender.reset(); + return hm_msg_handled; + } + // no match (restore client members) + std::swap(client->m_last_dequeued, node.msg); + std::swap(client->m_last_sender, node.sender); + client->pop_timeout(); + node.marked = false; + return hm_cache_msg; + } + default: CPPA_CRITICAL("illegal result of filter_msg"); + } + } + + template + handle_message_result handle_message(Client* client, + recursive_queue_node& node, + FunOrBehavior& fun, + callback) { + CPPA_REQUIRE(node.marked == false); + switch (client->filter_msg(node.msg)) { + case normal_exit_signal: + case expired_timeout_message: { + return hm_drop_msg; + } + case timeout_message: { + handle_timeout(client, fun); + return hm_msg_handled; + } + case ordinary_message: { + std::swap(client->m_last_dequeued, node.msg); + std::swap(client->m_last_sender, node.sender); + if (fun(client->m_last_dequeued)) { + client->m_last_dequeued.reset(); + client->m_last_sender.reset(); + // we definitely don't have a pending timeout now + client->m_has_pending_timeout_request = false; + return hm_msg_handled; + } + // no match, restore members + std::swap(client->m_last_dequeued, node.msg); + std::swap(client->m_last_sender, node.sender); + return hm_cache_msg; + } + default: CPPA_CRITICAL("illegal result of filter_msg"); + } + } + +}; + +} } // namespace cppa::detail + +#endif // CPPA_NESTABLE_RECEIVE_POLICY_HPP diff --git a/cppa/detail/recursive_queue_node.hpp b/cppa/detail/recursive_queue_node.hpp new file mode 100644 index 0000000000..4a8ae703fa --- /dev/null +++ b/cppa/detail/recursive_queue_node.hpp @@ -0,0 +1,64 @@ +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + + +#ifndef CPPA_RECURSIVE_QUEUE_NODE_HPP +#define CPPA_RECURSIVE_QUEUE_NODE_HPP + +#include "cppa/actor.hpp" +#include "cppa/any_tuple.hpp" + +namespace cppa { namespace detail { + +struct recursive_queue_node { + recursive_queue_node* next; // intrusive next pointer + bool marked; // denotes if this node is currently processed + actor_ptr sender; + any_tuple msg; + + inline recursive_queue_node() : next(nullptr), marked(false) { + } + + inline recursive_queue_node(actor* from, any_tuple&& content) + : next(nullptr) + , marked(false) + , sender(from) + , msg(std::move(content)) { + } + + recursive_queue_node(recursive_queue_node&&) = delete; + recursive_queue_node(const recursive_queue_node&) = delete; + recursive_queue_node& operator=(recursive_queue_node&&) = delete; + recursive_queue_node& operator=(const recursive_queue_node&) = delete; + +}; + +} } // namespace cppa::detail + +#endif // CPPA_RECURSIVE_QUEUE_NODE_HPP diff --git a/cppa/detail/ref_counted_impl.hpp b/cppa/detail/ref_counted_impl.hpp index 1b88ac2f7c..ef48cf1667 100644 --- a/cppa/detail/ref_counted_impl.hpp +++ b/cppa/detail/ref_counted_impl.hpp @@ -28,14 +28,13 @@ \******************************************************************************/ -#ifndef REF_COUNTED_IMPL_HPP -#define REF_COUNTED_IMPL_HPP +#ifndef CPPA_REF_COUNTED_IMPL_HPP +#define CPPA_REF_COUNTED_IMPL_HPP namespace cppa { namespace detail { template -class ref_counted_impl -{ +class ref_counted_impl { T m_rc; @@ -59,4 +58,4 @@ class ref_counted_impl } } // namespace cppa::detail -#endif // REF_COUNTED_IMPL_HPP +#endif // CPPA_REF_COUNTED_IMPL_HPP diff --git a/cppa/detail/mock_scheduler.hpp b/cppa/detail/scheduled_actor_dummy.hpp similarity index 75% rename from cppa/detail/mock_scheduler.hpp rename to cppa/detail/scheduled_actor_dummy.hpp index ad3453d09e..2a00bde213 100644 --- a/cppa/detail/mock_scheduler.hpp +++ b/cppa/detail/scheduled_actor_dummy.hpp @@ -28,28 +28,30 @@ \******************************************************************************/ -#ifndef MOCK_SCHEDULER_HPP -#define MOCK_SCHEDULER_HPP +#ifndef CPPA_SCHEDULED_ACTOR_DUMMY_HPP +#define CPPA_SCHEDULED_ACTOR_DUMMY_HPP -#include "cppa/scheduler.hpp" +#include "cppa/detail/abstract_scheduled_actor.hpp" namespace cppa { namespace detail { -class mock_scheduler : public scheduler -{ - - public: - - actor_ptr spawn(abstract_event_based_actor* what); - - actor_ptr spawn(scheduled_actor*, scheduling_hint); - - static actor_ptr spawn(scheduled_actor*); - - void enqueue(detail::abstract_scheduled_actor*); - +struct scheduled_actor_dummy : abstract_scheduled_actor { + resume_result resume(util::fiber*); + void quit(std::uint32_t); + void dequeue(behavior&); + void dequeue(partial_function&); + void link_to(intrusive_ptr&); + void unlink_from(intrusive_ptr&); + bool establish_backlink(intrusive_ptr&); + bool remove_backlink(intrusive_ptr&); + void detach(const attachable::token&); + bool attach(attachable*); + void unbecome(); + void do_become(behavior*, bool, bool); + bool has_behavior(); + scheduled_actor_type impl_type(); }; } } // namespace cppa::detail -#endif // MOCK_SCHEDULER_HPP +#endif // CPPA_SCHEDULED_ACTOR_DUMMY_HPP diff --git a/cppa/detail/serialize_tuple.hpp b/cppa/detail/serialize_tuple.hpp index a8e6bd547a..fcac2933da 100644 --- a/cppa/detail/serialize_tuple.hpp +++ b/cppa/detail/serialize_tuple.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef SERIALIZE_TUPLE_HPP -#define SERIALIZE_TUPLE_HPP +#ifndef CPPA_SERIALIZE_TUPLE_HPP +#define CPPA_SERIALIZE_TUPLE_HPP #include @@ -41,11 +41,9 @@ namespace cppa { class serializer; } namespace cppa { namespace detail { template -struct serialize_tuple -{ +struct serialize_tuple { template - inline static void _(serializer& s, T const* tup) - { + inline static void _(serializer& s, const T* tup) { s << uniform_typeid()->name() << *reinterpret_cast(tup->at(Pos)); serialize_tuple::_(s, tup); @@ -53,12 +51,11 @@ struct serialize_tuple }; template -struct serialize_tuple, Pos> -{ +struct serialize_tuple, Pos> { template - inline static void _(serializer&, T const*) { } + inline static void _(serializer&, const T*) { } }; } } // namespace cppa::detail -#endif // SERIALIZE_TUPLE_HPP +#endif // CPPA_SERIALIZE_TUPLE_HPP diff --git a/cppa/detail/singleton_manager.hpp b/cppa/detail/singleton_manager.hpp index 20b5a6b1db..0f0f640328 100644 --- a/cppa/detail/singleton_manager.hpp +++ b/cppa/detail/singleton_manager.hpp @@ -28,11 +28,10 @@ \******************************************************************************/ -#ifndef SINGLETON_MANAGER_HPP -#define SINGLETON_MANAGER_HPP +#ifndef CPPA_SINGLETON_MANAGER_HPP +#define CPPA_SINGLETON_MANAGER_HPP -namespace cppa -{ +namespace cppa { class scheduler; class msg_content; @@ -48,8 +47,7 @@ class actor_registry; class network_manager; class uniform_type_info_map; -class singleton_manager -{ +class singleton_manager { singleton_manager() = delete; @@ -76,4 +74,4 @@ class singleton_manager } } // namespace cppa::detail -#endif // SINGLETON_MANAGER_HPP +#endif // CPPA_SINGLETON_MANAGER_HPP diff --git a/src/post_office_msg.cpp b/cppa/detail/stacked_actor_mixin.hpp similarity index 54% rename from src/post_office_msg.cpp rename to cppa/detail/stacked_actor_mixin.hpp index 41c244aeb6..76dc67a8b4 100644 --- a/src/post_office_msg.cpp +++ b/cppa/detail/stacked_actor_mixin.hpp @@ -28,73 +28,88 @@ \******************************************************************************/ -#include "cppa/detail/post_office_msg.hpp" +#ifndef CPPA_STACKED_ACTOR_MIXIN_HPP +#define CPPA_STACKED_ACTOR_MIXIN_HPP + +#include +#include + +#include "cppa/behavior.hpp" + +#include "cppa/detail/receive_policy.hpp" +#include "cppa/detail/behavior_stack.hpp" +#include "cppa/detail/recursive_queue_node.hpp" namespace cppa { namespace detail { -post_office_msg::add_peer::add_peer(native_socket_type peer_socket, - const process_information_ptr& peer_ptr, - const actor_proxy_ptr& peer_actor_ptr, - std::unique_ptr&& peer_observer) - : sockfd(peer_socket) - , peer(peer_ptr) - , first_peer_actor(peer_actor_ptr) - , attachable_ptr(std::move(peer_observer)) -{ -} - -post_office_msg::add_server_socket::add_server_socket(native_socket_type ssockfd, - const actor_ptr& whom) - : server_sockfd(ssockfd) - , published_actor(whom) -{ -} - -post_office_msg::post_office_msg(native_socket_type arg0, - const process_information_ptr& arg1, - const actor_proxy_ptr& arg2, - std::unique_ptr&& arg3) - : next(nullptr) - , m_type(add_peer_type) -{ - new (&m_add_peer_msg) add_peer(arg0, arg1, arg2, std::move(arg3)); -} - -post_office_msg::post_office_msg(native_socket_type arg0, const actor_ptr& arg1) - : next(nullptr) - , m_type(add_server_socket_type) -{ - new (&m_add_server_socket) add_server_socket(arg0, arg1); -} - -post_office_msg::post_office_msg(const actor_proxy_ptr& proxy_ptr) - : next(nullptr) - , m_type(proxy_exited_type) -{ - new (&m_proxy_exited) proxy_exited(proxy_ptr); -} - -post_office_msg::~post_office_msg() -{ - switch (m_type) - { - case add_peer_type: - { - m_add_peer_msg.~add_peer(); - break; +template +class stacked_actor_mixin : public Base { + + public: + + virtual void unbecome() { + if (m_bhvr_stack_ptr) { + m_bhvr_stack_ptr->pop_back(); + } + } + + virtual void dequeue(partial_function& fun) { + m_recv_policy.receive(dthis(), fun); + } + + virtual void dequeue(behavior& bhvr) { + m_recv_policy.receive(dthis(), bhvr); + } + + virtual void run() { + if (m_bhvr_stack_ptr) { + m_bhvr_stack_ptr->exec(); + m_bhvr_stack_ptr.reset(); + } + if (m_behavior) { + m_behavior(); } - case add_server_socket_type: - { - m_add_server_socket.~add_server_socket(); - break; + } + + protected: + + stacked_actor_mixin() = default; + + stacked_actor_mixin(std::function f) : m_behavior(std::move(f)) { } + + virtual void do_become(behavior* bhvr, bool owns_bhvr, bool discard_old) { + if (m_bhvr_stack_ptr) { + if (discard_old) m_bhvr_stack_ptr->pop_back(); + m_bhvr_stack_ptr->push_back(bhvr, owns_bhvr); } - case proxy_exited_type: - { - m_proxy_exited.~proxy_exited(); - break; + else { + m_bhvr_stack_ptr.reset(new behavior_stack); + m_bhvr_stack_ptr->push_back(bhvr, owns_bhvr); + if (this->initialized()) { + m_bhvr_stack_ptr->exec(); + m_bhvr_stack_ptr.reset(); + } } - default: break; } -} + + virtual bool has_behavior() { + return static_cast(m_behavior) + || ( static_cast(m_bhvr_stack_ptr) + && m_bhvr_stack_ptr->empty() == false); + } + + private: + + std::function m_behavior; + receive_policy m_recv_policy; + std::unique_ptr m_bhvr_stack_ptr; + + inline Derived* dthis() { + return static_cast(this); + } + +}; } } // namespace cppa::detail + +#endif // CPPA_STACKED_ACTOR_MIXIN_HPP diff --git a/cppa/detail/swap_bytes.hpp b/cppa/detail/swap_bytes.hpp index 2a1e1695b1..517a1b55f9 100644 --- a/cppa/detail/swap_bytes.hpp +++ b/cppa/detail/swap_bytes.hpp @@ -28,18 +28,16 @@ \******************************************************************************/ -#ifndef SWAP_BYTES_HPP -#define SWAP_BYTES_HPP +#ifndef CPPA_SWAP_BYTES_HPP +#define CPPA_SWAP_BYTES_HPP #include namespace cppa { namespace detail { template -struct byte_access -{ - union - { +struct byte_access { + union { T value; unsigned char bytes[sizeof(T)]; }; @@ -47,14 +45,11 @@ struct byte_access }; template -struct byte_swapper -{ - static T _(byte_access from) - { +struct byte_swapper { + static T _(byte_access from) { byte_access to; auto i = SizeOfT - 1; - for (size_t j = 0 ; j < SizeOfT ; --i, ++j) - { + for (size_t j = 0 ; j < SizeOfT ; --i, ++j) { to.bytes[i] = from.bytes[j]; } return to.value; @@ -62,17 +57,15 @@ struct byte_swapper }; template -struct byte_swapper<1, T> -{ +struct byte_swapper<1, T> { inline static T _(T what) { return what; } }; template -inline T swap_bytes(T what) -{ +inline T swap_bytes(T what) { return byte_swapper::_(what); } } } // namespace cppa::detail -#endif // SWAP_BYTES_HPP +#endif // CPPA_SWAP_BYTES_HPP diff --git a/cppa/detail/tdata.hpp b/cppa/detail/tdata.hpp index 65d927375f..7229991107 100644 --- a/cppa/detail/tdata.hpp +++ b/cppa/detail/tdata.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef TDATA_HPP -#define TDATA_HPP +#ifndef CPPA_TDATA_HPP +#define CPPA_TDATA_HPP #include #include @@ -51,7 +51,7 @@ namespace cppa { class uniform_type_info; -uniform_type_info const* uniform_typeid(const std::type_info&); +const uniform_type_info* uniform_typeid(const std::type_info&); } // namespace cppa namespace cppa { namespace detail { @@ -60,65 +60,56 @@ template inline void* ptr_to(T& what) { return &what; } template -inline void const* ptr_to(const T& what) { return &what; } +inline const void* ptr_to(const T& what) { return &what; } template inline void* ptr_to(T* what) { return what; } template -inline void const* ptr_to(T const* what) { return what; } +inline const void* ptr_to(const T* what) { return what; } template -inline void* ptr_to(const std::reference_wrapper& what) -{ +inline void* ptr_to(const std::reference_wrapper& what) { return &(what.get()); } template -inline void const* ptr_to(const std::reference_wrapper& what) -{ +inline const void* ptr_to(const std::reference_wrapper& what) { return &(what.get()); } template -inline uniform_type_info const* utype_of(const T&) -{ +inline const uniform_type_info* utype_of(const T&) { return static_types_array::arr[0]; } template -inline uniform_type_info const* utype_of(const std::reference_wrapper&) -{ +inline const uniform_type_info* utype_of(const std::reference_wrapper&) { return static_types_array::type>::arr[0]; } template -inline uniform_type_info const* utype_of(T const* ptr) -{ +inline const uniform_type_info* utype_of(const T* ptr) { return utype_of(*ptr); } template -struct boxed_or_void -{ +struct boxed_or_void { static constexpr bool value = is_boxed::value; }; template<> -struct boxed_or_void -{ +struct boxed_or_void { static constexpr bool value = true; }; template -struct unbox_ref -{ +struct unbox_ref { typedef T type; }; template -struct unbox_ref > -{ +struct unbox_ref > { typedef T type; }; @@ -129,8 +120,7 @@ template struct tdata; template<> -struct tdata<> -{ +struct tdata<> { typedef tdata super; @@ -147,8 +137,7 @@ struct tdata<> // swallow any number of additional boxed or void_type arguments silently template - tdata(Args&&...) - { + tdata(Args&&...) { typedef util::type_list::type...> incoming; typedef typename util::tl_filter_not_type::type iargs; static_assert(util::tl_forall::value, @@ -171,18 +160,15 @@ struct tdata<> const tdata<>& ctail() const { return *this; } - inline void const* at(size_t) const - { + inline const void* at(size_t) const { throw std::out_of_range("tdata<>"); } - inline void* mutable_at(size_t) - { + inline void* mutable_at(size_t) { throw std::out_of_range("tdata<>"); } - inline uniform_type_info const* type_at(size_t) const - { + inline const uniform_type_info* type_at(size_t) const { throw std::out_of_range("tdata<>"); } @@ -190,36 +176,31 @@ struct tdata<> inline bool operator==(const tdata&) const { return true; } - inline tuple_impl_info impl_type() const - { + inline tuple_impl_info impl_type() const { return statically_typed; } }; template -struct td_filter_ -{ +struct td_filter_ { static inline const T& _(const T& arg) { return arg; } static inline T&& _(T&& arg) { return std::move(arg); } static inline T& _(T& arg) { return arg; } }; template -struct td_filter_ -{ +struct td_filter_ { static inline T* _(T* arg) { return arg; } }; template -struct td_filter_ -{ +struct td_filter_ { static inline Head _(const T&) { return Head{}; } }; template -struct td_filter_ : td_filter_ -{ +struct td_filter_ : td_filter_ { }; template @@ -230,8 +211,7 @@ auto td_filter(T&& arg) std::is_function::type>::value, Head, typename util::rm_ref::type - >::_(std::forward(arg))) -{ + >::_(std::forward(arg))) { return td_filter_< is_boxed::type>::value, std::is_function::type>::value, @@ -244,8 +224,7 @@ template void tdata_set(tdata& rhs, const tdata& lhs); template -struct tdata : tdata -{ +struct tdata : tdata { typedef tdata super; @@ -261,8 +240,7 @@ struct tdata : tdata typedef Head head_type; typedef tdata tail_type; - typedef typename util::if_else_c< - (sizeof...(Tail) > 0), + typedef typename util::if_else_c< (sizeof...(Tail) > 0), typename tdata::back_type, util::wrapped >::type @@ -270,52 +248,43 @@ struct tdata : tdata inline tdata() : super(), head() { } - //tdata(const Head& v0, const Tail&... vals) : super(vals...), head(v0) { } - tdata(Head arg) : super(), head(std::move(arg)) { } template tdata(Arg0&& arg0, Arg1&& arg1, Args&&... args) : super(std::forward(arg1), std::forward(args)...) - , head(td_filter(std::forward(arg0))) - { + , head(td_filter(std::forward(arg0))) { } tdata(const tdata&) = default; tdata(tdata&& other) - : super(std::move(other.tail())), head(std::move(other.head)) - { + : super(std::move(other.tail())), head(std::move(other.head)) { } // allow (partial) initialization from a different tdata template - tdata(tdata& other) : super(other.tail()), head(other.head) - { + tdata(tdata& other) : super(other.tail()), head(other.head) { } template - tdata(const tdata& other) : super(other.tail()), head(other.head) - { + tdata(const tdata& other) : super(other.tail()), head(other.head) { } template tdata(tdata&& other) - : super(std::move(other.tail())), head(std::move(other.head)) - { + : super(std::move(other.tail())), head(std::move(other.head)) { } template - tdata& operator=(const tdata& other) - { + tdata& operator=(const tdata& other) { tdata_set(*this, other); return *this; } template - inline void set(Arg0&& arg0, Args&&... args) - { + inline void set(Arg0&& arg0, Args&&... args) { head = std::forward(arg0); super::set(std::forward(args)...); } @@ -338,11 +307,9 @@ struct tdata : tdata inline const tdata& ctail() const { return *this; } - inline void const* at(size_t p) const - { + inline const void* at(size_t p) const { CPPA_REQUIRE(p < num_elements); - switch (p) - { + switch (p) { case 0: return ptr_to(head); case 1: return ptr_to(super::head); case 2: return ptr_to(super::super::head); @@ -354,13 +321,10 @@ struct tdata : tdata //return (p == 0) ? ptr_to(head) : super::at(p - 1); } - inline void* mutable_at(size_t p) - { + inline void* mutable_at(size_t p) { # ifdef CPPA_DEBUG - if (p == 0) - { - if (std::is_same::value) - { + if (p == 0) { + if (std::is_same::value) { throw std::logic_error{"mutable_at with const head"}; } return const_cast(ptr_to(head)); @@ -372,43 +336,36 @@ struct tdata : tdata } - inline uniform_type_info const* type_at(size_t p) const - { + inline const uniform_type_info* type_at(size_t p) const { return (p == 0) ? utype_of(head) : super::type_at(p-1); } - Head& _back(std::integral_constant) - { + Head& _back(std::integral_constant) { return head; } template - back_type& _back(std::integral_constant) - { + back_type& _back(std::integral_constant) { std::integral_constant token; return super::_back(token); } - back_type& back() - { + back_type& back() { std::integral_constant token; return _back(token); } - const Head& _back(std::integral_constant) const - { + const Head& _back(std::integral_constant) const { return head; } template - const back_type& _back(std::integral_constant) const - { + const back_type& _back(std::integral_constant) const { std::integral_constant token; return super::_back(token); } - const back_type& back() const - { + const back_type& back() const { std::integral_constant token; return _back(token); } @@ -418,8 +375,7 @@ template void tdata_set(tdata&, const tdata<>&) { } template -void tdata_set(tdata& lhs, tdata& rhs) -{ +void tdata_set(tdata& lhs, tdata& rhs) { lhs.head = rhs.head; tdata_set(lhs.tail(), rhs.tail()); } @@ -428,14 +384,12 @@ template struct tdata_upcast_helper; template -struct tdata_upcast_helper -{ +struct tdata_upcast_helper { typedef typename tdata_upcast_helper::type type; }; template -struct tdata_upcast_helper<0, Head, Tail...> -{ +struct tdata_upcast_helper<0, Head, Tail...> { typedef tdata type; }; @@ -443,8 +397,7 @@ template struct tdata_from_type_list; template -struct tdata_from_type_list> -{ +struct tdata_from_type_list> { typedef tdata type; }; @@ -452,14 +405,12 @@ template inline void collect_tdata(tdata&) { } template -void collect_tdata(Storage& storage, const tdata<>&, const Args&... args) -{ +void collect_tdata(Storage& storage, const tdata<>&, const Args&... args) { collect_tdata(storage, args...); } template -void collect_tdata(Storage& storage, const Arg0& arg0, const Args&... args) -{ +void collect_tdata(Storage& storage, const Arg0& arg0, const Args&... args) { storage.head = arg0.head; collect_tdata(storage.tail(), arg0.tail(), args...); } @@ -470,25 +421,22 @@ namespace cppa { template detail::tdata::type>::type...> -mk_tdata(Args&&... args) -{ +mk_tdata(Args&&... args) { return {std::forward(args)...}; } template -const typename util::at::type& get(const detail::tdata& tv) -{ +const typename util::at::type& get(const detail::tdata& tv) { static_assert(N < sizeof...(Tn), "N >= tv.size()"); return static_cast::type&>(tv).head; } template -typename util::at::type& get_ref(detail::tdata& tv) -{ +typename util::at::type& get_ref(detail::tdata& tv) { static_assert(N < sizeof...(Tn), "N >= tv.size()"); return static_cast::type&>(tv).head; } } // namespace cppa -#endif // TDATA_HPP +#endif // CPPA_TDATA_HPP diff --git a/cppa/detail/thread.hpp b/cppa/detail/thread.hpp deleted file mode 100644 index b2f1e7a047..0000000000 --- a/cppa/detail/thread.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/******************************************************************************\ - * ___ __ * - * /\_ \ __/\ \ * - * \//\ \ /\_\ \ \____ ___ _____ _____ __ * - * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * - * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * - * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * - * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * - * \ \_\ \ \_\ * - * \/_/ \/_/ * - * * - * Copyright (C) 2011, 2012 * - * Dominik Charousset * - * * - * This file is part of libcppa. * - * libcppa is free software: you can redistribute it and/or modify it under * - * the terms of the GNU Lesser General Public License as published by the * - * Free Software Foundation, either version 3 of the License * - * or (at your option) any later version. * - * * - * libcppa is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with libcppa. If not, see . * -\******************************************************************************/ - - -#ifndef THREAD_HPP -#define THREAD_HPP - -#ifdef __APPLE__ - -#include -#include "cppa/util/duration.hpp" - -namespace cppa { namespace detail { - -using boost::mutex; -using boost::thread; -using boost::lock_guard; -using boost::unique_lock; -using boost::condition_variable; - -namespace this_thread { using namespace boost::this_thread; } - -template -inline bool wait_until(Lock& lock, Condition& cond, - const boost::system_time& timeout) -{ - return cond.timed_wait(lock, timeout); -} - -inline boost::system_time now() -{ - return boost::get_system_time(); -} - -} } // namespace cppa::detail - -inline boost::system_time& operator+=(boost::system_time& lhs, - const cppa::util::duration& rhs) -{ - switch (rhs.unit) - { - case cppa::util::time_unit::seconds: - lhs += boost::posix_time::seconds(rhs.count); - break; - - case cppa::util::time_unit::milliseconds: - lhs += boost::posix_time::milliseconds(rhs.count); - break; - - case cppa::util::time_unit::microseconds: - lhs += boost::posix_time::microseconds(rhs.count); - break; - - default: break; - } - return lhs; -} - -#else - -#include -#include -#include - -namespace cppa { namespace detail { - -using std::mutex; -using std::thread; -using std::lock_guard; -using std::unique_lock; -using std::condition_variable; - -namespace this_thread { using namespace std::this_thread; } - -// returns false if a timeout occured -template -inline bool wait_until(Lock& lock, Condition& cond, const TimePoint& timeout) -{ - return cond.wait_until(lock, timeout) != std::cv_status::timeout; -} - -inline auto now() -> decltype(std::chrono::high_resolution_clock::now()) -{ - return std::chrono::high_resolution_clock::now(); -} - -} } // namespace cppa::detail - -#endif // __APPLE__ - -#endif // THREAD_HPP diff --git a/cppa/detail/thread_pool_scheduler.hpp b/cppa/detail/thread_pool_scheduler.hpp index 6506240fb1..1fb8a78d6b 100644 --- a/cppa/detail/thread_pool_scheduler.hpp +++ b/cppa/detail/thread_pool_scheduler.hpp @@ -28,18 +28,20 @@ \******************************************************************************/ -#ifndef THREAD_POOL_SCHEDULER_HPP -#define THREAD_POOL_SCHEDULER_HPP +#ifndef CPPA_THREAD_POOL_SCHEDULER_HPP +#define CPPA_THREAD_POOL_SCHEDULER_HPP + +#include #include "cppa/scheduler.hpp" -#include "cppa/detail/thread.hpp" +#include "cppa/context_switching_actor.hpp" #include "cppa/util/producer_consumer_list.hpp" +#include "cppa/detail/scheduled_actor_dummy.hpp" #include "cppa/detail/abstract_scheduled_actor.hpp" namespace cppa { namespace detail { -class thread_pool_scheduler : public scheduler -{ +class thread_pool_scheduler : public scheduler { typedef scheduler super; @@ -51,29 +53,50 @@ class thread_pool_scheduler : public scheduler void stop() /*override*/; - void enqueue(abstract_scheduled_actor* what) /*override*/; + void enqueue(scheduled_actor* what) /*override*/; + + actor_ptr spawn(scheduled_actor* what); + + actor_ptr spawn(scheduled_actor* what, init_callback init_cb); - actor_ptr spawn(abstract_event_based_actor* what); + actor_ptr spawn(void_function fun, scheduling_hint hint); - actor_ptr spawn(scheduled_actor* behavior, scheduling_hint hint); + actor_ptr spawn(void_function what, + scheduling_hint hint, + init_callback init_cb); private: //typedef util::single_reader_queue job_queue; - typedef util::producer_consumer_list job_queue; + typedef util::producer_consumer_list job_queue; job_queue m_queue; scheduled_actor_dummy m_dummy; - thread m_supervisor; - - actor_ptr spawn_impl(abstract_scheduled_actor* what, - bool push_to_queue = true); + std::thread m_supervisor; static void worker_loop(worker*); - static void supervisor_loop(job_queue*, abstract_scheduled_actor*); - + static void supervisor_loop(job_queue*, scheduled_actor*); + + actor_ptr spawn_impl(scheduled_actor_ptr what); + + actor_ptr spawn_as_thread(void_function fun, init_callback cb, bool hidden); + +# ifndef CPPA_DISABLE_CONTEXT_SWITCHING + template + actor_ptr spawn_impl(void_function fun, scheduling_hint sh, F cb) { + if (sh == scheduled) { + scheduled_actor_ptr ptr{new context_switching_actor(std::move(fun))}; + ptr->attach_to_scheduler(this); + cb(ptr.get()); + return spawn_impl(std::move(ptr)); + } + else { + return spawn_as_thread(std::move(fun), std::move(cb)); + } + } +# endif }; } } // namespace cppa::detail -#endif // THREAD_POOL_SCHEDULER_HPP +#endif // CPPA_THREAD_POOL_SCHEDULER_HPP diff --git a/cppa/detail/to_uniform_name.hpp b/cppa/detail/to_uniform_name.hpp index 9071df3560..a0191c5f70 100644 --- a/cppa/detail/to_uniform_name.hpp +++ b/cppa/detail/to_uniform_name.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef TO_UNIFORM_NAME_HPP -#define TO_UNIFORM_NAME_HPP +#ifndef CPPA_TO_UNIFORM_NAME_HPP +#define CPPA_TO_UNIFORM_NAME_HPP #include #include @@ -39,6 +39,9 @@ namespace cppa { namespace detail { std::string to_uniform_name(const std::string& demangled_name); std::string to_uniform_name(const std::type_info& tinfo); +template +inline std::string to_uniform_name() { return to_uniform_name(typeid(T)); } + } } // namespace cppa::detail -#endif // TO_UNIFORM_NAME_HPP +#endif // CPPA_TO_UNIFORM_NAME_HPP diff --git a/cppa/detail/tuple_cast_impl.hpp b/cppa/detail/tuple_cast_impl.hpp index 505e359180..d744c7deab 100644 --- a/cppa/detail/tuple_cast_impl.hpp +++ b/cppa/detail/tuple_cast_impl.hpp @@ -28,12 +28,11 @@ \******************************************************************************/ -#ifndef TUPLE_CAST_IMPL_HPP -#define TUPLE_CAST_IMPL_HPP +#ifndef CPPA_TUPLE_CAST_IMPL_HPP +#define CPPA_TUPLE_CAST_IMPL_HPP #include "cppa/pattern.hpp" #include "cppa/any_tuple.hpp" -#include "cppa/type_value_pair.hpp" #include "cppa/detail/matches.hpp" #include "cppa/detail/tuple_vals.hpp" @@ -44,8 +43,7 @@ namespace cppa { namespace detail { -enum class tuple_cast_impl_id -{ +enum class tuple_cast_impl_id { no_wildcard, trailing_wildcard, leading_wildcard, @@ -54,35 +52,29 @@ enum class tuple_cast_impl_id // covers wildcard_in_between and multiple_wildcards template -struct tuple_cast_impl -{ +struct tuple_cast_impl { static constexpr size_t size = util::tl_count_not, is_anything>::value; static constexpr size_t first_wc = static_cast( util::tl_find, anything>::value); typedef util::fixed_vector mapping_vector; - static inline option safe(any_tuple& tup) - { + static inline option safe(any_tuple& tup) { mapping_vector mv; if (matches(tup, mv)) return {Result::from(std::move(tup.vals()), mv)}; return {}; } - static inline option safe(any_tuple& tup, const pattern& p) - { + static inline option safe(any_tuple& tup, const pattern& p) { mapping_vector mv; if (matches(tup, p, mv)) return {Result::from(std::move(tup.vals()), mv)}; return {}; } - static inline option unsafe(any_tuple& tup, const pattern& p) - { + static inline option unsafe(any_tuple& tup, const pattern& p) { mapping_vector mv; - if (WP == wildcard_position::in_between) - { - if (!p.has_values() || matcher::vmatch(tup, p)) - { + if (WP == wildcard_position::in_between) { + if (!p.has_values() || matcher::vmatch(tup, p)) { // first range mv.resize(size); auto begin = mv.begin(); @@ -93,18 +85,15 @@ struct tuple_cast_impl return {Result::from(std::move(tup.vals()), mv)}; } } - else - { + else { if (matches(tup, p, mv)) return {Result::from(std::move(tup.vals()), mv)}; } return {}; } - static inline Result force(any_tuple& tup, const pattern& p) - { + static inline Result force(any_tuple& tup, const pattern& p) { mapping_vector mv; - if (WP == wildcard_position::in_between) - { + if (WP == wildcard_position::in_between) { // first range mv.resize(size); auto begin = mv.begin(); @@ -114,8 +103,7 @@ struct tuple_cast_impl std::iota(begin, mv.end(), tup.size() - (size - first_wc)); return {Result::from(std::move(tup.vals()), mv)}; } - else - { + else { matches(tup, p, mv); return {Result::from(std::move(tup.vals()), mv)}; } @@ -123,84 +111,67 @@ struct tuple_cast_impl }; template -struct tuple_cast_impl -{ - static inline option safe(any_tuple& tup) - { +struct tuple_cast_impl { + static inline option safe(any_tuple& tup) { if (matches(tup)) return {Result::from(std::move(tup.vals()))}; return {}; } - static inline option safe(any_tuple& tup, const pattern& p) - { - if (matches(tup, p)) - { + static inline option safe(any_tuple& tup, const pattern& p) { + if (matches(tup, p)) { return {Result::from(std::move(tup.vals()))}; } return {}; } - static inline option unsafe(any_tuple& tup, const pattern& p) - { + static inline option unsafe(any_tuple& tup, const pattern& p) { if ( p.has_values() == false - || matcher::vmatch(tup, p)) - { + || matcher::vmatch(tup, p)) { return {Result::from(std::move(tup.vals()))}; } return {}; } - static inline Result force(any_tuple& tup, const pattern&) - { + static inline Result force(any_tuple& tup, const pattern&) { return {Result::from(std::move(tup.vals()))}; } }; template struct tuple_cast_impl - : tuple_cast_impl -{ - static inline option unsafe(any_tuple& tup, const pattern& p) - { + : tuple_cast_impl { + static inline option unsafe(any_tuple& tup, const pattern& p) { if ( p.has_values() == false || matcher - ::vmatch(tup, p)) - { + ::vmatch(tup, p)) { return {Result::from(std::move(tup.vals()))}; } return {}; } - static inline Result force(any_tuple& tup, const pattern&) - { + static inline Result force(any_tuple& tup, const pattern&) { return {Result::from(std::move(tup.vals()))}; } }; template -struct tuple_cast_impl -{ - static inline option safe(any_tuple& tup) - { +struct tuple_cast_impl { + static inline option safe(any_tuple& tup) { size_t o = tup.size() - (sizeof...(T) - 1); if (matches(tup)) return {Result::offset_subtuple(tup.vals(), o)}; return {}; } - static inline option safe(any_tuple& tup, const pattern& p) - { + static inline option safe(any_tuple& tup, const pattern& p) { size_t o = tup.size() - (sizeof...(T) - 1); if (matches(tup, p)) return {Result::offset_subtuple(tup.vals(), o)}; return {}; } - static inline option unsafe(any_tuple& tup, const pattern& p) - { + static inline option unsafe(any_tuple& tup, const pattern& p) { if ( p.has_values() == false || matcher - ::vmatch(tup, p)) - { + ::vmatch(tup, p)) { size_t o = tup.size() - (sizeof...(T) - 1); return Result::offset_subtuple(tup.vals(), o); } return {}; } - static inline Result force(any_tuple& tup, const pattern&) - { + static inline Result force(any_tuple& tup, const pattern&) { size_t o = tup.size() - (sizeof...(T) - 1); return Result::offset_subtuple(tup.vals(), o); } @@ -208,4 +179,4 @@ struct tuple_cast_impl } } -#endif // TUPLE_CAST_IMPL_HPP +#endif // CPPA_TUPLE_CAST_IMPL_HPP diff --git a/cppa/detail/tuple_iterator.hpp b/cppa/detail/tuple_iterator.hpp index 5dd2377f7e..b8dbba1197 100644 --- a/cppa/detail/tuple_iterator.hpp +++ b/cppa/detail/tuple_iterator.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef TUPLE_ITERATOR_HPP -#define TUPLE_ITERATOR_HPP +#ifndef CPPA_TUPLE_ITERATOR_HPP +#define CPPA_TUPLE_ITERATOR_HPP #include @@ -38,66 +38,56 @@ namespace cppa { namespace detail { template -class tuple_iterator -{ +class tuple_iterator { size_t m_pos; - Tuple const* m_tuple; + const Tuple* m_tuple; public: - inline tuple_iterator(Tuple const* tup, size_t pos = 0) - : m_pos(pos), m_tuple(tup) - { + inline tuple_iterator(const Tuple* tup, size_t pos = 0) + : m_pos(pos), m_tuple(tup) { } tuple_iterator(const tuple_iterator&) = default; tuple_iterator& operator=(const tuple_iterator&) = default; - inline bool operator==(const tuple_iterator& other) const - { + inline bool operator==(const tuple_iterator& other) const { CPPA_REQUIRE(other.m_tuple == other.m_tuple); return other.m_pos == m_pos; } - inline bool operator!=(const tuple_iterator& other) const - { + inline bool operator!=(const tuple_iterator& other) const { return !(*this == other); } - inline tuple_iterator& operator++() - { + inline tuple_iterator& operator++() { ++m_pos; return *this; } - inline tuple_iterator& operator--() - { + inline tuple_iterator& operator--() { CPPA_REQUIRE(m_pos > 0); --m_pos; return *this; } - inline tuple_iterator operator+(size_t offset) - { + inline tuple_iterator operator+(size_t offset) { return {m_tuple, m_pos + offset}; } - inline tuple_iterator& operator+=(size_t offset) - { + inline tuple_iterator& operator+=(size_t offset) { m_pos += offset; return *this; } - inline tuple_iterator operator-(size_t offset) - { + inline tuple_iterator operator-(size_t offset) { CPPA_REQUIRE(m_pos >= offset); return {m_tuple, m_pos - offset}; } - inline tuple_iterator& operator-=(size_t offset) - { + inline tuple_iterator& operator-=(size_t offset) { CPPA_REQUIRE(m_pos >= offset); m_pos -= offset; return *this; @@ -105,13 +95,11 @@ class tuple_iterator inline size_t position() const { return m_pos; } - inline void const* value() const - { + inline const void* value() const { return m_tuple->at(m_pos); } - inline uniform_type_info const* type() const - { + inline const uniform_type_info* type() const { return m_tuple->type_at(m_pos); } @@ -121,4 +109,4 @@ class tuple_iterator } } // namespace cppa::detail -#endif // TUPLE_ITERATOR_HPP +#endif // CPPA_TUPLE_ITERATOR_HPP diff --git a/cppa/detail/tuple_vals.hpp b/cppa/detail/tuple_vals.hpp index 850a0450d1..97317b0024 100644 --- a/cppa/detail/tuple_vals.hpp +++ b/cppa/detail/tuple_vals.hpp @@ -28,13 +28,11 @@ \******************************************************************************/ -#ifndef TUPLE_VALS_HPP -#define TUPLE_VALS_HPP +#ifndef CPPA_TUPLE_VALS_HPP +#define CPPA_TUPLE_VALS_HPP #include -#include "cppa/type_value_pair.hpp" - #include "cppa/util/type_list.hpp" #include "cppa/detail/tdata.hpp" @@ -45,8 +43,7 @@ namespace cppa { namespace detail { template -class tuple_vals : public abstract_tuple -{ +class tuple_vals : public abstract_tuple { static_assert(sizeof...(ElementTypes) > 0, "tuple_vals is not allowed to be empty"); @@ -64,71 +61,58 @@ class tuple_vals : public abstract_tuple tuple_vals(const tuple_vals&) = default; tuple_vals(const ElementTypes&... args) - : super(tuple_impl_info::statically_typed), m_data(args...) - { + : super(tuple_impl_info::statically_typed), m_data(args...) { } - void const* native_data() const - { + const void* native_data() const { return &m_data; } - void* mutable_native_data() - { + void* mutable_native_data() { return &m_data; } - inline data_type& data() - { + inline data_type& data() { return m_data; } - inline const data_type& data() const - { + inline const data_type& data() const { return m_data; } - size_t size() const - { + size_t size() const { return sizeof...(ElementTypes); } - tuple_vals* copy() const - { + tuple_vals* copy() const { return new tuple_vals(*this); } - void const* at(size_t pos) const - { + const void* at(size_t pos) const { CPPA_REQUIRE(pos < size()); return m_data.at(pos); } - void* mutable_at(size_t pos) - { + void* mutable_at(size_t pos) { CPPA_REQUIRE(pos < size()); return const_cast(at(pos)); } - uniform_type_info const* type_at(size_t pos) const - { + const uniform_type_info* type_at(size_t pos) const { CPPA_REQUIRE(pos < size()); return m_types[pos]; } - bool equals(const abstract_tuple& other) const - { + bool equals(const abstract_tuple& other) const { if (size() != other.size()) return false; - tuple_vals const* o = dynamic_cast(&other); - if (o) - { + const tuple_vals* o = dynamic_cast(&other); + if (o) { return m_data == (o->m_data); } return abstract_tuple::equals(other); } - std::type_info const* type_token() const - { + const std::type_info* type_token() const { return detail::static_type_list::list; } @@ -147,11 +131,10 @@ template struct tuple_vals_from_type_list; template -struct tuple_vals_from_type_list< util::type_list > -{ +struct tuple_vals_from_type_list< util::type_list > { typedef tuple_vals type; }; } } // namespace cppa::detail -#endif // TUPLE_VALS_HPP +#endif // CPPA_TUPLE_VALS_HPP diff --git a/cppa/detail/tuple_view.hpp b/cppa/detail/tuple_view.hpp index 8290bd6146..f0442ca138 100644 --- a/cppa/detail/tuple_view.hpp +++ b/cppa/detail/tuple_view.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef TUPLE_VIEW_HPP -#define TUPLE_VIEW_HPP +#ifndef CPPA_TUPLE_VIEW_HPP +#define CPPA_TUPLE_VIEW_HPP #include "cppa/util/static_foreach.hpp" @@ -38,21 +38,18 @@ namespace cppa { namespace detail { -struct tuple_view_copy_helper -{ +struct tuple_view_copy_helper { size_t pos; abstract_tuple* target; tuple_view_copy_helper(abstract_tuple* trgt) : pos(0), target(trgt) { } template - void operator()(T const* value) - { + void operator()(const T* value) { *(reinterpret_cast(target->mutable_at(pos++))) = *value; } }; template -class tuple_view : public abstract_tuple -{ +class tuple_view : public abstract_tuple { static_assert(sizeof...(ElementTypes) > 0, "tuple_vals is not allowed to be empty"); @@ -72,53 +69,44 @@ class tuple_view : public abstract_tuple * @warning @p tuple_view does @b NOT takes ownership for given pointers */ tuple_view(ElementTypes*... args) - : super(tuple_impl_info::statically_typed), m_data(args...) - { + : super(tuple_impl_info::statically_typed), m_data(args...) { } - inline data_type& data() - { + inline data_type& data() { return m_data; } - inline const data_type& data() const - { + inline const data_type& data() const { return m_data; } - size_t size() const - { + size_t size() const { return sizeof...(ElementTypes); } - abstract_tuple* copy() const - { + abstract_tuple* copy() const { auto result = new tuple_vals; tuple_view_copy_helper f{result}; util::static_foreach<0, sizeof...(ElementTypes)>::_(m_data, f); return result; } - void const* at(size_t pos) const - { + const void* at(size_t pos) const { CPPA_REQUIRE(pos < size()); return m_data.at(pos); } - void* mutable_at(size_t pos) - { + void* mutable_at(size_t pos) { CPPA_REQUIRE(pos < size()); return m_data.mutable_at(pos); } - uniform_type_info const* type_at(size_t pos) const - { + const uniform_type_info* type_at(size_t pos) const { CPPA_REQUIRE(pos < size()); return m_types[pos]; } - std::type_info const* type_token() const - { + const std::type_info* type_token() const { return detail::static_type_list::list; } @@ -135,4 +123,4 @@ types_array tuple_view::m_types; } } // namespace cppa::detail -#endif // TUPLE_VIEW_HPP +#endif // CPPA_TUPLE_VIEW_HPP diff --git a/cppa/detail/type_to_ptype.hpp b/cppa/detail/type_to_ptype.hpp index 629c39fb1c..26e8ceff0e 100644 --- a/cppa/detail/type_to_ptype.hpp +++ b/cppa/detail/type_to_ptype.hpp @@ -28,9 +28,10 @@ \******************************************************************************/ -#ifndef TYPE_TO_PTYPE_HPP -#define TYPE_TO_PTYPE_HPP +#ifndef CPPA_TYPE_TO_PTYPE_HPP +#define CPPA_TYPE_TO_PTYPE_HPP +#include #include #include @@ -40,14 +41,12 @@ namespace cppa { namespace detail { // if (IfStmt == true) ptype = PT; else ptype = Else::ptype; template -struct if_else_ptype_c -{ +struct if_else_ptype_c { static const primitive_type ptype = PT; }; template -struct if_else_ptype_c -{ +struct if_else_ptype_c { static const primitive_type ptype = Else::ptype; }; @@ -80,13 +79,11 @@ struct type_to_ptype_impl : if_else_ptype, pt_u16string, if_else_ptype, pt_u32string, // default case - wrapped_ptype > > > > > > > > > > > > > > -{ + wrapped_ptype > > > > > > > > > > > > > > { }; template -struct type_to_ptype -{ +struct type_to_ptype { typedef typename std::remove_cv::type>::type type; @@ -96,4 +93,4 @@ struct type_to_ptype } } // namespace cppa::detail -#endif // TYPE_TO_PTYPE_HPP +#endif // CPPA_TYPE_TO_PTYPE_HPP diff --git a/cppa/detail/types_array.hpp b/cppa/detail/types_array.hpp index 687d88e306..a0fc64190a 100644 --- a/cppa/detail/types_array.hpp +++ b/cppa/detail/types_array.hpp @@ -1,17 +1,45 @@ -#ifndef TYPES_ARRAY_HPP -#define TYPES_ARRAY_HPP +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + + +#ifndef CPPA_TYPES_ARRAY_HPP +#define CPPA_TYPES_ARRAY_HPP #include -#include "cppa/type_value_pair.hpp" - #include "cppa/util/type_list.hpp" #include "cppa/util/is_builtin.hpp" // forward declarations namespace cppa { class uniform_type_info; -uniform_type_info const* uniform_typeid(const std::type_info&); +const uniform_type_info* uniform_typeid(const std::type_info&); } // namespace cppa namespace cppa { namespace detail { @@ -23,121 +51,102 @@ template struct ta_util; template -struct ta_util -{ - static inline std::type_info const* get() { return &(typeid(T)); } +struct ta_util { + static inline const std::type_info* get() { return &(typeid(T)); } }; template<> -struct ta_util -{ - static inline std::type_info const* get() { return nullptr; } +struct ta_util { + static inline const std::type_info* get() { return nullptr; } }; template -struct ta_util -{ - static inline uniform_type_info const* get() - { +struct ta_util { + static inline const uniform_type_info* get() { return uniform_typeid(typeid(T)); } }; template<> -struct ta_util -{ - static inline uniform_type_info const* get() { return nullptr; } +struct ta_util { + static inline const uniform_type_info* get() { return nullptr; } }; template -struct ta_util -{ - static inline uniform_type_info const* get() { return nullptr; } +struct ta_util { + static inline const uniform_type_info* get() { return nullptr; } }; +// only built-in types are guaranteed to be available at static initialization +// time, other types are announced at runtime + // implements types_array template -struct types_array_impl -{ +struct types_array_impl { static constexpr bool builtin_only = true; + inline bool is_pure() const { return true; } // all types are builtin, perform lookup on constuction - uniform_type_info const* data[sizeof...(T)]; - types_array_impl() - : data{ta_util::value,T>::get()...} - { - } - inline uniform_type_info const* operator[](size_t p) const - { + const uniform_type_info* data[sizeof...(T)]; + types_array_impl() : data{ta_util::get()...} { } + inline const uniform_type_info* operator[](size_t p) const { return data[p]; } - typedef uniform_type_info const* const* const_iterator; + typedef const uniform_type_info* const* const_iterator; inline const_iterator begin() const { return std::begin(data); } inline const_iterator end() const { return std::end(data); } }; template -struct types_array_impl -{ +struct types_array_impl { static constexpr bool builtin_only = false; + inline bool is_pure() const { return false; } // contains std::type_info for all non-builtin types - std::type_info const* tinfo_data[sizeof...(T)]; + const std::type_info* tinfo_data[sizeof...(T)]; // contains uniform_type_infos for builtin types and lazy initializes // non-builtin types at runtime - mutable std::atomic data[sizeof...(T)]; - mutable std::atomic pairs; + mutable std::atomic data[sizeof...(T)]; + mutable std::atomic pairs; // pairs[sizeof...(T)]; types_array_impl() - : tinfo_data{ta_util::value,T>::get()...} - { + : tinfo_data{ta_util::value,T>::get()...} { bool static_init[sizeof...(T)] = { !std::is_same::value && util::is_builtin::value ... }; - for (size_t i = 0; i < sizeof...(T); ++i) - { - if (static_init[i]) - { + for (size_t i = 0; i < sizeof...(T); ++i) { + if (static_init[i]) { data[i].store(uniform_typeid(*(tinfo_data[i])), std::memory_order_relaxed); } } } - inline uniform_type_info const* operator[](size_t p) const - { + inline const uniform_type_info* operator[](size_t p) const { auto result = data[p].load(); - if (result == nullptr) - { + if (result == nullptr) { auto tinfo = tinfo_data[p]; - if (tinfo != nullptr) - { + if (tinfo != nullptr) { result = uniform_typeid(*tinfo); data[p].store(result, std::memory_order_relaxed); } } return result; } - typedef uniform_type_info const* const* const_iterator; - inline const_iterator begin() const - { + typedef const uniform_type_info* const* const_iterator; + inline const_iterator begin() const { auto result = pairs.load(); - if (result == nullptr) - { - auto parr = new uniform_type_info const*[sizeof...(T)]; - for (size_t i = 0; i < sizeof...(T); ++i) - { + if (result == nullptr) { + auto parr = new const uniform_type_info*[sizeof...(T)]; + for (size_t i = 0; i < sizeof...(T); ++i) { parr[i] = (*this)[i]; } - if (!pairs.compare_exchange_weak(result, parr, std::memory_order_relaxed)) - { + if (!pairs.compare_exchange_weak(result, parr, std::memory_order_relaxed)) { delete[] parr; } - else - { + else { result = parr; } } return result; } - inline const_iterator end() const - { + inline const_iterator end() const { return begin() + sizeof...(T); } }; @@ -147,8 +156,7 @@ struct types_array_impl template struct types_array : types_array_impl, util::is_builtin>::value, - T...> -{ + T...> { static constexpr size_t size = sizeof...(T); typedef util::type_list types; typedef typename util::tl_filter_not::type @@ -159,8 +167,7 @@ struct types_array : types_array_impl, // utility for singleton-like access to a types_array template -struct static_types_array -{ +struct static_types_array { static types_array arr; }; @@ -171,21 +178,19 @@ template struct static_types_array_from_type_list; template -struct static_types_array_from_type_list> -{ +struct static_types_array_from_type_list> { typedef static_types_array type; }; // utility for singleton-like access to a type_info instance of a type_list template -struct static_type_list -{ - static std::type_info const* list; +struct static_type_list { + static const std::type_info* list; }; template -std::type_info const* static_type_list::list = &typeid(util::type_list); +const std::type_info* static_type_list::list = &typeid(util::type_list); } } // namespace cppa::detail -#endif // TYPES_ARRAY_HPP +#endif // CPPA_TYPES_ARRAY_HPP diff --git a/cppa/detail/unboxed.hpp b/cppa/detail/unboxed.hpp index 2d26abab5d..9e82e24050 100644 --- a/cppa/detail/unboxed.hpp +++ b/cppa/detail/unboxed.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef UNBOXED_HPP -#define UNBOXED_HPP +#ifndef CPPA_UNBOXED_HPP +#define CPPA_UNBOXED_HPP #include @@ -39,41 +39,35 @@ namespace cppa { namespace detail { template -struct unboxed -{ +struct unboxed { typedef T type; }; template -struct unboxed< util::wrapped > -{ +struct unboxed< util::wrapped > { typedef typename util::wrapped::type type; }; template -struct unboxed (&)()> -{ +struct unboxed (&)()> { typedef typename util::wrapped::type type; }; template -struct unboxed ()> -{ +struct unboxed ()> { typedef typename util::wrapped::type type; }; template -struct unboxed (*)()> -{ +struct unboxed (*)()> { typedef typename util::wrapped::type type; }; template -struct unboxed>> -{ +struct unboxed>> { typedef T type; }; } } // namespace cppa::detail -#endif // UNBOXED_HPP +#endif // CPPA_UNBOXED_HPP diff --git a/cppa/detail/uniform_type_info_map.hpp b/cppa/detail/uniform_type_info_map.hpp index 0f4d65236f..b6a204f059 100644 --- a/cppa/detail/uniform_type_info_map.hpp +++ b/cppa/detail/uniform_type_info_map.hpp @@ -28,13 +28,15 @@ \******************************************************************************/ -#ifndef UNIFORM_TYPE_INFO_MAP_HPP -#define UNIFORM_TYPE_INFO_MAP_HPP +#ifndef CPPA_UNIFORM_TYPE_INFO_MAP_HPP +#define CPPA_UNIFORM_TYPE_INFO_MAP_HPP #include #include #include // std::pair +#include "cppa/detail/default_uniform_type_info_impl.hpp" + namespace cppa { class uniform_type_info; } namespace cppa { namespace detail { @@ -42,33 +44,29 @@ namespace cppa { namespace detail { class uniform_type_info_map_helper; // note: this class is implemented in uniform_type_info.cpp -class uniform_type_info_map -{ +class uniform_type_info_map { friend class uniform_type_info_map_helper; public: - typedef std::set string_set; - - typedef std::map uti_map; - - typedef std::map< int, std::pair > int_map; + typedef std::set set_type; + typedef std::map uti_map_type; + typedef std::map > int_map_type; uniform_type_info_map(); ~uniform_type_info_map(); - inline const int_map& int_names() const - { + inline const int_map_type& int_names() const { return m_ints; } - uniform_type_info* by_raw_name(const std::string& name) const; + const uniform_type_info* by_raw_name(const std::string& name) const; - uniform_type_info* by_uniform_name(const std::string& name) const; + const uniform_type_info* by_uniform_name(const std::string& name) const; - std::vector get_all() const; + std::vector get_all() const; // NOT thread safe! bool insert(const std::set& raw_names, uniform_type_info* uti); @@ -76,16 +74,16 @@ class uniform_type_info_map private: // maps raw typeid names to uniform type informations - uti_map m_by_rname; + uti_map_type m_by_rname; // maps uniform names to uniform type informations - uti_map m_by_uname; + uti_map_type m_by_uname; // maps sizeof(-integer_type-) to { signed-names-set, unsigned-names-set } - int_map m_ints; + int_map_type m_ints; }; } } // namespace cppa::detail -#endif // UNIFORM_TYPE_INFO_MAP_HPP +#endif // CPPA_UNIFORM_TYPE_INFO_MAP_HPP diff --git a/cppa/detail/value_guard.hpp b/cppa/detail/value_guard.hpp index da514ef3ec..1446360be0 100644 --- a/cppa/detail/value_guard.hpp +++ b/cppa/detail/value_guard.hpp @@ -28,8 +28,10 @@ \******************************************************************************/ -#ifndef VALUE_GUARD_HPP -#define VALUE_GUARD_HPP +#ifndef CPPA_VALUE_GUARD_HPP +#define CPPA_VALUE_GUARD_HPP + +#include #include "cppa/util/rm_ref.hpp" #include "cppa/util/void_type.hpp" @@ -41,16 +43,14 @@ namespace cppa { namespace detail { template -struct vg_fwd_ -{ +struct vg_fwd_ { static inline const T& _(const T& arg) { return arg; } static inline T&& _(T&& arg) { return std::move(arg); } static inline T& _(T& arg) { return arg; } }; template -struct vg_fwd_ -{ +struct vg_fwd_ { template static inline util::void_type _(Arg&&) { return {}; } }; @@ -59,34 +59,27 @@ struct vg_fwd_ template struct vg_fwd : vg_fwd_::type>::value, - typename util::rm_ref::type> -{ + typename util::rm_ref::type> { }; -template -class value_guard -{ - typename tdata_from_type_list::type m_args; - - template - inline bool _eval(const util::void_type&, const tdata<>&, Args&&...) const - { - return true; +template +struct vg_cmp { + template + inline static bool _(const T& lhs, const U& rhs) { + return lhs == rhs; } +}; - template - inline bool _eval(const util::void_type&, const Tail& tail, - const Arg0&, const Args&... args ) const - { - return _eval(tail.head, tail.tail(), args...); +template<> +struct vg_cmp { + template + inline static bool _(const util::void_type&, const T&) { + return true; } +}; - template - inline bool _eval(const Head& head, const Tail& tail, - const Arg0& arg0, const Args&... args) const - { - return head == arg0 && _eval(tail.head, tail.tail(), args...); - } +template +class value_guard { public: @@ -94,17 +87,48 @@ class value_guard value_guard(const value_guard&) = default; template - value_guard(const Args&... args) : m_args(vg_fwd::_(args)...) - { + value_guard(const Args&... args) : m_args(vg_fwd::_(args)...) { } template - inline bool operator()(const Args&... args) const - { + inline bool operator()(const Args&... args) const { return _eval(m_args.head, m_args.tail(), args...); } + + private: + + typename tdata_from_type_list::type m_args; + + template + static inline bool cmp(const T& lhs, const U& rhs) { + return vg_cmp::_(lhs, rhs); + } + + template + static inline bool cmp(const T& lhs, const std::reference_wrapper& rhs) { + return vg_cmp::_(lhs, rhs.get()); + } + + static inline bool _eval(const util::void_type&, const tdata<>&) { + return true; + } + + template + static inline bool _eval(const Head& head, const tdata<>&, + const Arg0& arg0, const Args&...) { + return cmp(head, arg0); + } + + template + static inline bool _eval(const Head& head, const tdata& tail, + const Arg0& arg0, const Args&... args) { + return cmp(head, arg0) && _eval(tail.head, tail.tail(), args...); + } + }; } } // namespace cppa::detail -#endif // VALUE_GUARD_HPP +#endif // CPPA_VALUE_GUARD_HPP diff --git a/cppa/detail/yield_interface.hpp b/cppa/detail/yield_interface.hpp index e47a0b4e91..e118d10dbe 100644 --- a/cppa/detail/yield_interface.hpp +++ b/cppa/detail/yield_interface.hpp @@ -28,15 +28,14 @@ \******************************************************************************/ -#ifndef YIELD_INTERFACE_HPP -#define YIELD_INTERFACE_HPP +#ifndef CPPA_YIELD_INTERFACE_HPP +#define CPPA_YIELD_INTERFACE_HPP #include "cppa/util/fiber.hpp" namespace cppa { namespace detail { -enum class yield_state : int -{ +enum class yield_state : int { // yield() wasn't called yet invalid, // actor is still ready @@ -55,4 +54,4 @@ yield_state call(util::fiber* what, util::fiber* from); } } // namespace cppa::detail -#endif // YIELD_INTERFACE_HPP +#endif // CPPA_YIELD_INTERFACE_HPP diff --git a/cppa/either.hpp b/cppa/either.hpp index 5f11bda61d..d975efac86 100644 --- a/cppa/either.hpp +++ b/cppa/either.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef EITHER_HPP -#define EITHER_HPP +#ifndef CPPA_EITHER_HPP +#define CPPA_EITHER_HPP #include #include @@ -42,8 +42,7 @@ namespace cppa { * @brief Represents either a @p Left or a @p Right. */ template -class either -{ +class either { static_assert( std::is_convertible::value == false && std::is_convertible::value == false, @@ -79,29 +78,24 @@ class either */ either(Right&& value) : m_is_left(false) { cr_right(std::move(value)); } - either(const either& other) : m_is_left(other.m_is_left) - { + either(const either& other) : m_is_left(other.m_is_left) { if (other.m_is_left) cr_left(other.m_left); else cr_right(other.m_right); } - either(either&& other) : m_is_left(other.m_is_left) - { + either(either&& other) : m_is_left(other.m_is_left) { if (other.m_is_left) cr_left(std::move(other.m_left)); else cr_right(std::move(other.m_right)); } ~either() { destroy(); } - either& operator=(const either& other) - { - if (m_is_left == other.m_is_left) - { + either& operator=(const either& other) { + if (m_is_left == other.m_is_left) { if (m_is_left) m_left = other.m_left; else m_right = other.m_right; } - else - { + else { destroy(); m_is_left = other.m_is_left; if (other.m_is_left) cr_left(other.m_left); @@ -110,15 +104,12 @@ class either return *this; } - either& operator=(either&& other) - { - if (m_is_left == other.m_is_left) - { + either& operator=(either&& other) { + if (m_is_left == other.m_is_left) { if (m_is_left) m_left = std::move(other.m_left); else m_right = std::move(other.m_right); } - else - { + else { destroy(); m_is_left = other.m_is_left; if (other.m_is_left) cr_left(std::move(other.m_left)); @@ -140,8 +131,7 @@ class either /** * @brief Returns this @p either as a @p Left. */ - inline Left& left() - { + inline Left& left() { CPPA_REQUIRE(m_is_left); return m_left; } @@ -149,8 +139,7 @@ class either /** * @brief Returns this @p either as a @p Left. */ - inline const left_type& left() const - { + inline const left_type& left() const { CPPA_REQUIRE(m_is_left); return m_left; } @@ -158,8 +147,7 @@ class either /** * @brief Returns this @p either as a @p Right. */ - inline Right& right() - { + inline Right& right() { CPPA_REQUIRE(!m_is_left); return m_right; } @@ -167,8 +155,7 @@ class either /** * @brief Returns this @p either as a @p Right. */ - inline const right_type& right() const - { + inline const right_type& right() const { CPPA_REQUIRE(!m_is_left); return m_right; } @@ -177,27 +164,23 @@ class either bool m_is_left; - union - { + union { left_type m_left; right_type m_right; }; - void destroy() - { + void destroy() { if (m_is_left) m_left.~Left(); else m_right.~Right(); } template - void cr_left(L&& value) - { + void cr_left(L&& value) { new (&m_left) left_type (std::forward(value)); } template - void cr_right(R&& value) - { + void cr_right(R&& value) { new (&m_right) right_type (std::forward(value)); } @@ -205,10 +188,8 @@ class either /** @relates either */ template -bool operator==(const either& lhs, const either& rhs) -{ - if (lhs.is_left() == rhs.is_left()) - { +bool operator==(const either& lhs, const either& rhs) { + if (lhs.is_left() == rhs.is_left()) { if (lhs.is_left()) return lhs.left() == rhs.left(); else return lhs.right() == rhs.right(); } @@ -217,67 +198,58 @@ bool operator==(const either& lhs, const either& rhs) /** @relates either */ template -bool operator==(const either& lhs, const Left& rhs) -{ +bool operator==(const either& lhs, const Left& rhs) { return lhs.is_left() && lhs.left() == rhs; } /** @relates either */ template -bool operator==(const Left& lhs, const either& rhs) -{ +bool operator==(const Left& lhs, const either& rhs) { return rhs == lhs; } /** @relates either */ template -bool operator==(const either& lhs, const Right& rhs) -{ +bool operator==(const either& lhs, const Right& rhs) { return lhs.is_right() && lhs.right() == rhs; } /** @relates either */ template -bool operator==(const Right& lhs, const either& rhs) -{ +bool operator==(const Right& lhs, const either& rhs) { return rhs == lhs; } /** @relates either */ template -bool operator!=(const either& lhs, const either& rhs) -{ +bool operator!=(const either& lhs, const either& rhs) { return !(lhs == rhs); } /** @relates either */ template -bool operator!=(const either& lhs, const Left& rhs) -{ +bool operator!=(const either& lhs, const Left& rhs) { return !(lhs == rhs); } /** @relates either */ template -bool operator!=(const Left& lhs, const either& rhs) -{ +bool operator!=(const Left& lhs, const either& rhs) { return !(rhs == lhs); } /** @relates either */ template -bool operator!=(const either& lhs, const Right& rhs) -{ +bool operator!=(const either& lhs, const Right& rhs) { return !(lhs == rhs); } /** @relates either */ template -bool operator!=(const Right& lhs, const either& rhs) -{ +bool operator!=(const Right& lhs, const either& rhs) { return !(rhs == lhs); } } // namespace cppa -#endif // EITHER_HPP +#endif // CPPA_EITHER_HPP diff --git a/cppa/event_based_actor.hpp b/cppa/event_based_actor.hpp index a029b81668..44a6a51ff9 100644 --- a/cppa/event_based_actor.hpp +++ b/cppa/event_based_actor.hpp @@ -28,40 +28,133 @@ \******************************************************************************/ -#ifndef EVENT_BASED_ACTOR_HPP -#define EVENT_BASED_ACTOR_HPP +#ifndef CPPA_ABSTRACT_EVENT_BASED_ACTOR_HPP +#define CPPA_ABSTRACT_EVENT_BASED_ACTOR_HPP +#include +#include +#include +#include + +#include "cppa/config.hpp" +#include "cppa/either.hpp" +#include "cppa/pattern.hpp" #include "cppa/behavior.hpp" -#include "cppa/event_based_actor_base.hpp" +#include "cppa/detail/receive_policy.hpp" +#include "cppa/detail/behavior_stack.hpp" +#include "cppa/detail/abstract_scheduled_actor.hpp" namespace cppa { +#ifdef CPPA_DOCUMENTATION /** - * @brief Base class for non-stacked event-based actor implementations. + * @brief Base class for all event-based actor implementations. */ -class event_based_actor : public event_based_actor_base -{ +class event_based_actor : public scheduled_actor { +#else // CPPA_DOCUMENTATION +class event_based_actor : public detail::abstract_scheduled_actor { +#endif // CPPA_DOCUMENTATION + + friend class detail::receive_policy; + typedef detail::abstract_scheduled_actor super; - friend class event_based_actor_base; + public: - typedef abstract_event_based_actor::stack_element stack_element; + /** + * @brief Finishes execution with exit reason + * {@link exit_reason::unallowed_function_call unallowed_function_call}. + */ + void dequeue(behavior&); //override - // has_ownership == false - void do_become(behavior* bhvr, bool has_ownership); + /** + * @copydoc dequeue(behavior&) + */ + void dequeue(partial_function&); //override - public: + resume_result resume(util::fiber*); //override + + /** + * @brief Initializes the actor. + */ + virtual void init() = 0; + + void quit(std::uint32_t reason = exit_reason::normal); + + void unbecome(); + + bool has_behavior(); + + scheduled_actor_type impl_type(); + + protected: event_based_actor(); + // provoke compiler errors for usage of receive() and related functions + + /** + * @brief Provokes a compiler error to ensure that an event-based actor + * does not accidently uses receive() instead of become(). + */ + template + void receive(Args&&...) { + static_assert((sizeof...(Args) + 1) < 1, + "You shall not use receive in an event-based actor. " + "Use become() instead."); + } + + /** + * @brief Provokes a compiler error. + */ + template + void receive_loop(Args&&... args) { + receive(std::forward(args)...); + } + /** - * @brief Terminates this actor with normal exit reason. + * @brief Provokes a compiler error. */ - void become_void(); + template + void receive_while(Args&&... args) { + receive(std::forward(args)...); + } + + /** + * @brief Provokes a compiler error. + */ + template + void do_receive(Args&&... args) { + receive(std::forward(args)...); + } + + void do_become(behavior* bhvr, bool owns_bhvr, bool discard_old); + + private: + + inline behavior& get_behavior() { + CPPA_REQUIRE(m_bhvr_stack.empty() == false); + return m_bhvr_stack.back(); + } + + // required by detail::nestable_receive_policy + static const detail::receive_policy_flag receive_flag = detail::rp_callback; + inline void handle_timeout(behavior& bhvr) { + CPPA_REQUIRE(bhvr.timeout().valid()); + m_has_pending_timeout_request = false; + bhvr.handle_timeout(); + if (m_bhvr_stack.empty() == false) { + request_timeout(get_behavior().timeout()); + } + } - void quit(std::uint32_t reason); + // stack elements are moved to m_erased_stack_elements and erased later + // to prevent possible segfaults that can occur if a currently executed + // lambda gets deleted + detail::behavior_stack m_bhvr_stack; + detail::receive_policy m_policy; }; } // namespace cppa -#endif // EVENT_BASED_ACTOR_HPP +#endif // CPPA_ABSTRACT_EVENT_BASED_ACTOR_HPP diff --git a/cppa/exception.hpp b/cppa/exception.hpp index 4db2d54f7b..11cb8eae1f 100644 --- a/cppa/exception.hpp +++ b/cppa/exception.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef EXCEPTION_HPP -#define EXCEPTION_HPP +#ifndef CPPA_EXCEPTION_HPP +#define CPPA_EXCEPTION_HPP #include #include @@ -41,8 +41,7 @@ namespace cppa { /** * @brief Base class for libcppa exceptions. */ -class exception : public std::exception -{ +class exception : public std::exception { public: @@ -52,7 +51,7 @@ class exception : public std::exception * @brief Returns the error message. * @returns The error message as C-string. */ - char const* what() const throw(); + const char* what() const throw(); protected: @@ -77,8 +76,7 @@ class exception : public std::exception /** * @brief Thrown if an actor finished execution. */ -class actor_exited : public exception -{ +class actor_exited : public exception { public: @@ -101,8 +99,7 @@ class actor_exited : public exception * @brief Thrown to indicate that either an actor publishing failed or * @p libcppa was unable to connect to a remote host. */ -class network_error : public exception -{ +class network_error : public exception { public: @@ -115,8 +112,7 @@ class network_error : public exception * @brief Thrown to indicate that an actor publishing failed because * the requested port could not be used. */ -class bind_failure : public network_error -{ +class bind_failure : public network_error { public: @@ -134,16 +130,14 @@ class bind_failure : public network_error }; -inline std::uint32_t actor_exited::reason() const throw() -{ +inline std::uint32_t actor_exited::reason() const throw() { return m_reason; } -inline int bind_failure::error_code() const throw() -{ +inline int bind_failure::error_code() const throw() { return m_errno; } } // namespace cppa -#endif // EXCEPTION_HPP +#endif // CPPA_EXCEPTION_HPP diff --git a/cppa/exit_reason.hpp b/cppa/exit_reason.hpp index 2a52e6282b..7201ecd6fb 100644 --- a/cppa/exit_reason.hpp +++ b/cppa/exit_reason.hpp @@ -28,16 +28,11 @@ \******************************************************************************/ -#ifndef EXIT_REASON_HPP -#define EXIT_REASON_HPP +#ifndef CPPA_EXIT_REASON_HPP +#define CPPA_EXIT_REASON_HPP #include -/** - * @namespace cppa::exit_reason - * @brief This naemspace contains all predefined exit reasons. - */ - namespace cppa { namespace exit_reason { /** @@ -78,4 +73,4 @@ static constexpr std::uint32_t user_defined = 0x10000; } } // namespace cppa::exit_reason -#endif // EXIT_REASON_HPP +#endif // CPPA_EXIT_REASON_HPP diff --git a/cppa/detail/converted_thread_context.hpp b/cppa/factory.hpp similarity index 55% rename from cppa/detail/converted_thread_context.hpp rename to cppa/factory.hpp index 40d55ae18d..78e4460ba6 100644 --- a/cppa/detail/converted_thread_context.hpp +++ b/cppa/factory.hpp @@ -28,81 +28,64 @@ \******************************************************************************/ -#ifndef CONVERTED_THREAD_CONTEXT_HPP -#define CONVERTED_THREAD_CONTEXT_HPP +#ifndef CPPA_FACTORY_HPP +#define CPPA_FACTORY_HPP -#include "cppa/config.hpp" +#include "cppa/detail/event_based_actor_factory.hpp" -#include -#include -#include -#include -#include -#include -#include -#include +namespace cppa { namespace factory { -#include "cppa/atom.hpp" -#include "cppa/either.hpp" -#include "cppa/pattern.hpp" -#include "cppa/local_actor.hpp" -#include "cppa/exit_reason.hpp" -#include "cppa/abstract_actor.hpp" -#include "cppa/intrusive/singly_linked_list.hpp" - -namespace cppa { namespace detail { +#ifdef CPPA_DOCUMENTATION /** - * @brief Represents a thread that was converted to an Actor. + * @brief Returns a factory for event-based actors using @p fun as + * implementation for {@link cppa::event_based_actor::init() init()}. + * + * @p fun must take pointer arguments only. The factory creates an event-based + * actor implementation with member variables according to the functor's + * signature, as shown in the example below. + * + * @code + * auto f = factory::event_based([](int* a, int* b) { ... }); + * auto actor1 = f.spawn(); + * auto actor2 = f.spawn(1); + * auto actor3 = f.spawn(1, 2); + * @endcode + * + * The arguments @p a and @p b will point to @p int member variables of the + * actor. All member variables are initialized using the default constructor + * unless an initial value is passed to @p spawn. */ -class converted_thread_context : public abstract_actor -{ - - typedef abstract_actor super; - typedef super::queue_node queue_node; - typedef super::queue_node_ptr queue_node_ptr; - - public: - - converted_thread_context(); - - // called if the converted thread finished execution - void cleanup(std::uint32_t reason = exit_reason::normal); - - void quit(std::uint32_t reason); //override - - void enqueue(actor* sender, any_tuple&& msg); //override +template +auto event_based(InitFun fun); - void enqueue(actor* sender, const any_tuple& msg); //override - - void dequeue(behavior& rules); //override - - void dequeue(partial_function& rules) ; //override - - inline decltype(m_mailbox)& mailbox() - { - return m_mailbox; - } - - private: - - typedef intrusive::singly_linked_list queue_node_buffer; +/** + * @brief Returns a factory for event-based actors using @p fun0 as + * implementation for {@link cppa::event_based_actor::init() init()} + * and @p fun1 as implementation for + * {@link cppa::event_based_actor::on_exit() on_exit()}. + */ +template +auto event_based(InitFun fun0, OnExitFun fun1); - enum throw_on_exit_result - { - not_an_exit_signal, - normal_exit_signal - }; +#else // CPPA_DOCUMENTATION - // returns true if node->msg was accepted by rules - bool dq(queue_node& node, partial_function& rules); +void default_cleanup(); - throw_on_exit_result throw_on_exit(const any_tuple& msg); +template +inline typename detail::ebaf_from_functor::type +event_based(InitFun init) { + return {std::move(init), default_cleanup}; +} - pattern m_exit_msg_pattern; +template +inline typename detail::ebaf_from_functor::type +event_based(InitFun init, OnExitFun on_exit) { + return {std::move(init), on_exit}; +} -}; +#endif // CPPA_DOCUMENTATION -} } // namespace cppa::detail +} } // namespace cppa::factory -#endif // CONVERTED_THREAD_CONTEXT_HPP +#endif // CPPA_FACTORY_HPP diff --git a/cppa/from_string.hpp b/cppa/from_string.hpp index 214fb1a5a8..e3ed33883d 100644 --- a/cppa/from_string.hpp +++ b/cppa/from_string.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef FROM_STRING_HPP -#define FROM_STRING_HPP +#ifndef CPPA_FROM_STRING_HPP +#define CPPA_FROM_STRING_HPP #include #include @@ -40,19 +40,29 @@ namespace cppa { +/** + * @brief Converts a string created by {@link cppa::to_string to_string} + * to its original value. + * @param what String representation of a serialized value. + * @returns An {@link cppa::object object} instance that contains + * the deserialized value. + */ object from_string(const std::string& what); +/** + * @brief Convenience function that deserializes a value from @p what and + * converts the result to @p T. + * @throws std::logic_error if the result is not of type @p T. + * @returns The deserialized value as instance of @p T. + */ template -T from_string(const std::string &what) -{ +T from_string(const std::string& what) { object o = from_string(what); const std::type_info& tinfo = typeid(T); - if (tinfo == *(o.type())) - { - return std::move(get(o)); + if (tinfo == *(o.type())) { + return std::move(get_ref(o)); } - else - { + else { std::string error_msg = "expected type name "; error_msg += uniform_typeid(tinfo)->name(); error_msg += " found "; @@ -63,4 +73,4 @@ T from_string(const std::string &what) } // namespace cppa -#endif // FROM_STRING_HPP +#endif // CPPA_FROM_STRING_HPP diff --git a/cppa/get.hpp b/cppa/get.hpp index 704337ecf6..fa82f3cf95 100644 --- a/cppa/get.hpp +++ b/cppa/get.hpp @@ -28,8 +28,11 @@ \******************************************************************************/ -#ifndef GET_HPP -#define GET_HPP +#ifndef CPPA_GET_HPP +#define CPPA_GET_HPP + +// functions are documented in the implementation headers +#ifndef CPPA_DOCUMENTATION #include @@ -40,7 +43,7 @@ namespace cppa { // forward declaration of details namespace detail { -template class tdata; +template struct tdata; template struct pseudo_tuple; } @@ -73,11 +76,11 @@ typename util::at::type& get_ref(detail::pseudo_tuple& tv); // support container-like access for type lists containing tokens template -typename util::at::type get(const util::type_list&) -{ +typename util::at::type get(const util::type_list&) { return {}; } } // namespace cppa -#endif // GET_HPP +#endif // CPPA_DOCUMENTATION +#endif // CPPA_GET_HPP diff --git a/cppa/group.hpp b/cppa/group.hpp index 223b4c9a86..50b698c929 100644 --- a/cppa/group.hpp +++ b/cppa/group.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef GROUP_HPP -#define GROUP_HPP +#ifndef CPPA_GROUP_HPP +#define CPPA_GROUP_HPP #include #include @@ -45,8 +45,7 @@ namespace cppa { /** * @brief A multicast group. */ -class group : public channel -{ +class group : public channel { friend class detail::group_manager; @@ -69,8 +68,7 @@ class group : public channel friend class unsubscriber; // unsubscribes its channel from the group on destruction - class unsubscriber : public attachable - { + class unsubscriber : public attachable { friend class group; @@ -95,15 +93,13 @@ class group : public channel /** * @brief Module interface. */ - class module - { + class module { std::string m_name; protected: - module(std::string&& module_name); - module(const std::string& module_name); + module(std::string module_name); public: @@ -170,9 +166,10 @@ class group : public channel /** * @brief A smart pointer type that manages instances of {@link group}. + * @relates group */ typedef intrusive_ptr group_ptr; } // namespace cppa -#endif // GROUP_HPP +#endif // CPPA_GROUP_HPP diff --git a/cppa/guard_expr.hpp b/cppa/guard_expr.hpp index c7bcc3c044..329c3c0a0d 100644 --- a/cppa/guard_expr.hpp +++ b/cppa/guard_expr.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef GUARD_EXPR_HPP -#define GUARD_EXPR_HPP +#ifndef CPPA_GUARD_EXPR_HPP +#define CPPA_GUARD_EXPR_HPP #include #include @@ -49,8 +49,7 @@ namespace cppa { -enum operator_id -{ +enum operator_id { // arithmetic operators addition_op, subtraction_op, multiplication_op, division_op, modulo_op, // comparison operators @@ -67,8 +66,7 @@ enum operator_id // {operator, lhs, rhs} expression template -struct guard_expr -{ +struct guard_expr { typedef First first_type; typedef Second second_type; @@ -78,24 +76,21 @@ struct guard_expr template guard_expr(T0&& a0, T1&& a1) - : m_args(std::forward(a0), std::forward(a1)) - { + : m_args(std::forward(a0), std::forward(a1)) { } // {operator, {operator, a0, a1}, a2} template guard_expr(T0&& a0, T1&& a1, T2&& a2) : m_args(First{std::forward(a0), std::forward(a1)}, - std::forward(a2)) - { + std::forward(a2)) { } // {operator, {operator, a0, a1}, {operator, a2, a3}} template guard_expr(T0&& a0, T1&& a1, T2&& a2, T3&& a3) : m_args(First{std::forward(a0), std::forward(a1)}, - Second{std::forward(a2), std::forward(a3)}) - { + Second{std::forward(a2), std::forward(a3)}) { } guard_expr(const guard_expr&) = default; @@ -116,15 +111,13 @@ struct guard_expr template -struct ge_mutable_reference_wrapper -{ +struct ge_mutable_reference_wrapper { T* value; ge_mutable_reference_wrapper() : value(nullptr) { } ge_mutable_reference_wrapper(T&&) = delete; ge_mutable_reference_wrapper(T& vref) : value(&vref) { } ge_mutable_reference_wrapper(const ge_mutable_reference_wrapper&) = default; - ge_mutable_reference_wrapper& operator=(T& vref) - { + ge_mutable_reference_wrapper& operator=(T& vref) { value = &vref; return *this; } @@ -134,15 +127,13 @@ struct ge_mutable_reference_wrapper }; template -struct ge_reference_wrapper -{ - T const* value; +struct ge_reference_wrapper { + const T* value; ge_reference_wrapper(T&&) = delete; ge_reference_wrapper() : value(nullptr) { } ge_reference_wrapper(const T& val_ref) : value(&val_ref) { } ge_reference_wrapper(const ge_reference_wrapper&) = default; - ge_reference_wrapper& operator=(const T& vref) - { + ge_reference_wrapper& operator=(const T& vref) { value = &vref; return *this; } @@ -153,9 +144,8 @@ struct ge_reference_wrapper // support use of gref(BooleanVariable) as receive loop 'guard' template<> -struct ge_reference_wrapper -{ - bool const* value; +struct ge_reference_wrapper { + const bool* value; ge_reference_wrapper(bool&&) = delete; ge_reference_wrapper(const bool& val_ref) : value(&val_ref) { } ge_reference_wrapper(const ge_reference_wrapper&) = default; @@ -166,7 +156,7 @@ struct ge_reference_wrapper }; /** - * @brief Create a reference wrapper similar to std::reference_wrapper + * @brief Creates a reference wrapper similar to std::reference_wrapper * that could be used in guard expressions or to enforce lazy evaluation. */ template @@ -175,20 +165,17 @@ ge_reference_wrapper gref(const T& value) { return {value}; } // bind utility for placeholders template -struct gcall1 -{ +struct gcall1 { typedef guard_expr result; }; template -struct gcall2 -{ +struct gcall2 { typedef guard_expr, T2> result; }; template -struct gcall3 -{ +struct gcall3 { typedef guard_expr, guard_expr > result; @@ -198,8 +185,7 @@ struct gcall3 * @brief Call wrapper for guard placeholders and lazy evaluation. */ template -typename gcall1::result gcall(Fun fun, T1 t1) -{ +typename gcall1::result gcall(Fun fun, T1 t1) { return {fun, t1}; } @@ -207,8 +193,7 @@ typename gcall1::result gcall(Fun fun, T1 t1) * @brief Call wrapper for guard placeholders and lazy evaluation. */ template -typename gcall2::result gcall(Fun fun, T1 t1, T2 t2) -{ +typename gcall2::result gcall(Fun fun, T1 t1, T2 t2) { return {fun, t1, t2}; } @@ -216,8 +201,7 @@ typename gcall2::result gcall(Fun fun, T1 t1, T2 t2) * @brief Call wrapper for guard placeholders and lazy evaluation. */ template -typename gcall3::result gcall(Fun fun, T1 t1, T2 t2, T3 t3) -{ +typename gcall3::result gcall(Fun fun, T1 t1, T2 t2, T3 t3) { return {fun, t1, t2, t3}; } @@ -226,20 +210,17 @@ typename gcall3::result gcall(Fun fun, T1 t1, T2 t2, T3 t3) * The functor @p fun must return a boolean. */ template -guard_expr ge_sub_function(Fun fun) -{ +guard_expr ge_sub_function(Fun fun) { return {fun, util::void_type{}}; } -struct ge_search_container -{ +struct ge_search_container { bool sc; ge_search_container(bool should_contain) : sc(should_contain) { } template bool operator()(const C& haystack, - const typename C::value_type& needle) const - { + const typename C::value_type& needle) const { typedef typename C::value_type vtype; if (sc) return std::any_of(haystack.begin(), haystack.end(), @@ -249,28 +230,23 @@ struct ge_search_container } }; -struct ge_get_size -{ +struct ge_get_size { template - inline auto operator()(const C& what) const -> decltype(what.size()) - { + inline auto operator()(const C& what) const -> decltype(what.size()) { return what.size(); } }; -struct ge_is_empty -{ +struct ge_is_empty { bool expected; ge_is_empty(bool expected_value) : expected(expected_value) { } template - inline bool operator()(const C& what) const - { + inline bool operator()(const C& what) const { return what.empty() == expected; } }; -struct ge_get_front -{ +struct ge_get_front { template inline auto operator()(const C& what, typename std::enable_if< @@ -280,8 +256,7 @@ struct ge_get_front >::type* = 0) const -> option< std::reference_wrapper< - const typename util::rm_ref::type> > - { + const typename util::rm_ref::type> > { if (what.empty() == false) return {what.front()}; return {}; } @@ -292,8 +267,7 @@ struct ge_get_front decltype(what.front()) >::value == false >::type* = 0) const - -> option - { + -> option { if (what.empty() == false) return {what.front()}; return {}; } @@ -303,8 +277,7 @@ struct ge_get_front * @brief A placeholder for guard expression. */ template -struct guard_placeholder -{ +struct guard_placeholder { constexpr guard_placeholder() { } @@ -312,40 +285,34 @@ struct guard_placeholder * @brief Convenient way to call gcall(fun, guard_placeholder). */ template - typename gcall1::result operator()(Fun fun) const - { + typename gcall1::result operator()(Fun fun) const { return gcall(fun, *this); } // utility function for starts_with() - static bool u8_starts_with(const std::string& lhs, const std::string& rhs) - { + static bool u8_starts_with(const std::string& lhs, const std::string& rhs) { return std::equal(rhs.begin(), rhs.end(), lhs.begin()); } /** * @brief Evaluates to the size of a container. */ - typename gcall1::result size() const - { + typename gcall1::result size() const { return gcall(ge_get_size{}, *this); } - typename gcall1::result empty() const - { + typename gcall1::result empty() const { return gcall(ge_is_empty{true}, *this); } - typename gcall1::result not_empty() const - { + typename gcall1::result not_empty() const { return gcall(ge_is_empty{false}, *this); } /** * @brief Evaluates to the first element of a container if it's not empty. */ - typename gcall1::result front() const - { + typename gcall1::result front() const { return gcall(ge_get_front{}, *this); } @@ -356,8 +323,7 @@ struct guard_placeholder guard_placeholder, std::string >::result - starts_with(std::string str) const - { + starts_with(std::string str) const { return gcall(&guard_placeholder::u8_starts_with, *this, std::move(str)); } @@ -367,8 +333,7 @@ struct guard_placeholder */ template typename gcall2::result - in(C container) const - { + in(C container) const { return gcall(ge_search_container{true}, std::move(container), *this); } @@ -381,8 +346,7 @@ struct guard_placeholder std::vector::type>, guard_placeholder >::result - in(std::initializer_list list) const - { + in(std::initializer_list list) const { std::vector::type> vec; for (auto& i : list) vec.emplace_back(i); return in(std::move(vec)); @@ -394,8 +358,7 @@ struct guard_placeholder */ template typename gcall2::result - not_in(C container) const - { + not_in(C container) const { return gcall(ge_search_container{false}, std::move(container), *this); } @@ -408,8 +371,7 @@ struct guard_placeholder std::vector::type>, guard_placeholder >::result - not_in(std::initializer_list list) const - { + not_in(std::initializer_list list) const { std::vector::type> vec; for (auto& i : list) vec.emplace_back(i); return not_in(vec); @@ -433,8 +395,7 @@ struct ge_unbound, Tuple> { typedef T type; }; // unbound type of placeholder template -struct ge_unbound, detail::tdata > -{ +struct ge_unbound, detail::tdata > { static_assert(X < sizeof...(Ts), "Cannot unbind placeholder (too few arguments)"); typedef typename ge_unbound< @@ -447,26 +408,22 @@ struct ge_unbound, detail::tdata > // operators, operators, operators template -struct is_ge_type -{ +struct is_ge_type { static constexpr bool value = false; }; template -struct is_ge_type > -{ +struct is_ge_type > { static constexpr bool value = true; }; template -struct is_ge_type > -{ +struct is_ge_type > { static constexpr bool value = true; }; template -struct is_ge_type > -{ +struct is_ge_type > { static constexpr bool value = true; }; @@ -476,8 +433,7 @@ guard_expr::type, ge_concatenate(T1 first, T2 second, typename std::enable_if< is_ge_type::value || is_ge_type::value - >::type* = 0) -{ + >::type* = 0) { return {first, second}; } @@ -505,69 +461,59 @@ CPPA_EVAL_OP_IMPL(logical_and_op, &&) CPPA_EVAL_OP_IMPL(logical_or_op, ||) template -struct ge_result_ -{ +struct ge_result_ { typedef typename ge_unbound::type type; }; template -struct ge_result_, Tuple> -{ +struct ge_result_, Tuple> { typedef typename ge_result_::type lhs_type; typedef typename ge_result_::type rhs_type; typedef decltype( - ge_eval_op::_(*static_cast(nullptr), - *static_cast(nullptr))) type; + ge_eval_op::_(*static_cast(nullptr), + *static_cast(nullptr))) type; }; template -struct ge_result_, Tuple> -{ +struct ge_result_, Tuple> { typedef bool type; }; template -struct ge_result_, Tuple> -{ +struct ge_result_, Tuple> { typedef First type0; typedef typename ge_unbound::type type1; - typedef decltype( - (*static_cast(nullptr))( - *static_cast(nullptr) + typedef decltype( (*static_cast(nullptr))( + *static_cast(nullptr) )) type; }; template -struct ge_result_, Tuple> -{ +struct ge_result_, Tuple> { typedef typename First::first_type type0; typedef typename ge_unbound::type type1; typedef typename ge_unbound::type type2; - typedef decltype( - (*static_cast(nullptr))( - *static_cast(nullptr), - *static_cast(nullptr) + typedef decltype( (*static_cast(nullptr))( + *static_cast(nullptr), + *static_cast(nullptr) )) type; }; template -struct ge_result_, Tuple> -{ +struct ge_result_, Tuple> { typedef typename First::first_type type0; typedef typename ge_unbound::type type1; typedef typename ge_unbound::type type2; typedef typename ge_unbound::type type3; - typedef decltype( - (*static_cast(nullptr))( - *static_cast(nullptr), - *static_cast(nullptr), - *static_cast(nullptr) + typedef decltype( (*static_cast(nullptr))( + *static_cast(nullptr), + *static_cast(nullptr), + *static_cast(nullptr) )) type; }; template -struct ge_result -{ +struct ge_result { typedef typename ge_result_, Tuple>::type type; }; @@ -576,8 +522,7 @@ template guard_expr, guard_expr> operator&&(guard_expr lhs, - guard_expr rhs) -{ + guard_expr rhs) { return {lhs, rhs}; } @@ -585,8 +530,7 @@ template guard_expr, guard_expr> operator||(guard_expr lhs, - guard_expr rhs) -{ + guard_expr rhs) { return {lhs, rhs}; } @@ -594,33 +538,28 @@ operator||(guard_expr lhs, // evaluation of guard_expr template -inline const T& ge_resolve(const Tuple&, const T& value) -{ +inline const T& ge_resolve(const Tuple&, const T& value) { return value; } template -inline const T& ge_resolve(const Tuple&, const std::reference_wrapper& value) -{ +inline const T& ge_resolve(const Tuple&, const std::reference_wrapper& value) { return value.get(); } template -inline const T& ge_resolve(const Tuple&, const std::reference_wrapper& value) -{ +inline const T& ge_resolve(const Tuple&, const std::reference_wrapper& value) { return value.get(); } template -inline const T& ge_resolve(const Tuple&, const ge_reference_wrapper& value) -{ +inline const T& ge_resolve(const Tuple&, const ge_reference_wrapper& value) { return value.get(); } template inline auto ge_resolve(const Tuple& tup, guard_placeholder) - -> decltype(get(tup).get()) -{ + -> decltype(get(tup).get()) { return get(tup).get(); } @@ -630,20 +569,16 @@ auto ge_resolve(const Tuple& tup, -> typename ge_result::type; template -struct ge_eval_ -{ +struct ge_eval_ { static inline typename ge_result::type - _(const Tuple& tup, const First& lhs, const Second& rhs) - { + _(const Tuple& tup, const First& lhs, const Second& rhs) { return ge_eval_op::_(ge_resolve(tup, lhs), ge_resolve(tup, rhs)); } }; template -struct ge_eval_ -{ - static inline bool _(const Tuple& tup, const First& lhs, const Second& rhs) - { +struct ge_eval_ { + static inline bool _(const Tuple& tup, const First& lhs, const Second& rhs) { // emulate short-circuit evaluation if (ge_resolve(tup, lhs)) return ge_resolve(tup, rhs); return false; @@ -651,10 +586,8 @@ struct ge_eval_ }; template -struct ge_eval_ -{ - static inline bool _(const Tuple& tup, const First& lhs, const Second& rhs) - { +struct ge_eval_ { + static inline bool _(const Tuple& tup, const First& lhs, const Second& rhs) { // emulate short-circuit evaluation if (ge_resolve(tup, lhs)) return true; return ge_resolve(tup, rhs); @@ -662,44 +595,36 @@ struct ge_eval_ }; template -struct ge_eval_ -{ - static inline bool _(const Tuple& tup, const Fun& fun, const util::void_type&) - { +struct ge_eval_ { + static inline bool _(const Tuple& tup, const Fun& fun, const util::void_type&) { return util::unchecked_apply_tuple(fun, tup); } }; template -struct ge_eval_ -{ +struct ge_eval_ { static inline auto _(const Tuple& tup, const First& fun, const Second& arg0) - -> decltype(fun(ge_resolve(tup, arg0))) - { + -> decltype(fun(ge_resolve(tup, arg0))) { return fun(ge_resolve(tup, arg0)); } }; template -struct ge_eval_ -{ +struct ge_eval_ { static inline auto _(const Tuple& tup, const First& lhs, const Second& rhs) -> decltype(lhs.m_args.first(ge_resolve(tup, lhs.m_args.second), - ge_resolve(tup, rhs))) - { + ge_resolve(tup, rhs))) { return lhs.m_args.first(ge_resolve(tup, lhs.m_args.second), ge_resolve(tup, rhs)); } }; template -struct ge_eval_ -{ +struct ge_eval_ { static inline auto _(const Tuple& tup, const First& lhs, const Second& rhs) -> decltype(lhs.m_args.first(ge_resolve(tup, lhs.m_args.second), ge_resolve(tup, rhs.m_args.first), - ge_resolve(tup, rhs.m_args.second))) - { + ge_resolve(tup, rhs.m_args.second))) { return lhs.m_args.first(ge_resolve(tup, lhs.m_args.second), ge_resolve(tup, rhs.m_args.first), ge_resolve(tup, rhs.m_args.second)); @@ -708,24 +633,21 @@ struct ge_eval_ template inline typename ge_result::type -ge_eval(const Tuple& tup, const First& lhs, const Second& rhs) -{ +ge_eval(const Tuple& tup, const First& lhs, const Second& rhs) { return ge_eval_::_(tup, lhs, rhs); } template auto ge_resolve(const Tuple& tup, const guard_expr& ge) - -> typename ge_result::type -{ + -> typename ge_result::type { return ge_eval(tup, ge.m_args.first, ge.m_args.second); } template auto ge_invoke_step2(const guard_expr& ge, const detail::tdata& tup) - -> typename ge_result>::type -{ + -> typename ge_result>::type { return ge_eval(tup, ge.m_args.first, ge.m_args.second); } @@ -733,20 +655,17 @@ template auto ge_invoke(const guard_expr& ge, const Args&... args) -> typename ge_result...>>::type -{ + detail::tdata...>>::type { detail::tdata...> tup{args...}; return ge_invoke_step2(ge, tup); } template -struct ge_invoke_helper -{ +struct ge_invoke_helper { const GuardExpr& ge; ge_invoke_helper(const GuardExpr& arg) : ge(arg) { } template - bool operator()(Args&&... args) const - { + bool operator()(Args&&... args) const { return ge_invoke(ge, std::forward(args)...); } }; @@ -759,8 +678,7 @@ typename ge_result< >::type >::type ge_invoke_any(const guard_expr& ge, - const any_tuple& tup) -{ + const any_tuple& tup) { typedef typename ge_result< OP, First, Second, typename detail::tdata_from_type_list< @@ -783,8 +701,7 @@ ge_invoke_any(const guard_expr& ge, template template -bool guard_expr::operator()(const Args&... args) const -{ +bool guard_expr::operator()(const Args&... args) const { static_assert(std::is_same::value, "guard expression does not return a boolean"); return ge_invoke(*this, args...); @@ -793,26 +710,28 @@ bool guard_expr::operator()(const Args&... args) const // some utility functions template -struct gref_wrapped -{ +struct gref_wrapped { typedef ge_reference_wrapper::type> type; }; template -struct mutable_gref_wrapped -{ +struct mutable_gref_wrapped { typedef ge_mutable_reference_wrapper type; }; template -struct mutable_gref_wrapped -{ +struct mutable_gref_wrapped { typedef ge_mutable_reference_wrapper type; }; // finally ... -namespace placeholders { namespace { +namespace placeholders { + +// doxygen cannot handle anonymous namespaces +#ifndef CPPA_DOCUMENTATION +namespace { +#endif // CPPA_DOCUMENTATION constexpr guard_placeholder<0> _x1; constexpr guard_placeholder<1> _x2; @@ -824,8 +743,13 @@ constexpr guard_placeholder<6> _x7; constexpr guard_placeholder<7> _x8; constexpr guard_placeholder<8> _x9; -} } // namespace placeholders:: +// doxygen cannot handle anonymous namespaces +#ifndef CPPA_DOCUMENTATION +} // namespace +#endif // CPPA_DOCUMENTATION + +} // namespace placeholders } // namespace cppa -#endif // GUARD_EXPR_HPP +#endif // CPPA_GUARD_EXPR_HPP diff --git a/cppa/intrusive/forward_iterator.hpp b/cppa/intrusive/forward_iterator.hpp index dea143ef57..806b5ea3ba 100644 --- a/cppa/intrusive/forward_iterator.hpp +++ b/cppa/intrusive/forward_iterator.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef ITERATOR_HPP -#define ITERATOR_HPP +#ifndef CPPA_FORWARD_ITERATOR_HPP +#define CPPA_FORWARD_ITERATOR_HPP #include @@ -39,8 +39,7 @@ namespace cppa { namespace intrusive { * @brief A forward iterator for intrusive lists. */ template -class forward_iterator -{ +class forward_iterator { public: @@ -48,7 +47,7 @@ class forward_iterator typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* pointer; - typedef value_type const* const_pointer; + typedef const value_type* const_pointer; typedef ptrdiff_t difference_type; typedef std::forward_iterator_tag iterator_category; @@ -57,14 +56,12 @@ class forward_iterator forward_iterator(const forward_iterator&) = default; forward_iterator& operator=(const forward_iterator&) = default; - inline forward_iterator& operator++() - { + inline forward_iterator& operator++() { m_ptr = m_ptr->next; return *this; } - inline forward_iterator operator++(int) - { + inline forward_iterator operator++(int) { forward_iterator tmp{*this}; m_ptr = m_ptr->next; return tmp; @@ -101,8 +98,7 @@ class forward_iterator */ template inline bool operator==(const forward_iterator& lhs, - const forward_iterator& rhs) -{ + const forward_iterator& rhs) { return lhs.ptr() == rhs.ptr(); } @@ -110,8 +106,7 @@ inline bool operator==(const forward_iterator& lhs, * @relates forward_iterator */ template -inline bool operator==(const forward_iterator& lhs, T const* rhs) -{ +inline bool operator==(const forward_iterator& lhs, const T* rhs) { return lhs.ptr() == rhs; } @@ -119,8 +114,7 @@ inline bool operator==(const forward_iterator& lhs, T const* rhs) * @relates forward_iterator */ template -inline bool operator==(T const* lhs, const forward_iterator& rhs) -{ +inline bool operator==(const T* lhs, const forward_iterator& rhs) { return lhs == rhs.ptr(); } @@ -128,8 +122,7 @@ inline bool operator==(T const* lhs, const forward_iterator& rhs) * @relates forward_iterator */ template -inline bool operator==(const forward_iterator& lhs, decltype(nullptr)) -{ +inline bool operator==(const forward_iterator& lhs, std::nullptr_t) { return lhs.ptr() == nullptr; } @@ -137,8 +130,7 @@ inline bool operator==(const forward_iterator& lhs, decltype(nullptr)) * @relates forward_iterator */ template -inline bool operator==(decltype(nullptr), const forward_iterator& rhs) -{ +inline bool operator==(std::nullptr_t, const forward_iterator& rhs) { return rhs.ptr() == nullptr; } @@ -147,8 +139,7 @@ inline bool operator==(decltype(nullptr), const forward_iterator& rhs) */ template inline bool operator!=(const forward_iterator& lhs, - const forward_iterator& rhs) -{ + const forward_iterator& rhs) { return !(lhs == rhs); } @@ -156,8 +147,7 @@ inline bool operator!=(const forward_iterator& lhs, * @relates forward_iterator */ template -inline bool operator!=(const forward_iterator& lhs, T const* rhs) -{ +inline bool operator!=(const forward_iterator& lhs, const T* rhs) { return !(lhs == rhs); } @@ -165,8 +155,7 @@ inline bool operator!=(const forward_iterator& lhs, T const* rhs) * @relates forward_iterator */ template -inline bool operator!=(T const* lhs, const forward_iterator& rhs) -{ +inline bool operator!=(const T* lhs, const forward_iterator& rhs) { return !(lhs == rhs); } @@ -174,8 +163,7 @@ inline bool operator!=(T const* lhs, const forward_iterator& rhs) * @relates forward_iterator */ template -inline bool operator!=(const forward_iterator& lhs, decltype(nullptr)) -{ +inline bool operator!=(const forward_iterator& lhs, std::nullptr_t) { return !(lhs == nullptr); } @@ -183,12 +171,11 @@ inline bool operator!=(const forward_iterator& lhs, decltype(nullptr)) * @relates forward_iterator */ template -inline bool operator!=(decltype(nullptr), const forward_iterator& rhs) -{ +inline bool operator!=(std::nullptr_t, const forward_iterator& rhs) { return !(nullptr == rhs); } } } // namespace cppa::intrusive -#endif // ITERATOR_HPP +#endif // CPPA_FORWARD_ITERATOR_HPP diff --git a/cppa/intrusive/single_reader_queue.hpp b/cppa/intrusive/single_reader_queue.hpp index 28342fb545..7d4011d0e4 100644 --- a/cppa/intrusive/single_reader_queue.hpp +++ b/cppa/intrusive/single_reader_queue.hpp @@ -28,14 +28,17 @@ \******************************************************************************/ -#ifndef SINGLE_READER_QUEUE_HPP -#define SINGLE_READER_QUEUE_HPP +#ifndef CPPA_SINGLE_READER_QUEUE_HPP +#define CPPA_SINGLE_READER_QUEUE_HPP #include +#include #include #include +#include +#include -#include "cppa/detail/thread.hpp" +#include "cppa/config.hpp" namespace cppa { namespace intrusive { @@ -45,30 +48,19 @@ namespace cppa { namespace intrusive { * http://libcppa.blogspot.com/2011/04/mailbox-part-1.html */ template -class single_reader_queue -{ +class single_reader_queue { - typedef detail::unique_lock lock_type; + typedef std::unique_lock lock_type; public: - typedef T value_type; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef value_type* pointer; - typedef value_type const* const_pointer; - - typedef std::unique_ptr unique_value_ptr; - typedef std::list cache_type; - typedef typename cache_type::iterator cache_iterator; + typedef T value_type; + typedef value_type* pointer; /** * @warning call only from the reader (owner) */ - pointer pop() - { + pointer pop() { wait_for_data(); return take_head(); } @@ -76,8 +68,7 @@ class single_reader_queue /** * @warning call only from the reader (owner) */ - pointer try_pop() - { + pointer try_pop() { return take_head(); } @@ -85,104 +76,63 @@ class single_reader_queue * @warning call only from the reader (owner) */ template - pointer try_pop(const TimePoint& abs_time) - { + pointer try_pop(const TimePoint& abs_time) { return (timed_wait_for_data(abs_time)) ? take_head() : nullptr; } // returns true if the queue was empty - bool _push_back(pointer new_element) - { + bool _push_back(pointer new_element) { pointer e = m_stack.load(); - for (;;) - { + for (;;) { new_element->next = e; - if (m_stack.compare_exchange_weak(e, new_element)) - { + if (m_stack.compare_exchange_weak(e, new_element)) { return (e == nullptr); } } } - void push_back(pointer new_element) - { + void push_back(pointer new_element) { pointer e = m_stack.load(); - for (;;) - { + for (;;) { new_element->next = e; - if (!e) - { + if (!e) { lock_type guard(m_mtx); - if (m_stack.compare_exchange_weak(e, new_element)) - { + if (m_stack.compare_exchange_weak(e, new_element)) { m_cv.notify_one(); return; } } - else - { - if (m_stack.compare_exchange_weak(e, new_element)) - { + else { + if (m_stack.compare_exchange_weak(e, new_element)) { return; } } } } - inline cache_type& cache() { return m_cache; } - - inline bool can_fetch_more() const - { + inline bool can_fetch_more() const { return m_stack.load() != nullptr; } /** * @warning call only from the reader (owner) */ - inline bool empty() const - { - return m_cache.empty() && m_stack.load() == nullptr; + inline bool empty() const { + return m_head == nullptr && m_stack.load() == nullptr; } /** * @warning call only from the reader (owner) */ - inline bool not_empty() const - { + inline bool not_empty() const { return !empty(); } - single_reader_queue() : m_stack(nullptr) - { - } - - ~single_reader_queue() - { - // empty the stack - (void) fetch_new_data(); - } - - cache_iterator try_fetch_more() - { - cache_iterator result = m_cache.end(); - fetch_new_data(&result); - return result; + single_reader_queue() : m_stack(nullptr), m_head(nullptr) { } - template - cache_iterator try_fetch_more(const TimePoint& abs_time) - { - cache_iterator result = m_cache.end(); - if (timed_wait_for_data(abs_time)) fetch_new_data(&result); - return result; - } - - cache_iterator fetch_more() - { - cache_iterator result = m_cache.end(); - wait_for_data(); - fetch_new_data(&result); - return result; + ~single_reader_queue() { + // empty the stack (void) fetch_new_data(); } private: @@ -191,22 +141,18 @@ class single_reader_queue std::atomic m_stack; // accessed only by the owner - cache_type m_cache; + pointer m_head; // locked on enqueue/dequeue operations to/from an empty list - detail::mutex m_mtx; - detail::condition_variable m_cv; + std::mutex m_mtx; + std::condition_variable m_cv; template - bool timed_wait_for_data(const TimePoint& timeout) - { - if (m_cache.empty() && !(m_stack.load())) - { + bool timed_wait_for_data(const TimePoint& timeout) { + if (empty()) { lock_type guard(m_mtx); - while (!(m_stack.load())) - { - if (detail::wait_until(guard, m_cv, timeout) == false) - { + while (m_stack.load() == nullptr) { + if (m_cv.wait_until(guard, timeout) == std::cv_status::timeout) { return false; } } @@ -214,39 +160,25 @@ class single_reader_queue return true; } - void wait_for_data() - { - if (m_cache.empty() && !(m_stack.load())) - { + void wait_for_data() { + if (empty()) { lock_type guard(m_mtx); while (!(m_stack.load())) m_cv.wait(guard); } } // atomically sets m_stack to nullptr and enqueues all elements to the cache - bool fetch_new_data(cache_iterator* iter = nullptr) - { + bool fetch_new_data() { + CPPA_REQUIRE(m_head == nullptr); pointer e = m_stack.load(); - while (e) - { - if (m_stack.compare_exchange_weak(e, 0)) - { - // temporary list to convert LIFO to FIFO order - cache_type tmp; - // public_tail (e) has LIFO order, - // but private_head requires FIFO order - while (e) - { - // next iteration element - pointer next = e->next; - // insert e to private cache (convert to LIFO order) - tmp.push_front(unique_value_ptr{e}); - //m_cache.insert(iter, unique_value_ptr{e}); - // next iteration + while (e) { + if (m_stack.compare_exchange_weak(e, 0)) { + while (e) { + auto next = e->next; + e->next = m_head; + m_head = e; e = next; } - if (iter) *iter = tmp.begin(); - m_cache.splice(m_cache.end(), tmp); return true; } // next iteration @@ -255,14 +187,11 @@ class single_reader_queue return false; } - pointer take_head() - { - if (!m_cache.empty() || fetch_new_data()) - { - auto result = m_cache.front().release(); - m_cache.pop_front(); + pointer take_head() { + if (m_head != nullptr || fetch_new_data()) { + auto result = m_head; + m_head = m_head->next; return result; - //return m_cache.take_after(m_cache.before_begin()); } return nullptr; } @@ -271,4 +200,4 @@ class single_reader_queue } } // namespace cppa::util -#endif // SINGLE_READER_QUEUE_HPP +#endif // CPPA_SINGLE_READER_QUEUE_HPP diff --git a/cppa/intrusive/singly_linked_list.hpp b/cppa/intrusive/singly_linked_list.hpp index cd679e3f85..df17ea8610 100644 --- a/cppa/intrusive/singly_linked_list.hpp +++ b/cppa/intrusive/singly_linked_list.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef SINGLY_LINKED_LIST_HPP -#define SINGLY_LINKED_LIST_HPP +#ifndef CPPA_SINGLY_LINKED_LIST_HPP +#define CPPA_SINGLY_LINKED_LIST_HPP #include #include @@ -45,8 +45,7 @@ namespace cppa { namespace intrusive { * @tparam T A class providing a @p next pointer and a default constructor. */ template -class singly_linked_list -{ +class singly_linked_list { singly_linked_list(const singly_linked_list&) = delete; singly_linked_list& operator=(const singly_linked_list&) = delete; @@ -59,23 +58,20 @@ class singly_linked_list typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* pointer; - typedef value_type const* const_pointer; + typedef const value_type* const_pointer; typedef forward_iterator iterator; typedef forward_iterator const_iterator; singly_linked_list() : m_head(), m_tail(&m_head) { } - singly_linked_list(singly_linked_list&& other) : m_head(), m_tail(&m_head) - { + singly_linked_list(singly_linked_list&& other) : m_head(), m_tail(&m_head) { *this = std::move(other); } - singly_linked_list& operator=(singly_linked_list&& other) - { + singly_linked_list& operator=(singly_linked_list&& other) { clear(); - if (other.not_empty()) - { + if (other.not_empty()) { m_head.next = other.m_head.next; m_tail = other.m_tail; other.m_head.next = nullptr; @@ -87,8 +83,7 @@ class singly_linked_list /** * @brief Creates a list from given [first, last] range. */ - static singly_linked_list from(const std::pair& p) - { + static singly_linked_list from(const std::pair& p) { singly_linked_list result; result.m_head.next = p.first; result.m_tail = p.second; @@ -142,13 +137,10 @@ class singly_linked_list * @brief Deletes all elements. * @post {@link empty()} */ - void clear() - { - if (not_empty()) - { + void clear() { + if (not_empty()) { auto h = m_head.next; - while (h) - { + while (h) { pointer next = h->next; delete h; h = next; @@ -162,8 +154,7 @@ class singly_linked_list * @brief Inserts @p what after @p pos. * @returns An iterator to the inserted element. */ - iterator insert_after(iterator pos, pointer what) - { + iterator insert_after(iterator pos, pointer what) { what->next = pos->next; pos->next = what; if (pos == m_tail) m_tail = what; @@ -175,8 +166,7 @@ class singly_linked_list * @returns An iterator to the inserted element. */ template - void emplace_after(iterator pos, Args&&... args) - { + void emplace_after(iterator pos, Args&&... args) { insert_after(pos, new value_type(std::forward(args)...)); } @@ -184,12 +174,10 @@ class singly_linked_list * @brief Deletes the element after @p pos. * @returns An iterator to the element following the erased one. */ - iterator erase_after(iterator pos) - { + iterator erase_after(iterator pos) { CPPA_REQUIRE(pos != nullptr); auto next = pos->next; - if (next) - { + if (next) { if (next == m_tail) m_tail = pos.ptr(); pos->next = next->next; delete next; @@ -200,12 +188,10 @@ class singly_linked_list /** * @brief Removes the element after @p pos from the list and returns it. */ - pointer take_after(iterator pos) - { + pointer take_after(iterator pos) { CPPA_REQUIRE(pos != nullptr); auto next = pos->next; - if (next) - { + if (next) { if (next == m_tail) m_tail = pos.ptr(); pos->next = next->next; next->next = nullptr; @@ -216,8 +202,7 @@ class singly_linked_list /** * @brief Appends @p what to the list. */ - void push_back(pointer what) - { + void push_back(pointer what) { what->next = nullptr; m_tail->next = what; m_tail = what; @@ -228,22 +213,18 @@ class singly_linked_list * to the list. */ template - void emplace_back(Args&&... args) - { + void emplace_back(Args&&... args) { push_back(new value_type(std::forward(args)...)); } /** * @brief Inserts @p what as the first element of the list. */ - void push_front(pointer what) - { - if (empty()) - { + void push_front(pointer what) { + if (empty()) { push_back(what); } - else - { + else { what->next = m_head.next; m_head.next = what; } @@ -254,29 +235,24 @@ class singly_linked_list * as the first element of the list. */ template - void emplace_front(Args&&... args) - { + void emplace_front(Args&&... args) { push_front(new value_type(std::forward(args)...)); } /** * @brief Deletes the first element of the list. */ - void pop_front() - { + void pop_front() { auto x = m_head.next; - if (x == nullptr) - { + if (x == nullptr) { // list is empty return; } - else if (x == m_tail) - { + else if (x == m_tail) { m_tail = &m_head; m_head.next = nullptr; } - else - { + else { m_head.next = x->next; } delete x; @@ -288,14 +264,11 @@ class singly_linked_list * @brief Returns the content of the list as [first, last] sequence. * @post {@link empty()} */ - std::pair take() - { - if (empty()) - { + std::pair take() { + if (empty()) { return {nullptr, nullptr}; } - else - { + else { auto result = std::make_pair(m_head.next, m_tail); m_head.next = nullptr; m_tail = &m_head; @@ -309,18 +282,15 @@ class singly_linked_list * @pre @p pos != {@link end()} * @pre this != &other */ - void splice_after(iterator pos, singly_linked_list&& other) - { + void splice_after(iterator pos, singly_linked_list&& other) { CPPA_REQUIRE(pos != nullptr); CPPA_REQUIRE(this != &other); - if (other.not_empty()) - { + if (other.not_empty()) { auto next = pos->next; auto pair = other.take(); pos->next = pair.first; pair.second->next = next; - if (pos == m_tail) - { + if (pos == m_tail) { CPPA_REQUIRE(next == nullptr); m_tail = pair.second; } @@ -331,17 +301,12 @@ class singly_linked_list * @brief Removes all elements for which predicate @p p returns @p true. */ template - void remove_if(UnaryPredicate p) - { + void remove_if(UnaryPredicate p) { auto i = before_begin(); - while (i->next != nullptr) - { - if (p(*(i->next))) - { - (void) erase_after(i); + while (i->next != nullptr) { + if (p(*(i->next))) { (void) erase_after(i); } - else - { + else { ++i; } } @@ -354,18 +319,14 @@ class singly_linked_list * or end(). */ template - iterator remove_first(UnaryPredicate p, iterator before_first) - { + iterator remove_first(UnaryPredicate p, iterator before_first) { CPPA_REQUIRE(before_first != end()); - while (before_first->next != nullptr) - { - if (p(*(before_first->next))) - { + while (before_first->next != nullptr) { + if (p(*(before_first->next))) { erase_after(before_first); return before_first; } - else - { + else { ++before_first; } } @@ -373,16 +334,14 @@ class singly_linked_list } template - inline iterator remove_first(UnaryPredicate p) - { + inline iterator remove_first(UnaryPredicate p) { return remove_first(std::move(p), before_begin()); } /** * @brief Removes all elements that are equal to @p value. */ - void remove(const value_type& value) - { + void remove(const value_type& value) { remove_if([&](const value_type& other) { return value == other; }); } @@ -395,4 +354,4 @@ class singly_linked_list } } // namespace cppa::intrusive -#endif // SINGLY_LINKED_LIST_HPP +#endif // CPPA_SINGLY_LINKED_LIST_HPP diff --git a/cppa/intrusive_ptr.hpp b/cppa/intrusive_ptr.hpp index f1e745624c..235aba4f3b 100644 --- a/cppa/intrusive_ptr.hpp +++ b/cppa/intrusive_ptr.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef INTRUSIVE_PTR_HPP -#define INTRUSIVE_PTR_HPP +#ifndef CPPA_INTRUSIVE_PTR_HPP +#define CPPA_INTRUSIVE_PTR_HPP #include #include @@ -41,11 +41,8 @@ namespace cppa { template -struct convertible -{ - constexpr convertible() { } - To convert() const - { +struct convertible { + inline To convert() const { return static_cast(this)->do_convert(); } }; @@ -55,185 +52,153 @@ struct convertible * @relates ref_counted */ template -class intrusive_ptr : util::comparable, const T*>, - util::comparable> -{ - - T* m_ptr; - - inline void set_ptr(T* raw_ptr) - { - m_ptr = raw_ptr; - if (raw_ptr) raw_ptr->ref(); - } +class intrusive_ptr : util::comparable >, + util::comparable, const T*>, + util::comparable, std::nullptr_t> { public: - constexpr intrusive_ptr() : m_ptr(nullptr) { } + typedef T* pointer; + typedef const T* const_pointer; + typedef T element_type; + typedef T& reference; + typedef const T& const_reference; - intrusive_ptr(T* raw_ptr) { set_ptr(raw_ptr); } + constexpr intrusive_ptr() : m_ptr(nullptr) { } - intrusive_ptr(const intrusive_ptr& other) { set_ptr(other.m_ptr); } + intrusive_ptr(pointer raw_ptr) { set_ptr(raw_ptr); } - intrusive_ptr(intrusive_ptr&& other) : m_ptr(other.take()) { } + intrusive_ptr(intrusive_ptr&& other) : m_ptr(other.release()) { } - // enables "actor_ptr s = self" - template - intrusive_ptr(const convertible& from) - { - set_ptr(from.convert()); - } + intrusive_ptr(const intrusive_ptr& other) { set_ptr(other.get()); } template - intrusive_ptr(const intrusive_ptr& other) - { + intrusive_ptr(intrusive_ptr other) : m_ptr(other.release()) { static_assert(std::is_convertible::value, "Y* is not assignable to T*"); - set_ptr(const_cast(other.get())); } - template - intrusive_ptr(intrusive_ptr&& other) : m_ptr(other.take()) - { - static_assert(std::is_convertible::value, - "Y* is not assignable to T*"); + // enables "actor_ptr s = self" + template + intrusive_ptr(const convertible& from) { + set_ptr(from.convert()); } - ~intrusive_ptr() - { - if (m_ptr && !m_ptr->deref()) - { - delete m_ptr; - } + ~intrusive_ptr() { + if (m_ptr && !m_ptr->deref()) delete m_ptr; } - inline T* get() { return m_ptr; } - - inline const T* get() const { return m_ptr; } + inline void swap(intrusive_ptr& other) { + std::swap(m_ptr, other.m_ptr); + } - T* take() - { + /** + * @brief Returns the raw pointer without modifying reference count. + */ + pointer release() { auto result = m_ptr; m_ptr = nullptr; return result; } - inline void swap(intrusive_ptr& other) - { - std::swap(m_ptr, other.m_ptr); + /** + * @brief Sets this pointer to @p ptr without modifying reference count. + */ + void adopt(pointer ptr) { + reset(); + m_ptr = ptr; } - void reset(T* new_value = nullptr) - { + void reset(pointer new_value = nullptr) { if (m_ptr && !m_ptr->deref()) delete m_ptr; set_ptr(new_value); } - intrusive_ptr& operator=(T* ptr) - { + intrusive_ptr& operator=(pointer ptr) { reset(ptr); return *this; } - intrusive_ptr& operator=(const intrusive_ptr& other) - { - intrusive_ptr tmp(other); - swap(tmp); + intrusive_ptr& operator=(intrusive_ptr&& other) { + swap(other); return *this; } - intrusive_ptr& operator=(intrusive_ptr&& other) - { - reset(); - swap(other); + intrusive_ptr& operator=(const intrusive_ptr& other) { + intrusive_ptr tmp{other}; + swap(tmp); return *this; } template - intrusive_ptr& operator=(const intrusive_ptr& other) - { - static_assert(std::is_convertible::value, - "Y* is not assignable to T*"); - intrusive_ptr tmp(other); + intrusive_ptr& operator=(intrusive_ptr other) { + intrusive_ptr tmp{std::move(other)}; swap(tmp); return *this; } template - intrusive_ptr& operator=(const convertible& from) - { + intrusive_ptr& operator=(const convertible& from) { reset(from.convert()); return *this; } - template - intrusive_ptr& operator=(intrusive_ptr&& other) - { - static_assert(std::is_convertible::value, - "Y* is not assignable to T*"); - reset(); - m_ptr = other.take(); - return *this; - } - - inline T& operator*() { return *m_ptr; } - - inline T* operator->() { return m_ptr; } - - inline const T& operator*() const { return *m_ptr; } - - inline const T* operator->() const { return m_ptr; } + inline pointer get() const { return m_ptr; } + inline pointer operator->() const { return m_ptr; } + inline reference operator*() const { return *m_ptr; } + inline bool operator!() const { return m_ptr == nullptr; } inline explicit operator bool() const { return m_ptr != nullptr; } - inline ptrdiff_t compare(const T* ptr) const - { + inline ptrdiff_t compare(const_pointer ptr) const { return static_cast(get() - ptr); } - inline ptrdiff_t compare(const intrusive_ptr& other) const - { + inline ptrdiff_t compare(const intrusive_ptr& other) const { return compare(other.get()); } + inline ptrdiff_t compare(std::nullptr_t) const { + return reinterpret_cast(get()); + } + template - intrusive_ptr downcast() const - { - return (m_ptr) ? dynamic_cast(const_cast(m_ptr)) : nullptr; + intrusive_ptr downcast() const { + return (m_ptr) ? dynamic_cast(get()) : nullptr; } template - intrusive_ptr upcast() const - { - return (m_ptr) ? static_cast(const_cast(m_ptr)) : nullptr; + intrusive_ptr upcast() const { + return (m_ptr) ? static_cast(get()) : nullptr; } -}; + private: -template -inline bool operator==(const intrusive_ptr& lhs, decltype(nullptr)) -{ - return lhs.get() == nullptr; -} + pointer m_ptr; -template -inline bool operator==(decltype(nullptr), const intrusive_ptr& rhs) -{ - return rhs.get() == nullptr; -} + inline void set_ptr(pointer raw_ptr) { + m_ptr = raw_ptr; + if (raw_ptr) raw_ptr->ref(); + } +}; + +/** + * @relates intrusive_ptr + */ template -bool operator==(const intrusive_ptr& lhs, const intrusive_ptr& rhs) -{ +inline bool operator==(const intrusive_ptr& lhs, const intrusive_ptr& rhs) { return lhs.get() == rhs.get(); } +/** + * @relates intrusive_ptr + */ template -inline bool operator!=(const intrusive_ptr& lhs, const intrusive_ptr& rhs) -{ +inline bool operator!=(const intrusive_ptr& lhs, const intrusive_ptr& rhs) { return !(lhs == rhs); } } // namespace cppa -#endif // INTRUSIVE_PTR_HPP +#endif // CPPA_INTRUSIVE_PTR_HPP diff --git a/cppa/local_actor.hpp b/cppa/local_actor.hpp index 5c726a160e..68e658193f 100644 --- a/cppa/local_actor.hpp +++ b/cppa/local_actor.hpp @@ -28,95 +28,321 @@ \******************************************************************************/ -#ifndef CONTEXT_HPP -#define CONTEXT_HPP +#ifndef CPPA_CONTEXT_HPP +#define CPPA_CONTEXT_HPP #include "cppa/actor.hpp" #include "cppa/behavior.hpp" #include "cppa/any_tuple.hpp" +#include "cppa/exit_reason.hpp" #include "cppa/partial_function.hpp" #include "cppa/intrusive/single_reader_queue.hpp" namespace cppa { class scheduler; +class local_scheduler; + +struct discard_behavior_t { }; +struct keep_behavior_t { }; + +#ifndef CPPA_DOCUMENTATION +namespace { +#endif // CPPA_DOCUMENTATION /** - * @brief Base class for local running Actors. + * @brief Policy tag that causes {@link event_based_actor::become} to + * discard the current behavior. + * @relates local_actor */ -class local_actor : public actor -{ +constexpr discard_behavior_t discard_behavior = discard_behavior_t(); - friend class scheduler; +/** + * @brief 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(); - protected: +#ifndef CPPA_DOCUMENTATION +} // namespace +#endif // CPPA_DOCUMENTATION - bool m_trap_exit; - actor_ptr m_last_sender; - any_tuple m_last_dequeued; +/** + * @brief Base class for local running Actors. + */ +class local_actor : public actor { + + friend class scheduler; public: - local_actor(); + /** + * @brief Causes this actor to subscribe to the group @p what. + * + * The group will be unsubscribed if the actor finishes execution. + * @param what Group instance that should be joined. + */ + void join(const group_ptr& what); + + /** + * @brief Causes this actor to leave the group @p what. + * @param what Joined group that should be leaved. + * @note Groups are leaved automatically if the Actor finishes + * execution. + */ + void leave(const group_ptr& what); /** * @brief Finishes execution of this actor. * - * Causes this actor to send an exit signal to all of its - * linked actors, sets its state to @c exited and throws - * {@link actor_exited} to cleanup the stack. - * @param reason Exit reason that will be send to linked actors. - * @throws actor_exited + * Causes this actor to send an exit message to all of its + * linked actors, sets its state to @c exited and finishes execution. + * @param reason Exit reason that will be send to + * linked actors and monitors. + */ + virtual void quit(std::uint32_t reason = exit_reason::normal) = 0; + + /** + * @brief Removes the first element from the mailbox @p pfun is defined + * for and invokes @p pfun with the removed element. + * Blocks until a matching message arrives if @p pfun is not + * defined for any message in the actor's mailbox. + * @param pfun A partial function denoting the actor's response to the + * next incoming message. + * @warning You should not call this member function by hand. + * Use the {@link cppa::receive receive} function or + * the @p become member function in case of event-based actors. */ - virtual void quit(std::uint32_t reason) = 0; + virtual void dequeue(partial_function& pfun) = 0; /** - * @brief - * @param rules - * @warning Call only from the owner of the queue. + * @brief Removes the first element from the mailbox @p bhvr is defined + * for and invokes @p bhvr with the removed element. + * Blocks until either a matching message arrives if @p bhvr is not + * defined for any message in the actor's mailbox or until a + * timeout occurs. + * @param bhvr A partial function with optional timeout denoting the + * actor's response to the next incoming message. + * @warning You should not call this member function by hand. + * Use the {@link cppa::receive receive} function or + * the @p become member function in case of event-based actors. */ - virtual void dequeue(behavior& rules) = 0; + virtual void dequeue(behavior& bhvr) = 0; /** - * @brief Removes the first element from the queue that is matched - * by @p rules and invokes the corresponding callback. - * @param rules - * @warning Call only from the owner of the queue. + * @brief Checks whether this actor traps exit messages. */ - virtual void dequeue(partial_function& rules) = 0; + inline bool trap_exit() const { + return m_trap_exit; + } - inline bool trap_exit() const; + /** + * @brief Enables or disables trapping of exit messages. + */ + inline void trap_exit(bool new_value) { + m_trap_exit = new_value; + } + + /** + * @brief Checks whether this actor uses the "chained send" optimization. + */ + inline bool chaining() const { + return m_chaining; + } - inline void trap_exit(bool new_value); + /** + * @brief Enables or disables chained send. + */ + inline void chaining(bool new_value) { + m_chaining = m_is_scheduled && new_value; + } - inline any_tuple& last_dequeued(); + /** + * @brief Returns the last message that was dequeued + * from the actor's mailbox. + * @note Only set during callback invocation. + */ + inline any_tuple& last_dequeued() { + return m_last_dequeued; + } - inline actor_ptr& last_sender(); + /** + * @brief Returns the sender of the last dequeued message. + * @note Only set during callback invocation. + * @note Implicitly used by the function {@link cppa::reply}. + */ + inline actor_ptr& last_sender() { + return m_last_sender; + } -}; + /** + * @brief Adds a unidirectional @p monitor to @p whom. + * + * @whom sends a "DOWN" message to this actor as part of its termination. + * @param whom The actor that should be monitored by this actor. + * @note Each call to @p monitor creates a new, independent monitor. + */ + void monitor(actor_ptr whom); + + /** + * @brief Removes a monitor from @p whom. + * @param whom A monitored actor. + */ + void demonitor(actor_ptr whom); + + // become/unbecome API + + /** + * @brief Sets the actor's behavior to @p bhvr and discards the + * previous behavior. + * @note The recommended way of using this member function is to pass + * a pointer to a member variable. + * @warning @p bhvr is owned by the caller and must remain valid until + * the actor terminates. + */ + inline void become(discard_behavior_t, behavior* bhvr) { + do_become(bhvr, false, true); + } + + /** + * @brief Sets the actor's behavior. + */ + inline void become(discard_behavior_t, behavior&& bhvr) { + do_become(new behavior(std::move(bhvr)), true, true); + } + + /** + * @brief Sets the actor's behavior to @p bhvr and keeps the + * previous behavior, so that it can be restored by calling + * {@link unbecome()}. + * @note The recommended way of using this member function is to pass + * a pointer to a member variable. + * @warning @p bhvr is owned by the caller and must remain valid until + * the actor terminates. + */ + inline void become(keep_behavior_t, behavior* bhvr) { + do_become(bhvr, false, false); + } + + /** + * @brief Sets the actor's behavior. + */ + inline void become(keep_behavior_t, behavior&& bhvr) { + do_become(new behavior(std::move(bhvr)), true, false); + } + + /** + * @brief Sets the actor's behavior. + */ + inline void become(behavior&& bhvr) { + become(discard_behavior, std::move(bhvr)); + } + + /** + * @brief Equal to become(discard_old, bhvr). + */ + inline void become(behavior* bhvr) { + become(discard_behavior, bhvr); + } + + /** + * @brief Sets the actor's behavior. + */ + template + inline void become(discard_behavior_t, match_expr&& arg0, Args&&... args) { + become(discard_behavior, match_expr_concat(std::move(arg0), std::forward(args)...)); + } + + /** + * @brief Sets the actor's behavior. + */ + template + inline void become(keep_behavior_t, match_expr&& arg0, Args&&... args) { + become(keep_behavior, match_expr_concat(std::move(arg0), std::forward(args)...)); + } + + /** + * @brief Sets the actor's behavior. + */ + template + inline void become(match_expr arg0, Args&&... args) { + become(discard_behavior, match_expr_concat(std::move(arg0), std::forward(args)...)); + } + + /** + * @brief Returns to a previous behavior if available. + */ + virtual void unbecome() = 0; + + /** + * @brief Can be overridden to initialize an actor before any + * message is handled. + * @warning Must not call blocking functions such as + * {@link cppa::receive receive}. + * @note Calling {@link become} to set an initial behavior is supported. + */ + virtual void init(); + + /** + * @brief Can be overridden to perform cleanup code after an actor + * finished execution. + * @warning Must not call any function manipulating the actor's state such + * as join, leave, link, or monitor. + */ + virtual void on_exit(); + + // library-internal members and member functions that shall + // not appear in the documentation + +# ifndef CPPA_DOCUMENTATION + + local_actor(bool is_scheduled = false); + + virtual bool initialized() = 0; + + inline void send_message(channel* whom, any_tuple&& what) { + whom->enqueue(this, std::move(what)); + } -inline bool local_actor::trap_exit() const -{ - return m_trap_exit; -} + inline void send_message(actor* whom, any_tuple&& what) { + if (m_chaining && !m_chained_actor) { + if (whom->chained_enqueue(this, std::move(what))) { + m_chained_actor = whom; + } + } + else { + whom->enqueue(this, std::move(what)); + } + } -inline void local_actor::trap_exit(bool new_value) -{ - m_trap_exit = new_value; -} + inline actor_ptr& chained_actor() { + return m_chained_actor; + } -inline any_tuple& local_actor::last_dequeued() -{ - return m_last_dequeued; -} + protected: + + bool m_chaining; + bool m_trap_exit; + bool m_is_scheduled; + actor_ptr m_last_sender; + actor_ptr m_chained_actor; + any_tuple m_last_dequeued; + +# endif // CPPA_DOCUMENTATION -inline actor_ptr& local_actor::last_sender() -{ - return m_last_sender; -} + protected: + + virtual void do_become(behavior* bhvr, bool owns_ptr, bool discard_old) = 0; + +}; +/** + * @brief A smart pointer to a {@link local_actor} instance. + * @relates local_actor + */ typedef intrusive_ptr local_actor_ptr; } // namespace cppa -#endif // CONTEXT_HPP +#endif // CPPA_CONTEXT_HPP diff --git a/cppa/match.hpp b/cppa/match.hpp index 45eb78bad0..bd8e406eaf 100644 --- a/cppa/match.hpp +++ b/cppa/match.hpp @@ -28,86 +28,75 @@ \******************************************************************************/ -#ifndef MATCH_HPP -#define MATCH_HPP +#ifndef CPPA_MATCH_HPP +#define CPPA_MATCH_HPP #include "cppa/any_tuple.hpp" #include "cppa/partial_function.hpp" namespace cppa { namespace detail { -struct match_helper -{ +struct match_helper { match_helper(const match_helper&) = delete; match_helper& operator=(const match_helper&) = delete; any_tuple tup; - match_helper(any_tuple&& t) : tup(std::move(t)) { } + match_helper(any_tuple t) : tup(std::move(t)) { } match_helper(match_helper&&) = default; - void operator()(partial_function&& arg) - { + /* + void operator()(partial_function&& arg) { partial_function tmp{std::move(arg)}; tmp(tup); } + */ template - void operator()(Arg0&& arg0, Args&&... args) - { - (*this)(mexpr_concat_convert(std::forward(arg0), - std::forward(args)...)); + void operator()(Arg0&& arg0, Args&&... args) { + auto tmp = mexpr_concat(std::forward(arg0), + std::forward(args)...); + tmp(tup); } }; template -struct match_each_helper -{ +struct match_each_helper { match_each_helper(const match_each_helper&) = delete; match_each_helper& operator=(const match_each_helper&) = delete; Iterator i; Iterator e; match_each_helper(Iterator first, Iterator last) : i(first), e(last) { } match_each_helper(match_each_helper&&) = default; - void operator()(partial_function&& arg) - { + void operator()(partial_function&& arg) { partial_function tmp{std::move(arg)}; - for (; i != e; ++i) - { + for (; i != e; ++i) { tmp(any_tuple::view(*i)); } } template - void operator()(Arg0&& arg0, Args&&... args) - { - (*this)(mexpr_concat_convert(std::forward(arg0), + void operator()(Arg0&& arg0, Args&&... args) { (*this)(mexpr_concat_convert(std::forward(arg0), std::forward(args)...)); } }; template -struct copying_match_each_helper -{ +struct copying_match_each_helper { copying_match_each_helper(const copying_match_each_helper&) = delete; copying_match_each_helper& operator=(const copying_match_each_helper&) = delete; Container vec; copying_match_each_helper(Container tmp) : vec(std::move(tmp)) { } copying_match_each_helper(copying_match_each_helper&&) = default; - void operator()(partial_function&& arg) - { + void operator()(partial_function&& arg) { partial_function tmp{std::move(arg)}; - for (auto& i : vec) - { + for (auto& i : vec) { tmp(any_tuple::view(i)); } } template - void operator()(Arg0&& arg0, Args&&... args) - { - (*this)(mexpr_concat_convert(std::forward(arg0), + void operator()(Arg0&& arg0, Args&&... args) { (*this)(mexpr_concat_convert(std::forward(arg0), std::forward(args)...)); } }; template -struct pmatch_each_helper -{ +struct pmatch_each_helper { pmatch_each_helper(const pmatch_each_helper&) = delete; pmatch_each_helper& operator=(const pmatch_each_helper&) = delete; Iterator i; @@ -116,21 +105,16 @@ struct pmatch_each_helper pmatch_each_helper(pmatch_each_helper&&) = default; template pmatch_each_helper(Iterator first, Iterator last, PJ&& proj) - : i(first), e(last), p(std::forward(proj)) - { + : i(first), e(last), p(std::forward(proj)) { } - void operator()(partial_function&& arg) - { + void operator()(partial_function&& arg) { partial_function tmp{std::move(arg)}; - for (; i != e; ++i) - { + for (; i != e; ++i) { tmp(any_tuple::view(p(*i))); } } template - void operator()(Arg0&& arg0, Args&&... args) - { - (*this)(mexpr_concat_convert(std::forward(arg0), + void operator()(Arg0&& arg0, Args&&... args) { (*this)(mexpr_concat_convert(std::forward(arg0), std::forward(args)...)); } }; @@ -139,54 +123,75 @@ struct pmatch_each_helper namespace cppa { -inline detail::match_helper match(any_tuple t) -{ - return std::move(t); +/** + * @brief Starts a match expression. + * @param what Tuple or value that should be matched against a pattern. + * @returns A helper object providing operator(...). + */ +inline detail::match_helper match(any_tuple what) { + return std::move(what); } /** - * @brief Match expression. + * @copydoc match(any_tuple) */ template -detail::match_helper match(T&& what) -{ +detail::match_helper match(T&& what) { return any_tuple::view(std::forward(what)); } /** - * @brief Match expression that matches against all elements of @p what. + * @brief Starts a match expression that matches each element of @p what. + * @param what An STL-compliant container. + * @returns A helper object providing operator(...). */ template auto match_each(Container& what) - -> detail::match_each_helper -{ + -> detail::match_each_helper { return {std::begin(what), std::end(what)}; } +/** + * @brief Starts a match expression that matches each element of @p what. + * @param what An STL-compliant container. + * @returns A helper object providing operator(...). + */ template -auto match_each(std::initializer_list list) - -> detail::copying_match_each_helper::type>> -{ +auto match_each(std::initializer_list what) + -> detail::copying_match_each_helper::type>> { std::vector::type> vec; - vec.reserve(list.size()); - for (auto& i : list) vec.emplace_back(std::move(i)); + vec.reserve(what.size()); + for (auto& i : what) vec.emplace_back(std::move(i)); return vec; } +/** + * @brief Starts a match expression that matches each element in + * range [first, last). + * @param first Iterator to the first element. + * @param last Iterator to the last element (excluded). + * @returns A helper object providing operator(...). + */ template auto match_each(InputIterator first, InputIterator last) - -> detail::match_each_helper -{ + -> detail::match_each_helper { return {first, last}; } +/** + * @brief Starts a match expression that matches proj(i) for + * each element @p i in range [first, last). + * @param first Iterator to the first element. + * @param last Iterator to the last element (excluded). + * @param proj Projection or extractor functor. + * @returns A helper object providing operator(...). + */ template -auto pmatch_each(InputIterator first, InputIterator last, Projection&& proj) - -> detail::pmatch_each_helper::type> -{ - return {first, last, std::forward(proj)}; +auto match_each(InputIterator first, InputIterator last, Projection proj) + -> detail::pmatch_each_helper { + return {first, last, std::move(proj)}; } } // namespace cppa -#endif // MATCH_HPP +#endif // CPPA_MATCH_HPP diff --git a/cppa/match_expr.hpp b/cppa/match_expr.hpp index d90a8113fb..5be947c024 100644 --- a/cppa/match_expr.hpp +++ b/cppa/match_expr.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef MATCH_EXPR_HPP -#define MATCH_EXPR_HPP +#ifndef CPPA_MATCH_EXPR_HPP +#define CPPA_MATCH_EXPR_HPP #include "cppa/option.hpp" #include "cppa/pattern.hpp" @@ -44,6 +44,7 @@ #include "cppa/util/left_or_right.hpp" #include "cppa/util/deduce_ref_type.hpp" +#include "cppa/detail/matches.hpp" #include "cppa/detail/projection.hpp" #include "cppa/detail/value_guard.hpp" #include "cppa/detail/pseudo_tuple.hpp" @@ -52,14 +53,12 @@ namespace cppa { namespace detail { // covers wildcard_position::multiple and wildcard_position::in_between template -struct invoke_policy_impl -{ +struct invoke_policy_impl { typedef FilteredPattern filtered_pattern; template static bool can_invoke(const std::type_info& type_token, - const Tuple& tup) - { + const Tuple& tup) { typedef typename match_impl_from_type_list::type mimpl; return type_token == typeid(filtered_pattern) || mimpl::_(tup); } @@ -69,8 +68,7 @@ struct invoke_policy_impl const std::type_info& type_token, detail::tuple_impl_info, PtrType*, - Tuple& tup) - { + Tuple& tup) { typedef typename match_impl_from_type_list< typename std::remove_const::type, Pattern @@ -78,14 +76,12 @@ struct invoke_policy_impl mimpl; util::fixed_vector mv; - if (type_token == typeid(filtered_pattern) || mimpl::_(tup, mv)) - { + if (type_token == typeid(filtered_pattern) || mimpl::_(tup, mv)) { typedef typename pseudo_tuple_from_type_list::type ttup_type; ttup_type ttup; // if we strip const here ... - for (size_t i = 0; i < filtered_pattern::size; ++i) - { + for (size_t i = 0; i < filtered_pattern::size; ++i) { ttup[i] = const_cast(tup.at(mv[i])); } // ... we restore it here again @@ -104,8 +100,7 @@ struct invoke_policy_impl template struct invoke_policy_impl > -{ + Pattern, util::type_list > { typedef util::type_list filtered_pattern; typedef detail::tdata native_data_type; @@ -113,15 +108,13 @@ struct invoke_policy_impl arr_type; template - static bool invoke(std::integral_constant, Target&, Tup&) - { + static bool invoke(std::integral_constant, Target&, Tup&) { return false; } template static bool invoke(std::integral_constant, - Target& target, Tup& tup) - { + Target& target, Tup& tup) { return util::unchecked_apply_tuple(target, tup); } @@ -136,8 +129,7 @@ struct invoke_policy_impl::type, detail::abstract_tuple >::value == false - >::type* = 0) - { + >::type* = 0) { static constexpr bool can_apply = util::tl_binary_forall< typename util::tl_map< @@ -161,15 +153,12 @@ struct invoke_policy_impl::type, detail::abstract_tuple >::value - >::type* = 0) - { - if (arg_types == typeid(filtered_pattern)) - { - if (native_arg) - { + >::type* = 0) { + if (arg_types == typeid(filtered_pattern)) { + if (native_arg) { typedef typename util::if_else_c< std::is_const::value, - native_data_type const*, + const native_data_type*, util::wrapped >::type cast_type; @@ -178,24 +167,19 @@ struct invoke_policy_impl ttup_type; @@ -215,8 +199,7 @@ struct invoke_policy_impl - static bool can_invoke(const std::type_info& arg_types, const Tuple&) - { + static bool can_invoke(const std::type_info& arg_types, const Tuple&) { return arg_types == typeid(filtered_pattern); } }; @@ -224,12 +207,10 @@ struct invoke_policy_impl struct invoke_policy_impl, - util::type_list<> > -{ + util::type_list<> > { template static inline bool can_invoke(const std::type_info&, - const Tuple&) - { + const Tuple&) { return true; } @@ -238,8 +219,7 @@ struct invoke_policy_impl struct invoke_policy_impl > -{ + Pattern, util::type_list > { typedef util::type_list filtered_pattern; template static bool can_invoke(const std::type_info& arg_types, - const Tuple& tup) - { - if (arg_types == typeid(filtered_pattern)) - { + const Tuple& tup) { + if (arg_types == typeid(filtered_pattern)) { return true; } typedef detail::static_types_array arr_type; auto& arr = arr_type::arr; - if (tup.size() < filtered_pattern::size) - { + if (tup.size() < filtered_pattern::size) { return false; } - for (size_t i = 0; i < filtered_pattern::size; ++i) - { - if (arr[i] != tup.type_at(i)) - { + for (size_t i = 0; i < filtered_pattern::size; ++i) { + if (arr[i] != tup.type_at(i)) { return false; } } @@ -280,8 +254,7 @@ struct invoke_policy_impl ttup_type; ttup_type ttup; @@ -302,30 +275,24 @@ struct invoke_policy_impl struct invoke_policy_impl > -{ + Pattern, util::type_list > { typedef util::type_list filtered_pattern; template static bool can_invoke(const std::type_info& arg_types, - const Tuple& tup) - { - if (arg_types == typeid(filtered_pattern)) - { + const Tuple& tup) { + if (arg_types == typeid(filtered_pattern)) { return true; } typedef detail::static_types_array arr_type; auto& arr = arr_type::arr; - if (tup.size() < filtered_pattern::size) - { + if (tup.size() < filtered_pattern::size) { return false; } size_t i = tup.size() - filtered_pattern::size; size_t j = 0; - while (j < filtered_pattern::size) - { - if (arr[i++] != tup.type_at(j++)) - { + while (j < filtered_pattern::size) { + if (arr[i++] != tup.type_at(j++)) { return false; } } @@ -337,15 +304,13 @@ struct invoke_policy_impl ttup_type; ttup_type ttup; size_t i = tup.size() - filtered_pattern::size; size_t j = 0; - while (j < filtered_pattern::size) - { + while (j < filtered_pattern::size) { ttup[j++] = const_cast(tup.at(i++)); } // ensure const-correctness @@ -366,26 +331,22 @@ struct invoke_policy : invoke_policy_impl< get_wildcard_position(), Pattern, - typename util::tl_filter_not_type::type> -{ + typename util::tl_filter_not_type::type> { }; template -struct projection_partial_function_pair : std::pair -{ +struct projection_partial_function_pair : std::pair { template projection_partial_function_pair(Args&&... args) - : std::pair(std::forward(args)...) - { + : std::pair(std::forward(args)...) { } typedef Pattern pattern_type; }; template -struct get_case_ -{ +struct get_case_ { typedef typename util::get_callable_trait::type ctrait; typedef typename util::tl_filter_not_type< @@ -469,14 +430,12 @@ struct get_case_ }; template -struct get_case -{ +struct get_case { typedef typename get_case_::type type; }; template -struct get_case -{ +struct get_case { typedef typename util::tl_pop_back::type lhs_pattern; typedef typename util::tl_map< typename util::get_arg_types::types, @@ -495,8 +454,7 @@ struct get_case /* template struct get_case >, - util::type_list<>, util::type_list > -{ + util::type_list<>, util::type_list > { typedef typename get_case_< Expr, value_guard >, @@ -510,20 +468,17 @@ struct get_case >, template struct pjf_same_pattern : std::is_same -{ + typename Second::second::pattern_type> { }; // last invocation step; evaluates a {projection, tpartial_function} pair template -struct invoke_helper3 -{ +struct invoke_helper3 { const Data& data; invoke_helper3(const Data& mdata) : data(mdata) { } template inline bool operator()(util::type_pair, T>, - Args&&... args) const - { + Args&&... args) const { const auto& target = get(data); return target.first(target.second, std::forward(args)...); //return (get(data))(args...); @@ -531,22 +486,19 @@ struct invoke_helper3 }; template -struct invoke_helper2 -{ +struct invoke_helper2 { typedef Pattern pattern_type; typedef typename util::tl_filter_not_type::type arg_types; const Data& data; invoke_helper2(const Data& mdata) : data(mdata) { } template - bool invoke(Args&&... args) const - { + bool invoke(Args&&... args) const { typedef invoke_policy impl; return impl::invoke(*this, std::forward(args)...); } // resolved argument list (called from invoke_policy) template - bool operator()(Args&&... args) const - { + bool operator()(Args&&... args) const { //static_assert(false, "foo"); Token token; invoke_helper3 fun{data}; @@ -556,8 +508,7 @@ struct invoke_helper2 // invokes a group of {projection, tpartial_function} pairs template -struct invoke_helper -{ +struct invoke_helper { const Data& data; std::uint64_t bitfield; invoke_helper(const Data& mdata, std::uint64_t bits) : data(mdata), bitfield(bits) { } @@ -567,13 +518,10 @@ struct invoke_helper // all {projection, tpartial_function} pairs have the same pattern // thus, can be invoked from same data template - bool operator()(Token, Args&&... args) - { + bool operator()(Token, Args&&... args) { typedef typename Token::head type_pair; typedef typename type_pair::second leaf_pair; - if (bitfield & 0x01) - //if (*enabled++) - { + if (bitfield & 0x01) { // next invocation step invoke_helper2 - void operator()(Token, Args&&... args) - { + void operator()(Token, Args&&... args) { typedef typename Token::head type_pair; typedef typename type_pair::second leaf_pair; typedef invoke_policy impl; - if (impl::can_invoke(std::forward(args)...)) - { + if (impl::can_invoke(std::forward(args)...)) { bitfield |= (0x01 << i); } ++i; @@ -606,32 +551,27 @@ struct can_invoke_helper }; template -struct is_manipulator_case -{ +struct is_manipulator_case { static constexpr bool value = T::second_type::manipulates_args; }; template -struct mexpr_fwd_ -{ +struct mexpr_fwd_ { typedef T1 type; }; template -struct mexpr_fwd_ -{ +struct mexpr_fwd_ { typedef std::reference_wrapper type; }; template -struct mexpr_fwd_ -{ +struct mexpr_fwd_ { typedef std::reference_wrapper type; }; template -struct mexpr_fwd -{ +struct mexpr_fwd { typedef typename mexpr_fwd_< IsManipulator, T, @@ -646,13 +586,8 @@ struct mexpr_fwd namespace cppa { -/** - * @brief A function that works on the projection of given data rather than - * on the data itself. - */ template -class match_expr -{ +class match_expr { static_assert(sizeof...(Cases) < 64, "too many functions"); @@ -670,39 +605,32 @@ class match_expr util::tl_exists::value; template - match_expr(Args&&... args) : m_cases(std::forward(args)...) - { + match_expr(Args&&... args) : m_cases(std::forward(args)...) { init(); } - match_expr(match_expr&& other) : m_cases(std::move(other.m_cases)) - { + match_expr(match_expr&& other) : m_cases(std::move(other.m_cases)) { init(); } - match_expr(const match_expr& other) : m_cases(other.m_cases) - { + match_expr(const match_expr& other) : m_cases(other.m_cases) { init(); } - bool invoke(const any_tuple& tup) - { + bool invoke(const any_tuple& tup) { return _invoke(tup); } - bool invoke(any_tuple& tup) - { + bool invoke(any_tuple& tup) { return _invoke(tup); } - bool invoke(any_tuple&& tup) - { + bool invoke(any_tuple&& tup) { any_tuple tmp{tup}; return _invoke(tmp); } - bool can_invoke(any_tuple const tup) - { + bool can_invoke(any_tuple const tup) { auto& type_token = *(tup.type_token()); eval_order token; std::uint64_t tmp = 0; @@ -712,25 +640,21 @@ class match_expr return tmp != 0; } - bool operator()(const any_tuple& tup) - { + bool operator()(const any_tuple& tup) { return _invoke(tup); } - bool operator()(any_tuple& tup) - { + bool operator()(any_tuple& tup) { return _invoke(tup); } - bool operator()(any_tuple&& tup) - { + bool operator()(any_tuple&& tup) { any_tuple tmp{tup}; return _invoke(tmp); } template - bool operator()(Args&&... args) - { + bool operator()(Args&&... args) { typedef detail::tdata< typename detail::mexpr_fwd::type...> tuple_type; @@ -750,7 +674,7 @@ class match_expr typedef typename util::if_else_c< has_manipulator, void*, - util::wrapped + util::wrapped >::type ptr_type; @@ -767,43 +691,40 @@ class match_expr template match_expr - or_else(const match_expr& other) const - { + or_else(const match_expr& other) const { detail::tdata..., ge_reference_wrapper... > all_cases; collect_tdata(all_cases, m_cases, other.cases()); return {all_cases}; } - inline const detail::tdata& cases() const - { + inline const detail::tdata& cases() const { return m_cases; } - struct pfun_impl : partial_function::impl - { + struct pfun_impl : partial_function::impl { match_expr pfun; template pfun_impl(const Arg& from) : pfun(from) { } - bool invoke(any_tuple& tup) - { + bool invoke(any_tuple& tup) { return pfun.invoke(tup); } - bool invoke(const any_tuple& tup) - { + bool invoke(const any_tuple& tup) { return pfun.invoke(tup); } - bool defined_at(const any_tuple& tup) - { + bool defined_at(const any_tuple& tup) { return pfun.can_invoke(tup); } }; - operator partial_function() const - { + inline partial_function as_partial_function() const { return {partial_function::impl_ptr{new pfun_impl(*this)}}; } + inline operator partial_function() const { + return as_partial_function(); + } + private: // structure: tdata< tdata, ...>, @@ -814,11 +735,11 @@ class match_expr static constexpr size_t cache_size = 10; //typedef std::array cache_entry; //typedef typename cache_entry::iterator cache_entry_iterator; - //typedef std::pair cache_element; + //typedef std::pair cache_element; // std::uint64_t is used as a bitmask to enable/disable groups - typedef std::pair cache_element; + typedef std::pair cache_element; util::fixed_vector m_cache; @@ -828,33 +749,27 @@ class match_expr cache_element m_dummy; - static inline void advance_(size_t& i) - { + static inline void advance_(size_t& i) { i = (i + 1) % cache_size; } - inline size_t find_token_pos(std::type_info const* type_token) - { - for (size_t i = m_cache_begin ; i != m_cache_end; advance_(i)) - { + inline size_t find_token_pos(const std::type_info* type_token) { + for (size_t i = m_cache_begin ; i != m_cache_end; advance_(i)) { if (m_cache[i].first == type_token) return i; } return m_cache_end; } template - std::uint64_t get_cache_entry(std::type_info const* type_token, - const Tuple& value) - { + std::uint64_t get_cache_entry(const std::type_info* type_token, + const Tuple& value) { CPPA_REQUIRE(type_token != nullptr); - if (value.impl_type() == detail::dynamically_typed) - { + if (value.impl_type() == detail::dynamically_typed) { return m_dummy.second; // all groups enabled } size_t i = find_token_pos(type_token); // if we didn't found a cache entry ... - if (i == m_cache_end) - { + if (i == m_cache_end) { // ... 'create' one (override oldest element in cache if full) advance_(m_cache_end); if (m_cache_end == m_cache_begin) advance_(m_cache_begin); @@ -868,8 +783,7 @@ class match_expr return m_cache[i].second; } - void init() - { + void init() { m_dummy.second = std::numeric_limits::max(); m_cache.resize(cache_size); for (auto& entry : m_cache) { entry.first = nullptr; } @@ -877,9 +791,8 @@ class match_expr } template - bool _do_invoke(AbstractTuple& vals, NativeDataPtr ndp) - { - std::type_info const* type_token = vals.type_token(); + bool _do_invoke(AbstractTuple& vals, NativeDataPtr ndp) { + const std::type_info* type_token = vals.type_token(); auto bitfield = get_cache_entry(type_token, vals); eval_order token; detail::invoke_helper fun{m_cases, bitfield}; @@ -897,8 +810,7 @@ class match_expr typename std::enable_if< std::is_const::value == false && has_manipulator == true - >::type* = 0) - { + >::type* = 0) { tup.force_detach(); auto& vals = *(tup.vals()); return _do_invoke(vals, vals.mutable_native_data()); @@ -909,8 +821,7 @@ class match_expr typename std::enable_if< std::is_const::value == false && has_manipulator == false - >::type* = 0) - { + >::type* = 0) { return _invoke(static_cast(tup)); } @@ -919,8 +830,7 @@ class match_expr typename std::enable_if< std::is_const::value == true && has_manipulator == false - >::type* = 0) - { + >::type* = 0) { const auto& cvals = *(tup.cvals()); return _do_invoke(cvals, cvals.native_data()); } @@ -930,8 +840,7 @@ class match_expr typename std::enable_if< std::is_const::value == true && has_manipulator == true - >::type* = 0) - { + >::type* = 0) { any_tuple tup_copy{tup}; return _invoke(tup_copy); } @@ -942,15 +851,13 @@ template struct match_expr_from_type_list; template -struct match_expr_from_type_list > -{ +struct match_expr_from_type_list > { typedef match_expr type; }; template inline match_expr operator,(const match_expr& lhs, - const match_expr& rhs) -{ + const match_expr& rhs) { return lhs.or_else(rhs); } @@ -961,8 +868,7 @@ typename match_expr_from_type_list< typename Args::cases_list... >::type >::type -mexpr_concat(const Arg0& arg0, const Args&... args) -{ +mexpr_concat(const Arg0& arg0, const Args&... args) { typename detail::tdata_from_type_list< typename util::tl_map< typename util::tl_concat< @@ -978,8 +884,7 @@ mexpr_concat(const Arg0& arg0, const Args&... args) } template -partial_function mexpr_concat_convert(const Arg0& arg0, const Args&... args) -{ +partial_function mexpr_concat_convert(const Arg0& arg0, const Args&... args) { typename detail::tdata_from_type_list< typename util::tl_map< typename util::tl_concat< @@ -1004,4 +909,4 @@ partial_function mexpr_concat_convert(const Arg0& arg0, const Args&... args) } // namespace cppa -#endif // MATCH_EXPR_HPP +#endif // CPPA_MATCH_EXPR_HPP diff --git a/cppa/object.hpp b/cppa/object.hpp index e53e23daa5..3dd9e0abd2 100644 --- a/cppa/object.hpp +++ b/cppa/object.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef OBJECT_HPP -#define OBJECT_HPP +#ifndef CPPA_OBJECT_HPP +#define CPPA_OBJECT_HPP #include #include @@ -44,10 +44,14 @@ namespace cppa { // forward declarations class object; + +/** + * @relates object + */ bool operator==(const object& lhs, const object& rhs); class uniform_type_info; -uniform_type_info const* uniform_typeid(const std::type_info&); +const uniform_type_info* uniform_typeid(const std::type_info&); bool operator==(const uniform_type_info& lhs, const std::type_info& rhs); /** @@ -74,8 +78,7 @@ const T& get(const object& obj); * @brief An abstraction class that stores an instance of * an announced type. */ -class object -{ +class object { friend bool operator==(const object& lhs, const object& rhs); @@ -88,7 +91,7 @@ class object * @warning {@link object} takes ownership of @p val. * @pre {@code val != nullptr && utinfo != nullptr} */ - object(void* val, uniform_type_info const* utinfo); + object(void* val, const uniform_type_info* utinfo); /** * @brief Creates an empty object. @@ -125,14 +128,14 @@ class object * @returns A {@link uniform_type_info} describing the current * type of @p this. */ - uniform_type_info const* type() const; + const uniform_type_info* type() const; /** * @brief Gets the stored value. * @returns A const pointer to the currently stored value. * @see get(const object&) */ - void const* value() const; + const void* value() const; /** * @brief Gets the stored value. @@ -154,50 +157,44 @@ class object private: void* m_value; - uniform_type_info const* m_type; + const uniform_type_info* m_type; void swap(object& other); }; template -object object::from(T&& what) -{ +object object::from(T&& what) { typedef typename util::rm_ref::type plain_type; typedef typename detail::implicit_conversions::type value_type; auto rtti = uniform_typeid(typeid(value_type)); // throws on error return { new value_type(std::forward(what)), rtti }; } -inline bool operator!=(const object& lhs, const object& rhs) -{ +inline bool operator!=(const object& lhs, const object& rhs) { return !(lhs == rhs); } template -T& get_ref(object& obj) -{ +T& get_ref(object& obj) { static_assert(!std::is_pointer::value && !std::is_reference::value, "T is a reference or a pointer type."); - if (!(*(obj.type()) == typeid(T))) - { + if (!(*(obj.type()) == typeid(T))) { throw std::invalid_argument("obj.type() != typeid(T)"); } return *reinterpret_cast(obj.mutable_value()); } template -const T& get(const object& obj) -{ +const T& get(const object& obj) { static_assert(!std::is_pointer::value && !std::is_reference::value, "T is a reference or a pointer type."); - if (!(*(obj.type()) == typeid(T))) - { + if (!(*(obj.type()) == typeid(T))) { throw std::invalid_argument("obj.type() != typeid(T)"); } - return *reinterpret_cast(obj.value()); + return *reinterpret_cast(obj.value()); } } // namespace cppa -#endif // OBJECT_HPP +#endif // CPPA_OBJECT_HPP diff --git a/cppa/on.hpp b/cppa/on.hpp index ce3297223c..83459bd4bf 100644 --- a/cppa/on.hpp +++ b/cppa/on.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef ON_HPP -#define ON_HPP +#ifndef CPPA_ON_HPP +#define CPPA_ON_HPP #include #include @@ -51,7 +51,6 @@ #include "cppa/detail/boxed.hpp" #include "cppa/detail/unboxed.hpp" -#include "cppa/detail/invokable.hpp" #include "cppa/detail/value_guard.hpp" #include "cppa/detail/ref_counted_impl.hpp" #include "cppa/detail/implicit_conversions.hpp" @@ -59,58 +58,48 @@ namespace cppa { namespace detail { template -struct add_ptr_to_fun_ -{ +struct add_ptr_to_fun_ { typedef T* type; }; template -struct add_ptr_to_fun_ -{ +struct add_ptr_to_fun_ { typedef T type; }; template -struct add_ptr_to_fun : add_ptr_to_fun_::value, T> -{ +struct add_ptr_to_fun : add_ptr_to_fun_::value, T> { }; template -struct to_void_impl -{ +struct to_void_impl { typedef util::void_type type; }; template -struct to_void_impl -{ +struct to_void_impl { typedef typename add_ptr_to_fun::type type; }; template -struct not_callable_to_void : to_void_impl::value || !util::is_callable::value, T> -{ +struct not_callable_to_void : to_void_impl::value || !util::is_callable::value, T> { }; template -struct boxed_and_callable_to_void : to_void_impl::value || util::is_callable::value, T> -{ +struct boxed_and_callable_to_void : to_void_impl::value || util::is_callable::value, T> { }; -class behavior_rvalue_builder -{ +class behavior_rvalue_builder { util::duration m_timeout; public: - constexpr behavior_rvalue_builder(const util::duration& d) : m_timeout(d) - { + constexpr behavior_rvalue_builder(const util::duration& d) : m_timeout(d) { } template - behavior operator>>(F&& f) - { + behavior operator>>(F&& f) { return {m_timeout, std::function{std::forward(f)}}; } @@ -118,9 +107,28 @@ class behavior_rvalue_builder struct rvalue_builder_args_ctor { }; +template +struct disjunct_rvalue_builders { + Left m_left; + Right m_right; + + public: + + disjunct_rvalue_builders(Left l, Right r) : m_left(std::move(l)) + , m_right(std::move(r)) { + } + + template + auto operator>>(Expr expr) + -> decltype((*(static_cast(nullptr)) >> expr).or_else( + *(static_cast(nullptr)) >> expr)) const { + return (m_left >> expr).or_else(m_right >> expr); + } + +}; + template -struct rvalue_builder -{ +struct rvalue_builder { static constexpr bool is_complete = !std::is_same::value; @@ -137,13 +145,11 @@ struct rvalue_builder template rvalue_builder(rvalue_builder_args_ctor, const Args&... args) : m_guard(args...) - , m_funs(args...) - { + , m_funs(args...) { } rvalue_builder(Guard arg0, fun_container arg1) - : m_guard(std::move(arg0)), m_funs(std::move(arg1)) - { + : m_guard(std::move(arg0)), m_funs(std::move(arg1)) { } template @@ -158,8 +164,7 @@ struct rvalue_builder typename std::enable_if< std::is_same::value && !std::is_same >>::value - >::type* = 0 ) const - { + >::type* = 0 ) const { return {(ge_sub_function(m_guard) && ng), std::move(m_funs)}; } @@ -169,15 +174,13 @@ struct rvalue_builder typename std::enable_if< std::is_same::value && std::is_same >>::value - >::type* = 0 ) const - { + >::type* = 0 ) const { return {std::move(ng), std::move(m_funs)}; } template match_expr::type> - operator>>(Expr expr) const - { + operator>>(Expr expr) const { typedef typename get_case< is_complete, Expr, @@ -191,11 +194,15 @@ struct rvalue_builder std::move(m_guard)}}; } + template + disjunct_rvalue_builders operator||(Other other) const { + return {*this, std::move(other)}; + } + }; template -struct pattern_type_ -{ +struct pattern_type_ { typedef util::get_callable_trait ctrait; typedef typename ctrait::arg_types args; static_assert(args::size == 1, "only unary functions allowed"); @@ -203,8 +210,7 @@ struct pattern_type_ }; template -struct pattern_type_ -{ +struct pattern_type_ { typedef typename implicit_conversions< typename util::rm_ref< typename detail::unboxed::type @@ -214,46 +220,9 @@ struct pattern_type_ }; template -struct pattern_type : pattern_type_::value && !detail::is_boxed::value, T> -{ +struct pattern_type : pattern_type_::value && !detail::is_boxed::value, T> { }; -class on_the_fly_rvalue_builder -{ - - public: - - constexpr on_the_fly_rvalue_builder() - { - } - - - template - match_expr< - typename get_case< - false, - Expr, - value_guard< util::type_list<> >, - util::type_list<>, - util::type_list<> - >::type> - operator>>(Expr expr) const - { - typedef typename get_case< - false, - Expr, - value_guard< util::type_list<> >, - util::type_list<>, - util::type_list<> - >::type - result; - return result{typename result::first_type{}, - typename result::second_type{ - std::move(expr), - value_guard< util::type_list<> >{}}}; - } - -}; } } // cppa::detail @@ -319,8 +288,7 @@ ___ on(); #else template -constexpr typename detail::boxed::type val() -{ +constexpr typename detail::boxed::type val() { return typename detail::boxed::type(); } @@ -330,8 +298,6 @@ typedef typename detail::boxed::type boxed_arg_match_t; constexpr boxed_arg_match_t arg_match = boxed_arg_match_t(); -constexpr detail::on_the_fly_rvalue_builder on_arg_match; - template detail::rvalue_builder< detail::value_guard< @@ -349,8 +315,7 @@ detail::rvalue_builder< >::type, util::type_list::type, typename detail::pattern_type::type...> > -on(const Arg0& arg0, const Args&... args) -{ +on(const Arg0& arg0, const Args&... args) { return {detail::rvalue_builder_args_ctor{}, arg0, args...}; } @@ -358,50 +323,89 @@ template detail::rvalue_builder >, util::type_list<>, util::type_list > -on() -{ +on() { return {}; } template -decltype(on(A0, val()...)) on() -{ +decltype(on(A0, val()...)) on() { return on(A0, val()...); } template -decltype(on(A0, A1, val()...)) on() -{ +decltype(on(A0, A1, val()...)) on() { return on(A0, A1, val()...); } template -decltype(on(A0, A1, A2, val()...)) on() -{ +decltype(on(A0, A1, A2, val()...)) on() { return on(A0, A1, A2, val()...); } template -decltype(on(A0, A1, A2, A3, val()...)) on() -{ +decltype(on(A0, A1, A2, A3, val()...)) on() { return on(A0, A1, A2, A3, val()...); } template constexpr detail::behavior_rvalue_builder -after(const std::chrono::duration& d) -{ +after(const std::chrono::duration& d) { return { util::duration(d) }; } -inline decltype(on()) others() -{ +inline decltype(on()) others() { return on(); } +// some more convenience + +namespace detail { + +class on_the_fly_rvalue_builder { + + public: + + constexpr on_the_fly_rvalue_builder() { + } + + template + auto when(Guard g) const -> decltype(on(arg_match).when(g)) { + return on(arg_match).when(g); + } + + template + match_expr< + typename get_case< + false, + Expr, + value_guard< util::type_list<> >, + util::type_list<>, + util::type_list<> + >::type> + operator>>(Expr expr) const { + typedef typename get_case< + false, + Expr, + value_guard< util::type_list<> >, + util::type_list<>, + util::type_list<> + >::type + result; + return result{typename result::first_type{}, + typename result::second_type{ + std::move(expr), + value_guard< util::type_list<> >{}}}; + } + +}; + +} // namespace detail + +constexpr detail::on_the_fly_rvalue_builder on_arg_match; + #endif } // namespace cppa -#endif // ON_HPP +#endif // CPPA_ON_HPP diff --git a/cppa/option.hpp b/cppa/option.hpp index 6cc7bc13ed..4119677fb8 100644 --- a/cppa/option.hpp +++ b/cppa/option.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef OPTION_HPP -#define OPTION_HPP +#ifndef CPPA_OPTION_HPP +#define CPPA_OPTION_HPP #include #include @@ -41,15 +41,14 @@ namespace cppa { * @brief Represents an optional value of @p T. */ template -class option -{ +class option { public: /** * @brief Typdef for @p T. */ - typedef T value_type; + typedef T type; /** * @brief Default constructor. @@ -61,63 +60,47 @@ class option * @brief Creates an @p option from @p value. * @post valid() == true */ - option(T&& value) : m_valid(false) { cr(std::move(value)); } + option(T value) : m_valid(false) { cr(std::move(value)); } - /** - * @brief Creates an @p option from @p value. - * @post valid() == true - */ - option(const T& value) : m_valid(false) { cr(value); } - - option(const option& other) : m_valid(false) - { + option(const option& other) : m_valid(false) { if (other.m_valid) cr(other.m_value); } - option(option&& other) : m_valid(false) - { + option(option&& other) : m_valid(false) { if (other.m_valid) cr(std::move(other.m_value)); } ~option() { destroy(); } - option& operator=(const option& other) - { - if (m_valid) - { + option& operator=(const option& other) { + if (m_valid) { if (other.m_valid) m_value = other.m_value; else destroy(); } - else if (other.m_valid) - { + else if (other.m_valid) { cr(other.m_value); } return *this; } - option& operator=(option&& other) - { - if (m_valid) - { + option& operator=(option&& other) { + if (m_valid) { if (other.m_valid) m_value = std::move(other.m_value); else destroy(); } - else if (other.m_valid) - { + else if (other.m_valid) { cr(std::move(other.m_value)); } return *this; } - option& operator=(const T& value) - { + option& operator=(const T& value) { if (m_valid) m_value = value; else cr(value); return *this; } - option& operator=(T& value) - { + option& operator=(T& value) { if (m_valid) m_value = std::move(value); else cr(std::move(value)); return *this; @@ -129,21 +112,22 @@ class option */ inline bool valid() const { return m_valid; } + inline bool empty() const { return !m_valid; } + /** * @copydoc valid() */ - inline explicit operator bool() const { return m_valid; } + inline explicit operator bool() const { return valid(); } /** * @brief Returns !valid() */ - inline bool operator!() const { return !m_valid; } + inline bool operator!() const { return empty(); } /** * @brief Returns the value. */ - inline T& operator*() - { + inline T& operator*() { CPPA_REQUIRE(valid()); return m_value; } @@ -151,8 +135,7 @@ class option /** * @brief Returns the value. */ - inline const T& operator*() const - { + inline const T& operator*() const { CPPA_REQUIRE(valid()); return m_value; } @@ -160,8 +143,7 @@ class option /** * @brief Returns the value. */ - inline T& get() - { + inline T& get() { CPPA_REQUIRE(valid()); return m_value; } @@ -169,8 +151,7 @@ class option /** * @brief Returns the value. */ - inline const T& get() const - { + inline const T& get() const { CPPA_REQUIRE(valid()); return m_value; } @@ -180,19 +161,9 @@ class option * if valid() == false. * @post valid() == true */ - inline T& get_or_else(const T& default_value) - { - if (!m_valid) cr(default_value); - return m_value; - } - - /** - * @copydoc get_or_else(const T&) - */ - inline T& get_or_else(T&& default_value) - { - if (!m_valid) cr(std::move(default_value)); - return m_value; + inline const T& get_or_else(const T& default_value) const { + if (valid()) return get(); + return default_value; } private: @@ -200,18 +171,15 @@ class option bool m_valid; union { T m_value; }; - void destroy() - { - if (m_valid) - { + void destroy() { + if (m_valid) { m_value.~T(); m_valid = false; } } template - void cr(V&& value) - { + void cr(V&& value) { CPPA_REQUIRE(!valid()); m_valid = true; new (&m_value) T (std::forward(value)); @@ -221,48 +189,42 @@ class option /** @relates option */ template -bool operator==(const option& lhs, const option& rhs) -{ +bool operator==(const option& lhs, const option& rhs) { if ((lhs) && (rhs)) return *lhs == *rhs; return false; } /** @relates option */ template -bool operator==(const option& lhs, const U& rhs) -{ +bool operator==(const option& lhs, const U& rhs) { if (lhs) return *lhs == rhs; return false; } /** @relates option */ template -bool operator==(const T& lhs, const option& rhs) -{ +bool operator==(const T& lhs, const option& rhs) { return rhs == lhs; } /** @relates option */ template -bool operator!=(const option& lhs, const option& rhs) -{ +bool operator!=(const option& lhs, const option& rhs) { return !(lhs == rhs); } /** @relates option */ template -bool operator!=(const option& lhs, const U& rhs) -{ +bool operator!=(const option& lhs, const U& rhs) { return !(lhs == rhs); } /** @relates option */ template -bool operator!=(const T& lhs, const option& rhs) -{ +bool operator!=(const T& lhs, const option& rhs) { return !(lhs == rhs); } } // namespace cppa -#endif // OPTION_HPP +#endif // CPPA_OPTION_HPP diff --git a/cppa/partial_function.hpp b/cppa/partial_function.hpp index 6594331ff0..bf22cb40b9 100644 --- a/cppa/partial_function.hpp +++ b/cppa/partial_function.hpp @@ -28,15 +28,16 @@ \******************************************************************************/ -#ifndef PARTIAL_FUNCTION_HPP -#define PARTIAL_FUNCTION_HPP +#ifndef CPPA_PARTIAL_FUNCTION_HPP +#define CPPA_PARTIAL_FUNCTION_HPP #include #include #include #include -#include "cppa/detail/invokable.hpp" +#include "cppa/ref_counted.hpp" +#include "cppa/intrusive_ptr.hpp" #include "cppa/intrusive/singly_linked_list.hpp" namespace cppa { @@ -47,59 +48,53 @@ class behavior; * @brief A partial function implementation * for {@link cppa::any_tuple any_tuples}. */ -class partial_function -{ - - partial_function(const partial_function&) = delete; - partial_function& operator=(const partial_function&) = delete; +class partial_function { public: - struct impl - { - virtual ~impl(); + struct impl : ref_counted { virtual bool invoke(any_tuple&) = 0; virtual bool invoke(const any_tuple&) = 0; virtual bool defined_at(const any_tuple&) = 0; }; - typedef std::unique_ptr impl_ptr; + typedef intrusive_ptr impl_ptr; partial_function() = default; partial_function(partial_function&&) = default; + partial_function(const partial_function&) = default; partial_function& operator=(partial_function&&) = default; + partial_function& operator=(const partial_function&) = default; partial_function(impl_ptr&& ptr); - inline bool defined_at(const any_tuple& value) - { - return ((m_impl) && m_impl->defined_at(value)); + inline bool defined_at(const any_tuple& value) { + return (m_impl) && m_impl->defined_at(value); } - inline bool operator()(any_tuple& value) - { - return ((m_impl) && m_impl->invoke(value)); + inline bool operator()(any_tuple& value) { + return (m_impl) && m_impl->invoke(value); } - inline bool operator()(const any_tuple& value) - { - return ((m_impl) && m_impl->invoke(value)); + inline bool operator()(const any_tuple& value) { + return (m_impl) && m_impl->invoke(value); } - inline bool operator()(any_tuple&& value) - { + inline bool operator()(any_tuple&& value) { any_tuple cpy{std::move(value)}; return (*this)(cpy); } + inline bool undefined() const { + return m_impl == nullptr; + } + private: impl_ptr m_impl; }; -//behavior operator,(partial_function&& lhs, behavior&& rhs); - } // namespace cppa -#endif // PARTIAL_FUNCTION_HPP +#endif // CPPA_PARTIAL_FUNCTION_HPP diff --git a/cppa/pattern.hpp b/cppa/pattern.hpp index 259066b52b..d26740b914 100644 --- a/cppa/pattern.hpp +++ b/cppa/pattern.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef LIBCPPA_PATTERN_HPP -#define LIBCPPA_PATTERN_HPP +#ifndef CPPA_PATTERN_HPP +#define CPPA_PATTERN_HPP #include @@ -42,7 +42,6 @@ #include "cppa/option.hpp" #include "cppa/anything.hpp" #include "cppa/any_tuple.hpp" -#include "cppa/type_value_pair.hpp" #include "cppa/uniform_type_info.hpp" #include "cppa/util/guard.hpp" @@ -59,8 +58,11 @@ namespace cppa { -enum class wildcard_position -{ +/** + * @brief Denotes the position of {@link cppa::anything anything} in a + * template parameter pack. + */ +enum class wildcard_position { nil, trailing, leading, @@ -68,9 +70,13 @@ enum class wildcard_position multiple }; +/** + * @brief Gets the position of {@link cppa::anything anything} from the + * type list @p Types. + * @tparam A template parameter pack as {@link cppa::util::type_list type_list}. + */ template -constexpr wildcard_position get_wildcard_position() -{ +constexpr wildcard_position get_wildcard_position() { return util::tl_exists::value ? ((util::tl_count::value == 1) ? (std::is_same::value @@ -82,38 +88,32 @@ constexpr wildcard_position get_wildcard_position() : wildcard_position::nil; } -struct value_matcher -{ +struct value_matcher { const bool is_dummy; inline value_matcher(bool dummy_impl = false) : is_dummy(dummy_impl) { } virtual ~value_matcher(); virtual bool operator()(const any_tuple&) const = 0; }; -struct dummy_matcher : value_matcher -{ +struct dummy_matcher : value_matcher { inline dummy_matcher() : value_matcher(true) { } bool operator()(const any_tuple&) const; }; -struct cmp_helper -{ +struct cmp_helper { size_t i; const any_tuple& tup; cmp_helper(const any_tuple& tp, size_t pos = 0) : i(pos), tup(tp) { } template - inline bool operator()(const T& what) - { + inline bool operator()(const T& what) { return what == tup.get_as(i++); } template - inline bool operator()(std::unique_ptr const >& g) - { + inline bool operator()(std::unique_ptr const >& g) { return (*g)(tup.get_as(i++)); } template - inline bool operator()(const util::wrapped&) - { + inline bool operator()(const util::wrapped&) { ++i; return true; } @@ -125,8 +125,7 @@ class value_matcher_impl; template class value_matcher_impl, - util::type_list > : public value_matcher -{ + util::type_list > : public value_matcher { detail::tdata m_values; @@ -135,8 +134,7 @@ class value_matcher_impl value_matcher_impl(Args&&... args) : m_values(std::forward(args)...) { } - bool operator()(const any_tuple& tup) const - { + bool operator()(const any_tuple& tup) const { cmp_helper h{tup}; return util::static_foreach<0, sizeof...(Vs)>::eval(m_values, h); } @@ -149,8 +147,7 @@ class value_matcher_impl > : public value_matcher_impl, - util::type_list > -{ + util::type_list > { typedef value_matcher_impl, @@ -167,8 +164,7 @@ class value_matcher_impl class value_matcher_impl, - util::type_list > : public value_matcher -{ + util::type_list > : public value_matcher { detail::tdata m_values; @@ -177,8 +173,7 @@ class value_matcher_impl value_matcher_impl(Args&&... args) : m_values(std::forward(args)...) { } - bool operator()(const any_tuple& tup) const - { + bool operator()(const any_tuple& tup) const { cmp_helper h{tup, tup.size() - sizeof...(Ts)}; return util::static_foreach<0, sizeof...(Vs)>::eval(m_values, h); } @@ -188,8 +183,7 @@ class value_matcher_impl class value_matcher_impl, - util::type_list > : public value_matcher -{ + util::type_list > : public value_matcher { detail::tdata m_values; @@ -198,8 +192,7 @@ class value_matcher_impl value_matcher_impl(Args&&... args) : m_values(std::forward(args)...) { } - bool operator()(const any_tuple& tup) const - { + bool operator()(const any_tuple& tup) const { static constexpr size_t wcpos = static_cast(util::tl_find, anything>::value); static_assert(wcpos < sizeof...(Ts), "illegal wildcard position"); @@ -217,24 +210,24 @@ class value_matcher_impl class value_matcher_impl, - util::type_list > : public value_matcher -{ + util::type_list > : public value_matcher { public: template value_matcher_impl(Args&&...) { } - bool operator()(const any_tuple&) const - { + bool operator()(const any_tuple&) const { throw std::runtime_error("not implemented yet, sorry"); } }; +/** + * @brief A pattern matching for type and optionally value of tuple elements. + */ template -class pattern -{ +class pattern { static_assert(sizeof...(Types) > 0, "empty pattern"); @@ -248,6 +241,9 @@ class pattern static constexpr wildcard_position wildcard_pos = get_wildcard_position >(); + /** + * @brief Parameter pack as {@link cppa::util::type_list type_list}. + */ typedef util::type_list types; typedef typename types::head head_type; @@ -259,73 +255,61 @@ class pattern typedef util::fixed_vector mapping_vector; - typedef uniform_type_info const* const_iterator; + typedef const uniform_type_info* const_iterator; typedef std::reverse_iterator reverse_const_iterator; - inline const_iterator begin() const - { + inline const_iterator begin() const { return detail::static_types_array::arr.begin(); } - inline const_iterator end() const - { + inline const_iterator end() const { return detail::static_types_array::arr.end(); } - inline reverse_const_iterator rbegin() const - { + inline reverse_const_iterator rbegin() const { return reverse_const_iterator{end()}; } - inline reverse_const_iterator rend() const - { + inline reverse_const_iterator rend() const { return reverse_const_iterator{begin()}; } inline bool has_values() const { return m_vm->is_dummy == false; } // @warning does NOT check types - bool _matches_values(const any_tuple& tup) const - { + bool _matches_values(const any_tuple& tup) const { return (*m_vm)(tup); } - pattern() : m_vm(new dummy_matcher) - { + pattern() : m_vm(new dummy_matcher) { } template pattern(head_type arg0, Args&&... args) - : m_vm(get_value_matcher(std::move(arg0), std::forward(args)...)) - { + : m_vm(get_value_matcher(std::move(arg0), std::forward(args)...)) { } template pattern(const util::wrapped& arg0, Args&&... args) - : m_vm(get_value_matcher(arg0, std::forward(args)...)) - { + : m_vm(get_value_matcher(arg0, std::forward(args)...)) { } template - pattern(const detail::tdata& data) - { + pattern(const detail::tdata& data) { m_vm.reset(new value_matcher_impl >{data}); } - pattern(std::unique_ptr&& vm) : m_vm(std::move(vm)) - { + pattern(std::unique_ptr&& vm) : m_vm(std::move(vm)) { if (!m_vm) m_vm.reset(new dummy_matcher); } - static inline value_matcher* get_value_matcher() - { + static inline value_matcher* get_value_matcher() { return nullptr; } template - static value_matcher* get_value_matcher(Arg0&& arg0, Args&&... args) - { + static value_matcher* get_value_matcher(Arg0&& arg0, Args&&... args) { using namespace util; typedef typename tl_filter_not< type_list::type, @@ -334,8 +318,7 @@ class pattern >::type arg_types; static_assert(arg_types::size <= size, "too many arguments"); - if (tl_forall::value) - { + if (tl_forall::value) { return new dummy_matcher; } return new value_matcher_impl{std::forward(arg0), std::forward(args)...}; @@ -343,25 +326,6 @@ class pattern private: - typedef type_value_pair tvp_array[size]; - - // a polymophic functor - struct init_helper - { - size_t i; - tvp_array& m_ptrs; - detail::types_array& m_arr; - init_helper(tvp_array& ptrs, detail::types_array& tarr) - : i(0), m_ptrs(ptrs), m_arr(tarr) { } - template - inline void operator()(const option& what) - { - m_ptrs[i].first = m_arr[i]; - m_ptrs[i].second = (what) ? &(*what) : nullptr; - ++i; - } - }; - std::unique_ptr m_vm; }; @@ -370,11 +334,10 @@ template struct pattern_from_type_list; template -struct pattern_from_type_list> -{ +struct pattern_from_type_list> { typedef pattern type; }; } // namespace cppa -#endif // PATTERN_HPP +#endif // CPPA_PATTERN_HPP diff --git a/cppa/primitive_type.hpp b/cppa/primitive_type.hpp index f43309380b..36015fa6ee 100644 --- a/cppa/primitive_type.hpp +++ b/cppa/primitive_type.hpp @@ -28,21 +28,21 @@ \******************************************************************************/ -#ifndef PRIMITIVE_TYPE_HPP -#define PRIMITIVE_TYPE_HPP +#ifndef CPPA_PRIMITIVE_TYPE_HPP +#define CPPA_PRIMITIVE_TYPE_HPP namespace cppa { /** * @ingroup TypeSystem - * @brief Represents a type flag of {@link primitive_variant}. + * @brief Represents the type flag of + * {@link cppa::primitive_variant primitive_variant}. * * Includes integers (signed and unsigned), floating points - * and unicode strings (std::string, std::u16string and std::u32string). + * and strings (std::string, std::u16string and std::u32string). * @relates primitive_variant */ -enum primitive_type -{ +enum primitive_type { pt_int8, /**< equivalent of @p std::int8_t */ pt_int16, /**< equivalent of @p std::int16_t */ pt_int32, /**< equivalent of @p std::int32_t */ @@ -60,8 +60,7 @@ enum primitive_type pt_null /**< equivalent of @p void */ }; -constexpr char const* primitive_type_names[] = -{ +constexpr const char* primitive_type_names[] = { "pt_int8", "pt_int16", "pt_int32", "pt_int64", "pt_uint8", "pt_uint16", "pt_uint32", "pt_uint64", "pt_float", "pt_double", "pt_long_double", @@ -75,11 +74,10 @@ constexpr char const* primitive_type_names[] = * @param ptype Requestet @p primitive_type. * @returns A C-string representation of @p ptype. */ -constexpr char const* primitive_type_name(primitive_type ptype) -{ +constexpr const char* primitive_type_name(primitive_type ptype) { return primitive_type_names[static_cast(ptype)]; } } // namespace cppa -#endif // PRIMITIVE_TYPE_HPP +#endif // CPPA_PRIMITIVE_TYPE_HPP diff --git a/cppa/primitive_variant.hpp b/cppa/primitive_variant.hpp index 512b8384ce..2d54107256 100644 --- a/cppa/primitive_variant.hpp +++ b/cppa/primitive_variant.hpp @@ -28,11 +28,12 @@ \******************************************************************************/ -#ifndef PRIMITIVE_VARIANT_HPP -#define PRIMITIVE_VARIANT_HPP +#ifndef CPPA_PRIMITIVE_VARIANT_HPP +#define CPPA_PRIMITIVE_VARIANT_HPP #include #include +#include #include #include @@ -71,11 +72,10 @@ T& get_ref(primitive_variant& pv); * @ingroup TypeSystem * @brief An union container for primitive data types. */ -class primitive_variant -{ +class primitive_variant { - friend bool operator==(const primitive_variant& lhs, - const primitive_variant& rhs); + friend bool equal(const primitive_variant& lhs, + const primitive_variant& rhs); template friend const T& get(const primitive_variant& pv); @@ -85,8 +85,7 @@ class primitive_variant primitive_type m_ptype; - union - { + union { std::int8_t i8; std::int16_t i16; std::int32_t i32; @@ -104,38 +103,35 @@ class primitive_variant }; // use static call dispatching to select member - inline decltype(i8)& get(util::pt_token) { return i8; } - inline decltype(i16)& get(util::pt_token) { return i16; } - inline decltype(i32)& get(util::pt_token) { return i32; } - inline decltype(i64)& get(util::pt_token) { return i64; } - inline decltype(u8)& get(util::pt_token) { return u8; } - inline decltype(u16)& get(util::pt_token) { return u16; } - inline decltype(u32)& get(util::pt_token) { return u32; } - inline decltype(u64)& get(util::pt_token) { return u64; } - inline decltype(fl)& get(util::pt_token) { return fl; } - inline decltype(db)& get(util::pt_token) { return db; } - inline decltype(ldb)& get(util::pt_token) { return ldb; } - inline decltype(s8)& get(util::pt_token) { return s8; } - inline decltype(s16)& get(util::pt_token) { return s16; } - inline decltype(s32)& get(util::pt_token) { return s32; } + inline auto get(util::pt_token) -> decltype(i8)& { return i8; } + inline auto get(util::pt_token) -> decltype(i16)& { return i16; } + inline auto get(util::pt_token) -> decltype(i32)& { return i32; } + inline auto get(util::pt_token) -> decltype(i64)& { return i64; } + inline auto get(util::pt_token) -> decltype(u8)& { return u8; } + inline auto get(util::pt_token) -> decltype(u16)& { return u16; } + inline auto get(util::pt_token) -> decltype(u32)& { return u32; } + inline auto get(util::pt_token) -> decltype(u64)& { return u64; } + inline auto get(util::pt_token) -> decltype(fl)& { return fl; } + inline auto get(util::pt_token) -> decltype(db)& { return db; } + inline auto get(util::pt_token) -> decltype(ldb)& { return ldb; } + inline auto get(util::pt_token) -> decltype(s8)& { return s8; } + inline auto get(util::pt_token) -> decltype(s16)& { return s16; } + inline auto get(util::pt_token) -> decltype(s32)& { return s32; } // get(...) const overload template const typename detail::ptype_to_type::type& - get(util::pt_token token) const - { + get(util::pt_token token) const { return const_cast(this)->get(token); } template - struct applier - { + struct applier { Self* m_parent; Fun& m_f; applier(Self* parent, Fun& f) : m_parent(parent), m_f(f) { } template - inline void operator()(util::pt_token token) - { + inline void operator()(util::pt_token token) { m_f(m_parent->get(token)); } }; @@ -143,14 +139,12 @@ class primitive_variant void destroy(); template - void type_check() const - { + void type_check() const { if (m_ptype != PT) throw std::logic_error("type check failed"); } template - typename detail::ptype_to_type::type& get_as() - { + typename detail::ptype_to_type::type& get_as() { static_assert(PT != pt_null, "PT == pt_null"); type_check(); util::pt_token token; @@ -158,8 +152,7 @@ class primitive_variant } template - const typename detail::ptype_to_type::type& get_as() const - { + const typename detail::ptype_to_type::type& get_as() const { static_assert(PT != pt_null, "PT == pt_null"); type_check(); util::pt_token token; @@ -169,14 +162,12 @@ class primitive_variant public: template - void apply(Fun&& f) - { + void apply(Fun&& f) { util::pt_dispatch(m_ptype, applier(this, f)); } template - void apply(Fun&& f) const - { + void apply(Fun&& f) const { util::pt_dispatch(m_ptype, applier(this, f)); } @@ -193,8 +184,7 @@ class primitive_variant * @pre @p value does have a primitive type. */ template - primitive_variant(V&& value) : m_ptype(pt_null) - { + primitive_variant(V&& value) : m_ptype(pt_null) { static constexpr primitive_type ptype = detail::type_to_ptype::ptype; static_assert(ptype != pt_null, "V is not a primitive type"); detail::ptv_set(m_ptype, @@ -228,17 +218,14 @@ class primitive_variant * @returns *this. */ template - primitive_variant& operator=(V&& value) - { + primitive_variant& operator=(V&& value) { static constexpr primitive_type ptype = detail::type_to_ptype::ptype; static_assert(ptype != pt_null, "V is not a primitive type"); util::pt_token token; - if (ptype == m_ptype) - { + if (ptype == m_ptype) { get(token) = std::forward(value); } - else - { + else { destroy(); detail::ptv_set(m_ptype, get(token), std::forward(value)); //set(std::forward(value)); @@ -287,8 +274,7 @@ class primitive_variant * @throws std::logic_error if @p pv is not of type @p T. */ template -const T& get(const primitive_variant& pv) -{ +const T& get(const primitive_variant& pv) { static const primitive_type ptype = detail::type_to_ptype::ptype; return pv.get_as(); } @@ -302,8 +288,7 @@ const T& get(const primitive_variant& pv) * @throws std::logic_error if @p pv is not of type @p T. */ template -T& get_ref(primitive_variant& pv) -{ +T& get_ref(primitive_variant& pv) { static const primitive_type ptype = detail::type_to_ptype::ptype; return pv.get_as(); } @@ -336,58 +321,41 @@ T& get_ref(primitive_variant& pv); template inline const typename detail::ptype_to_type::type& -get(const primitive_variant& pv) -{ +get(const primitive_variant& pv) { static_assert(PT != pt_null, "PT == pt_null"); return get::type>(pv); } template inline typename detail::ptype_to_type::type& -get_ref(primitive_variant& pv) -{ +get_ref(primitive_variant& pv) { static_assert(PT != pt_null, "PT == pt_null"); return get_ref::type>(pv); } #endif -bool operator==(const primitive_variant& lhs, const primitive_variant& rhs); - -inline -bool operator!=(const primitive_variant& lhs, const primitive_variant& rhs) -{ - return !(lhs == rhs); -} +/** + * @relates primitive_variant + */ +bool equal(const primitive_variant& lhs, const primitive_variant& rhs); +/** + * @relates primitive_variant + */ template -typename std::enable_if::value, bool>::type -operator==(const T& lhs, const primitive_variant& rhs) -{ +bool equal(const T& lhs, const primitive_variant& rhs) { static constexpr primitive_type ptype = detail::type_to_ptype::ptype; static_assert(ptype != pt_null, "T is an incompatible type"); return (rhs.ptype() == ptype) ? lhs == get(rhs) : false; } +/** + * @relates primitive_variant + */ template -typename std::enable_if::value, bool>::type -operator==(const primitive_variant& lhs, const T& rhs) -{ - return (rhs == lhs); -} - -template -typename std::enable_if::value, bool>::type -operator!=(const primitive_variant& lhs, const T& rhs) -{ - return !(lhs == rhs); -} - -template -typename std::enable_if::value, bool>::type -operator!=(const T& lhs, const primitive_variant& rhs) -{ - return !(lhs == rhs); +inline bool equal(const primitive_variant& lhs, const T& rhs) { + return equal(rhs, lhs); } } // namespace cppa @@ -396,14 +364,11 @@ namespace cppa { namespace detail { template void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs, - typename std::enable_if::value>::type*) -{ - if (FT == lhs_type) - { + typename std::enable_if::value>::type*) { + if (FT == lhs_type) { lhs = std::forward(rhs); } - else - { + else { new (&lhs) T(std::forward(rhs)); lhs_type = FT; } @@ -411,9 +376,8 @@ void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs, template void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs, - typename std::enable_if::value, int>::type*) -{ - // don't call a constructor for arithmetic types + typename std::enable_if::value, int>::type*) { + // never call constructors for arithmetic types lhs = rhs; lhs_type = FT; } @@ -421,4 +385,4 @@ void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs, } } // namespace cppa::detail -#endif // PRIMITIVE_VARIANT_HPP +#endif // CPPA_PRIMITIVE_VARIANT_HPP diff --git a/cppa/process_information.hpp b/cppa/process_information.hpp index 772559f854..639210b21d 100644 --- a/cppa/process_information.hpp +++ b/cppa/process_information.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef PROCESS_INFORMATION_HPP -#define PROCESS_INFORMATION_HPP +#ifndef CPPA_PROCESS_INFORMATION_HPP +#define CPPA_PROCESS_INFORMATION_HPP #include #include @@ -45,8 +45,7 @@ namespace cppa { * @brief Identifies a process. */ class process_information : public ref_counted, - util::comparable -{ + util::comparable { typedef ref_counted super; @@ -117,11 +116,13 @@ bool equal(const std::string& hash, const process_information::node_id_type& node_id); inline bool equal(const process_information::node_id_type& node_id, - const std::string& hash) -{ + const std::string& hash) { return equal(hash, node_id); } +/** + * @relates process_information + */ std::string to_string(const process_information& what); /** @@ -129,15 +130,17 @@ std::string to_string(const process_information& what); * to a hexadecimal string. * @param node_id A unique node identifier. * @returns A hexadecimal representation of @p node_id. + * @relates process_information */ std::string to_string(const process_information::node_id_type& node_id); /** * @brief A smart pointer type that manages instances of * {@link process_information}. + * @relates process_information */ typedef intrusive_ptr process_information_ptr; } // namespace cppa -#endif // PROCESS_INFORMATION_HPP +#endif // CPPA_PROCESS_INFORMATION_HPP diff --git a/cppa/receive.hpp b/cppa/receive.hpp index a693e2520d..bc1a4cafbe 100644 --- a/cppa/receive.hpp +++ b/cppa/receive.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef RECEIVE_HPP -#define RECEIVE_HPP +#ifndef CPPA_RECEIVE_HPP +#define CPPA_RECEIVE_HPP #include "cppa/self.hpp" #include "cppa/behavior.hpp" @@ -122,8 +122,7 @@ inline void receive(behavior& bhvr) { self->dequeue(bhvr); } inline void receive(partial_function& fun) { self->dequeue(fun); } template -void receive(Arg0&& arg0, Args&&... args) -{ +void receive(Arg0&& arg0, Args&&... args) { auto tmp = match_expr_concat(std::forward(arg0), std::forward(args)...); receive(tmp); @@ -134,30 +133,26 @@ void receive_loop(behavior& rules); void receive_loop(partial_function& rules); template -void receive_loop(Arg0&& arg0, Args&&... args) -{ +void receive_loop(Arg0&& arg0, Args&&... args) { auto tmp = match_expr_concat(std::forward(arg0), std::forward(args)...); receive_loop(tmp); } template -detail::receive_for_helper receive_for(T& begin, const T& end) -{ +detail::receive_for_helper receive_for(T& begin, const T& end) { return {begin, end}; } template -detail::receive_while_helper receive_while(Statement&& stmt) -{ +detail::receive_while_helper receive_while(Statement&& stmt) { static_assert(std::is_same::value, "functor or function does not return a boolean"); return std::move(stmt); } template -detail::do_receive_helper do_receive(Args&&... args) -{ +detail::do_receive_helper do_receive(Args&&... args) { return detail::do_receive_helper(std::forward(args)...); } @@ -165,4 +160,4 @@ detail::do_receive_helper do_receive(Args&&... args) } // namespace cppa -#endif // RECEIVE_HPP +#endif // CPPA_RECEIVE_HPP diff --git a/cppa/ref_counted.hpp b/cppa/ref_counted.hpp index 81d92f77e1..7c74701887 100644 --- a/cppa/ref_counted.hpp +++ b/cppa/ref_counted.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef LIBCPPA_REF_COUNTED_HPP -#define LIBCPPA_REF_COUNTED_HPP +#ifndef CPPA_REF_COUNTED_HPP +#define CPPA_REF_COUNTED_HPP #include #include @@ -47,8 +47,7 @@ namespace cppa { * Serves the requirements of {@link intrusive_ptr}. * @relates intrusive_ptr */ -class ref_counted -{ +class ref_counted { public: @@ -80,4 +79,4 @@ typedef detail::ref_counted_impl< std::atomic > ref_counted; } // namespace cppa -#endif // LIBCPPA_REF_COUNTED_HPP +#endif // CPPA_REF_COUNTED_HPP diff --git a/cppa/fsm_actor.hpp b/cppa/sb_actor.hpp similarity index 85% rename from cppa/fsm_actor.hpp rename to cppa/sb_actor.hpp index 49c2043e56..2d43b90eae 100644 --- a/cppa/fsm_actor.hpp +++ b/cppa/sb_actor.hpp @@ -28,39 +28,32 @@ \******************************************************************************/ -#ifndef FSM_ACTOR_HPP -#define FSM_ACTOR_HPP +#ifndef CPPA_FSM_ACTOR_HPP +#define CPPA_FSM_ACTOR_HPP -#include - -#include "cppa/util/rm_ref.hpp" #include "cppa/event_based_actor.hpp" namespace cppa { /** - * @brief A base class for event-based actors using the + * @brief A base class for state-based actors using the * Curiously Recurring Template Pattern * to initialize the derived actor with its @p init_state member. - * @tparam Derived Subclass of fsm_actor. + * @tparam Derived Direct subclass of @p sb_actor. */ template -class fsm_actor : public event_based_actor -{ +class sb_actor : public event_based_actor { public: /** - * @brief Overrides abstract_event_based_actor::init() and sets + * @brief Overrides {@link event_based_actor::init()} and sets * the initial actor behavior to Derived::init_state. */ - void init() - { - become(&(static_cast(this)->init_state)); - } + void init() { become(&(static_cast(this)->init_state)); } }; } // namespace cppa -#endif // FSM_ACTOR_HPP +#endif // CPPA_FSM_ACTOR_HPP diff --git a/cppa/scheduled_actor.hpp b/cppa/scheduled_actor.hpp index a9b15e03c2..c7e958c9b4 100644 --- a/cppa/scheduled_actor.hpp +++ b/cppa/scheduled_actor.hpp @@ -28,44 +28,60 @@ \******************************************************************************/ -#ifndef ACTOR_BEHAVIOR_HPP -#define ACTOR_BEHAVIOR_HPP +#ifndef CPPA_ACTOR_BEHAVIOR_HPP +#define CPPA_ACTOR_BEHAVIOR_HPP + +#include "cppa/config.hpp" +#include "cppa/local_actor.hpp" namespace cppa { +class scheduler; +namespace util { class fiber; } + +enum class resume_result { + actor_blocked, + actor_done +}; + +enum scheduled_actor_type { + context_switching_impl, + event_based_impl +}; + /** - * @brief A base class for context-switching or thread-mapped actor - * implementations. - * - * This abstract class provides a class-based way to define context-switching - * or thread-mapped actors. In general, - * you always should use event-based actors. However, if you need to call - * blocking functions, or need to have your own thread for other reasons, - * this class can be used to define a class-based actor. + * @brief A base class for cooperatively scheduled actors. */ -class scheduled_actor -{ +class scheduled_actor : public local_actor { public: - virtual ~scheduled_actor(); + scheduled_actor(bool enable_chained_send = false); /** - * @brief Can be overridden to perform cleanup code after an actor - * finished execution. - * @warning Must not call any function manipulating the actor's state such - * as join, leave, link, or monitor. + * @brief Intrusive next pointer needed by the scheduler's job queue. */ - virtual void on_exit(); + scheduled_actor* next; - /** - * @brief Implements the behavior of a context-switching or thread-mapped - * actor. - */ - virtual void act() = 0; + // called from worker thread + virtual resume_result resume(util::fiber* from) = 0; + + void attach_to_scheduler(scheduler* sched); + + virtual bool has_behavior() = 0; + + virtual scheduled_actor_type impl_type() = 0; + + protected: + + scheduler* m_scheduler; + + bool initialized(); }; +typedef intrusive_ptr scheduled_actor_ptr; + } // namespace cppa -#endif // ACTOR_BEHAVIOR_HPP +#endif // CPPA_ACTOR_BEHAVIOR_HPP diff --git a/cppa/scheduler.hpp b/cppa/scheduler.hpp index 0339eb6194..ca9c8e104e 100644 --- a/cppa/scheduler.hpp +++ b/cppa/scheduler.hpp @@ -28,12 +28,13 @@ \******************************************************************************/ -#ifndef SCHEDULER_HPP -#define SCHEDULER_HPP +#ifndef CPPA_SCHEDULER_HPP +#define CPPA_SCHEDULER_HPP #include #include #include +#include #include "cppa/self.hpp" #include "cppa/atom.hpp" @@ -50,19 +51,32 @@ namespace cppa { class scheduled_actor; class scheduler_helper; -class abstract_event_based_actor; -namespace detail { class abstract_scheduled_actor; } +typedef std::function void_function; +typedef std::function init_callback; + +namespace detail { +// forwards self_type as actor_ptr, otherwise equal to std::forward +template +struct spawn_fwd_ { +static inline T&& _(T&& arg) { return std::move(arg); } +static inline T& _(T& arg) { return arg; } +static inline const T& _(const T& arg) { return arg; } +}; +template<> +struct spawn_fwd_ { +static inline actor_ptr _(const self_type& s) { return s.get(); } +}; +} // namespace detail /** * @brief */ -class scheduler -{ +class scheduler { scheduler_helper* m_helper; - channel* future_send_helper(); + channel* delayed_send_helper(); protected: @@ -82,19 +96,7 @@ class scheduler */ virtual void stop(); - virtual void enqueue(detail::abstract_scheduled_actor*) = 0; - - /** - * @brief Spawns a new actor that executes behavior->act() - * with the scheduling policy @p hint if possible. - */ - virtual actor_ptr spawn(scheduled_actor* behavior, - scheduling_hint hint) = 0; - - /** - * @brief Spawns a new event-based actor. - */ - virtual actor_ptr spawn(abstract_event_based_actor* what) = 0; + virtual void enqueue(scheduled_actor*) = 0; /** * @brief Informs the scheduler about a converted context @@ -112,15 +114,83 @@ class scheduler virtual attachable* register_hidden_context(); template - void future_send(const actor_ptr& to, - const Duration& rel_time, const Data&... data) - { + void delayed_send(const channel_ptr& to, + const Duration& rel_time, + Data&&... data) { static_assert(sizeof...(Data) > 0, "no message to send"); - any_tuple data_tup = make_cow_tuple(data...); - any_tuple tup = make_cow_tuple(util::duration(rel_time), to, data_tup); - future_send_helper()->enqueue(self, std::move(tup)); + auto sub = make_any_tuple(std::forward(data)...); + auto tup = make_any_tuple(util::duration{rel_time}, to, std::move(sub)); + delayed_send_helper()->enqueue(self, std::move(tup)); } + /** + * @brief Spawns a new actor that executes fun() + * with the scheduling policy @p hint if possible. + */ + virtual actor_ptr spawn(void_function fun, scheduling_hint hint) = 0; + + /** + * @brief Spawns a new actor that executes behavior() + * with the scheduling policy @p hint if possible and calls + * init_cb after the actor is initialized but before + * it starts execution. + */ + virtual actor_ptr spawn(void_function fun, + scheduling_hint hint, + init_callback init_cb) = 0; + + /** + * @brief Spawns a new event-based actor. + */ + virtual actor_ptr spawn(scheduled_actor* what) = 0; + + /** + * @brief Spawns a new event-based actor and calls + * init_cb after the actor is initialized but before + * it starts execution. + */ + virtual actor_ptr spawn(scheduled_actor* what, init_callback init_cb) = 0; + + // hide implementation details for documentation +# ifndef CPPA_DOCUMENTATION + + template + actor_ptr spawn_impl(scheduling_hint hint, Fun&& fun, Arg0&& arg0, Args&&... args) { + return this->spawn( + std::bind( + std::forward(fun), + detail::spawn_fwd_::type>::_(arg0), + detail::spawn_fwd_::type>::_(args)...), + hint); + } + + template + actor_ptr spawn_impl(scheduling_hint hint, Fun&& fun) { + return this->spawn(std::forward(fun), hint); + } + + template + actor_ptr spawn_cb_impl(scheduling_hint hint, + InitCallback&& init_cb, + Fun&& fun, Arg0&& arg0, Args&&... args) { + return this->spawn( + std::bind( + std::forward(fun), + detail::spawn_fwd_::type>::_(arg0), + detail::spawn_fwd_::type>::_(args)...), + hint, + std::forward(init_cb)); + } + + template + actor_ptr spawn_cb_impl(scheduling_hint hint, InitCallback&& init_cb, Fun&& fun) { + return this->spawn(std::forward(fun), + hint, + std::forward(init_cb)); + } + +# endif // CPPA_DOCUMENTATION + }; /** @@ -139,4 +209,4 @@ scheduler* get_scheduler(); } // namespace cppa::detail -#endif // SCHEDULER_HPP +#endif // CPPA_SCHEDULER_HPP diff --git a/cppa/scheduling_hint.hpp b/cppa/scheduling_hint.hpp index 20fa43ffc0..8aad465422 100644 --- a/cppa/scheduling_hint.hpp +++ b/cppa/scheduling_hint.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef SCHEDULING_HINT_HPP -#define SCHEDULING_HINT_HPP +#ifndef CPPA_SCHEDULING_HINT_HPP +#define CPPA_SCHEDULING_HINT_HPP namespace cppa { @@ -37,8 +37,7 @@ namespace cppa { * @brief Denotes whether a user wants an actor to take part in * cooperative scheduling or not. */ -enum scheduling_hint -{ +enum scheduling_hint { /** * @brief Indicates that an actor takes part in cooperative scheduling. @@ -48,10 +47,16 @@ enum scheduling_hint /** * @brief Indicates that an actor should run in its own thread. */ - detached + detached, + + /** + * @brief Indicates that an actor should run in its own thread but should + * be ignored by {@link await_others_done()}. + */ + detached_and_hidden }; } // namespace cppa -#endif // SCHEDULING_HINT_HPP +#endif // CPPA_SCHEDULING_HINT_HPP diff --git a/cppa/self.hpp b/cppa/self.hpp index 96f8df60d8..b4e7cc946c 100644 --- a/cppa/self.hpp +++ b/cppa/self.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef SELF_HPP -#define SELF_HPP +#ifndef CPPA_SELF_HPP +#define CPPA_SELF_HPP #include "cppa/actor.hpp" #include "cppa/intrusive_ptr.hpp" @@ -44,59 +44,76 @@ namespace cppa { */ extern local_actor* self; -#else +#else // CPPA_DOCUMENTATION class local_actor; // convertible<...> enables "actor_ptr this_actor = self;" -class self_type : public convertible -{ - - static void set_impl(local_actor*); - - static local_actor* get_unchecked_impl(); - - static local_actor* get_impl(); - - static actor* convert_impl(); +class self_type : public convertible, + public convertible { self_type(const self_type&) = delete; self_type& operator=(const self_type&) = delete; public: + typedef local_actor* pointer; + constexpr self_type() { } // "inherited" from convertible<...> - inline actor* do_convert() const - { + inline actor* do_convert() const { return convert_impl(); } + inline pointer get() const { + return get_impl(); + } + // allow "self" wherever an local_actor or actor pointer is expected - inline operator local_actor*() const - { + inline operator pointer() const { return get_impl(); } - inline local_actor* operator->() const - { + inline pointer operator->() const { return get_impl(); } // @pre get_unchecked() == nullptr - inline void set(local_actor* ptr) const - { + inline void set(pointer ptr) const { set_impl(ptr); } // @returns The current value without converting the calling context // to an actor on-the-fly. - inline local_actor* unchecked() const - { + inline pointer unchecked() const { return get_unchecked_impl(); } + inline pointer release() const { + return release_impl(); + } + + inline void adopt(pointer ptr) const { + adopt_impl(ptr); + } + + static void cleanup_fun(pointer); + + private: + + static void set_impl(pointer); + + static pointer get_unchecked_impl(); + + static pointer get_impl(); + + static actor* convert_impl(); + + static pointer release_impl(); + + static void adopt_impl(pointer); + }; /* @@ -105,8 +122,32 @@ class self_type : public convertible */ constexpr self_type self; -#endif +class scoped_self_setter { + + scoped_self_setter(const scoped_self_setter&) = delete; + scoped_self_setter& operator=(const scoped_self_setter&) = delete; + + public: + + inline scoped_self_setter(local_actor* new_value) { + m_original_value = self.release(); + self.adopt(new_value); + } + + inline ~scoped_self_setter() { + // restore self + static_cast(self.release()); + self.adopt(m_original_value); + } + + private: + + local_actor* m_original_value; + +}; + +#endif // CPPA_DOCUMENTATION } // namespace cppa -#endif // SELF_HPP +#endif // CPPA_SELF_HPP diff --git a/cppa/serializer.hpp b/cppa/serializer.hpp index 1bb7784525..789d509a42 100644 --- a/cppa/serializer.hpp +++ b/cppa/serializer.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef SERIALIZER_HPP -#define SERIALIZER_HPP +#ifndef CPPA_SERIALIZER_HPP +#define CPPA_SERIALIZER_HPP #include #include // size_t @@ -46,8 +46,7 @@ class primitive_variant; * @ingroup TypeSystem * @brief Technology-independent serialization interface. */ -class serializer -{ +class serializer { serializer(const serializer&) = delete; serializer& operator=(const serializer&) = delete; @@ -91,16 +90,21 @@ class serializer * @param num Size of the array @p values. * @param values An array of size @p num of primitive data values. */ - virtual void write_tuple(size_t num, primitive_variant const* values) = 0; + virtual void write_tuple(size_t num, const primitive_variant* values) = 0; }; +/** + * @brief Serializes a value to @p s. + * @param s A valid serializer. + * @param what A value of an announced or primitive type. + * @returns @p s + * @relates serializer + */ template -serializer& operator<<(serializer& s, const T& what) -{ +serializer& operator<<(serializer& s, const T& what) { auto mtype = uniform_typeid(); - if (mtype == nullptr) - { + if (mtype == nullptr) { throw std::logic_error( "no uniform type info found for " + cppa::detail::to_uniform_name(typeid(T))); } @@ -110,4 +114,4 @@ serializer& operator<<(serializer& s, const T& what) } // namespace cppa -#endif // SERIALIZER_HPP +#endif // CPPA_SERIALIZER_HPP diff --git a/cppa/thread_mapped_actor.hpp b/cppa/thread_mapped_actor.hpp new file mode 100644 index 0000000000..3ffe4fa0b9 --- /dev/null +++ b/cppa/thread_mapped_actor.hpp @@ -0,0 +1,151 @@ +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + + +#ifndef CPPA_THREAD_BASED_ACTOR_HPP +#define CPPA_THREAD_BASED_ACTOR_HPP + +#include "cppa/config.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cppa/atom.hpp" +#include "cppa/either.hpp" +#include "cppa/pattern.hpp" +#include "cppa/local_actor.hpp" +#include "cppa/exit_reason.hpp" +#include "cppa/intrusive_ptr.hpp" +#include "cppa/detail/abstract_actor.hpp" + +#include "cppa/intrusive/singly_linked_list.hpp" + +#include "cppa/detail/receive_policy.hpp" +#include "cppa/detail/behavior_stack.hpp" +#include "cppa/detail/stacked_actor_mixin.hpp" +#include "cppa/detail/recursive_queue_node.hpp" + +namespace cppa { + +#ifdef CPPA_DOCUMENTATION + +/** + * @brief An actor running in its own thread. + */ +class thread_mapped_actor : public local_actor { + + protected: + + /** + * @brief Implements the actor's behavior. + * Reimplemented this function for a class-based actor. + * Returning from this member function will end the + * execution of the actor. + */ + virtual void run(); + +}; + +#else // CPPA_DOCUMENTATION + +class self_type; + +class thread_mapped_actor : public detail::stacked_actor_mixin< + thread_mapped_actor, + detail::abstract_actor > { + + friend class self_type; // needs access to cleanup() + friend class detail::receive_policy; + + typedef detail::stacked_actor_mixin< + thread_mapped_actor, + detail::abstract_actor > super; + + public: + + thread_mapped_actor(); + + thread_mapped_actor(std::function fun); + + void quit(std::uint32_t reason = exit_reason::normal); //override + + void enqueue(actor* sender, any_tuple msg); //override + + detail::filter_result filter_msg(const any_tuple& msg); + + inline decltype(m_mailbox)& mailbox() { return m_mailbox; } + + inline void initialized(bool value) { m_initialized = value; } + + protected: + + bool initialized(); + + private: + + bool m_initialized; + + // required by nestable_receive_policy + static const detail::receive_policy_flag receive_flag = detail::rp_nestable; + inline void push_timeout() { } + inline void pop_timeout() { } + inline detail::recursive_queue_node* receive_node() { + return m_mailbox.pop(); + } + inline auto init_timeout(const util::duration& tout) -> decltype(std::chrono::high_resolution_clock::now()) { + auto result = std::chrono::high_resolution_clock::now(); + result += tout; + return result; + } + inline detail::recursive_queue_node* try_receive_node() { + return m_mailbox.try_pop(); + } + template + inline detail::recursive_queue_node* try_receive_node(const Timeout& tout) { + return m_mailbox.try_pop(tout); + } + inline void handle_timeout(behavior& bhvr) { + bhvr.handle_timeout(); + } + +}; + +typedef intrusive_ptr thread_mapped_actor_ptr; + +#endif // CPPA_DOCUMENTATION + +} // namespace cppa + +#endif // CPPA_THREAD_BASED_ACTOR_HPP diff --git a/cppa/to_string.hpp b/cppa/to_string.hpp index 8fb64f343a..b84d0ba81a 100644 --- a/cppa/to_string.hpp +++ b/cppa/to_string.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef TO_STRING_HPP -#define TO_STRING_HPP +#ifndef CPPA_TO_STRING_HPP +#define CPPA_TO_STRING_HPP #include "cppa/uniform_type_info.hpp" #include "cppa/detail/to_uniform_name.hpp" @@ -38,7 +38,7 @@ namespace cppa { namespace detail { -std::string to_string_impl(void const* what, uniform_type_info const* utype); +std::string to_string_impl(const void* what, const uniform_type_info* utype); } // namespace detail @@ -48,11 +48,9 @@ std::string to_string_impl(void const* what, uniform_type_info const* utype); * @returns A string representation of @p what. */ template -std::string to_string(const T& what) -{ +std::string to_string(const T& what) { auto utype = uniform_typeid(); - if (utype == nullptr) - { + if (utype == nullptr) { throw std::logic_error( detail::to_uniform_name(typeid(T)) + " is not announced"); } @@ -61,4 +59,4 @@ std::string to_string(const T& what) } // namespace cppa -#endif // TO_STRING_HPP +#endif // CPPA_TO_STRING_HPP diff --git a/cppa/tpartial_function.hpp b/cppa/tpartial_function.hpp index 743a8cb3a8..1fc15d6acf 100644 --- a/cppa/tpartial_function.hpp +++ b/cppa/tpartial_function.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef TPARTIAL_FUNCTION_HPP -#define TPARTIAL_FUNCTION_HPP +#ifndef CPPA_TPARTIAL_FUNCTION_HPP +#define CPPA_TPARTIAL_FUNCTION_HPP #include #include @@ -44,8 +44,7 @@ namespace cppa { template -class tpartial_function -{ +class tpartial_function { typedef typename util::get_callable_trait::type ctrait; typedef typename ctrait::arg_types ctrait_args; @@ -66,26 +65,22 @@ class tpartial_function template tpartial_function(Fun&& fun, G&&... guard_args) : m_guard(std::forward(guard_args)...) - , m_expr(std::forward(fun)) - { + , m_expr(std::forward(fun)) { } tpartial_function(tpartial_function&& other) : m_guard(std::move(other.m_guard)) - , m_expr(std::move(other.m_expr)) - { + , m_expr(std::move(other.m_expr)) { } tpartial_function(const tpartial_function&) = default; //bool defined_at(const typename util::rm_ref::type&... args) const - bool defined_at(Args... args) const - { + bool defined_at(Args... args) const { return m_guard(args...); } - Result operator()(Args... args) const - { + Result operator()(Args... args) const { return util::apply_args ::_(m_expr, args...); } @@ -102,15 +97,13 @@ template -struct get_tpartial_function, Result, 1> -{ +struct get_tpartial_function, Result, 1> { typedef tpartial_function type; }; template struct get_tpartial_function, util::void_type, 0> -{ + util::type_list, util::void_type, 0> { typedef typename util::get_callable_trait::type ctrait; typedef typename ctrait::arg_types arg_types; @@ -137,4 +130,4 @@ struct get_tpartial_function @@ -41,38 +41,95 @@ namespace cppa { +#ifdef CPPA_DOCUMENTATION + +/** + * @brief Tries to cast @p tup to {@link cow_tuple cow_tuple} and moves + * the content of @p tup to the returned tuple on success. + * @param tup Dynamically typed tuple. + * @param pttrn Requested types with optional guard values. + * @returns An {@link option} for a {@link cow_tuple} with the types + * deduced from @p pttrn. + * @relates any_tuple + */ +auto moving_tuple_cast(any_tuple& tup, const pattern& pttrn); + +/** + * @brief Tries to cast @p tup to {@link cow_tuple cow_tuple} and moves + * the content of @p tup to the returned tuple on success. + * @param tup Dynamically typed tuple. + * @returns An {@link option} for a {@link cow_tuple} with the types + * deduced from {T...}. + * @relates any_tuple + */ +template +auto moving_tuple_cast(any_tuple& tup); + +/** + * @brief Tries to cast @p tup to {@link cow_tuple cow_tuple} and moves + * the content of @p tup to the returned tuple on success. + * @param tup Dynamically typed tuple. + * @returns An {@link option} for a {@link cow_tuple} with the types + * deduced from {T...}. + * @relates any_tuple + */ +template +auto moving_tuple_cast(any_tuple& tup, const util::type_list&); + +/** + * @brief Tries to cast @p tup to {@link cow_tuple cow_tuple}. + * @param tup Dynamically typed tuple. + * @param pttrn Requested types with optional guard values. + * @returns An {@link option} for a {@link cow_tuple} with the types + * deduced from @p pttrn. + * @relates any_tuple + */ +template +auto tuple_cast(any_tuple tup, const pattern& pttrn); + /** - * @brief Tries to cast @p tup to {@link tuple tuple}; moves content - * of @p tup on success. + * @brief Tries to cast @p tup to {@link cow_tuple cow_tuple}. + * @param tup Dynamically typed tuple. + * @returns An {@link option} for a {@link cow_tuple} with the types + * deduced from {T...}. + * @relates any_tuple */ template -auto moving_tuple_cast(any_tuple& tup, const pattern& p) +auto tuple_cast(any_tuple tup); + +/** + * @brief Tries to cast @p tup to {@link cow_tuple cow_tuple}. + * @param tup Dynamically typed tuple. + * @returns An {@link option} for a {@link cow_tuple} with the types + * deduced from {T...}. + * @relates any_tuple + */ +template +auto tuple_cast(any_tuple tup, const util::type_list&); + +#else + +template +auto moving_tuple_cast(any_tuple& tup, const pattern& pttrn) -> option< typename cow_tuple_from_type_list< typename pattern::filtered_types - >::type> -{ + >::type> { typedef typename pattern::filtered_types filtered_types; typedef typename cow_tuple_from_type_list::type tuple_type; - static constexpr auto impl = - get_wildcard_position>(); - return detail::tuple_cast_impl::safe(tup, p); + static constexpr auto impl = get_wildcard_position>(); + return detail::tuple_cast_impl::safe(tup, pttrn); } -/** - * @brief Tries to cast @p tup to {@link tuple tuple}; moves content - * of @p tup on success. - */ template auto moving_tuple_cast(any_tuple& tup) -> option< typename cow_tuple_from_type_list< typename util::tl_filter_not, is_anything>::type - >::type> -{ + >::type> { typedef decltype(moving_tuple_cast(tup)) result_type; - typedef typename result_type::value_type tuple_type; + typedef typename result_type::type tuple_type; static constexpr auto impl = get_wildcard_position>(); return detail::tuple_cast_impl::safe(tup); @@ -80,46 +137,36 @@ auto moving_tuple_cast(any_tuple& tup) template auto moving_tuple_cast(any_tuple& tup, const util::type_list&) - -> decltype(moving_tuple_cast(tup)) -{ + -> decltype(moving_tuple_cast(tup)) { return moving_tuple_cast(tup); } -/** - * @brief Tries to cast @p tup to {@link tuple tuple}. - */ template -auto tuple_cast(any_tuple tup, const pattern& p) +auto tuple_cast(any_tuple tup, const pattern& pttrn) -> option< typename cow_tuple_from_type_list< typename pattern::filtered_types - >::type> -{ - return moving_tuple_cast(tup, p); + >::type> { + return moving_tuple_cast(tup, pttrn); } -/** - * @brief Tries to cast @p tup to {@link tuple tuple}. - */ template auto tuple_cast(any_tuple tup) -> option< typename cow_tuple_from_type_list< typename util::tl_filter_not, is_anything>::type - >::type> -{ + >::type> { return moving_tuple_cast(tup); } template auto tuple_cast(any_tuple tup, const util::type_list&) - -> decltype(tuple_cast(tup)) -{ + -> decltype(tuple_cast(tup)) { return moving_tuple_cast(tup); } -/////////////////////////// for in-library use only! /////////////////////////// +// ************************ for in-library use only! ************************ // // (moving) cast using a pattern; does not perform type checking template @@ -127,8 +174,7 @@ auto unsafe_tuple_cast(any_tuple& tup, const pattern& p) -> option< typename cow_tuple_from_type_list< typename pattern::filtered_types - >::type> -{ + >::type> { typedef typename pattern::filtered_types filtered_types; typedef typename cow_tuple_from_type_list::type tuple_type; static constexpr auto impl = @@ -138,8 +184,7 @@ auto unsafe_tuple_cast(any_tuple& tup, const pattern& p) template auto unsafe_tuple_cast(any_tuple& tup, const util::type_list&) - -> decltype(tuple_cast(tup)) -{ + -> decltype(tuple_cast(tup)) { return tuple_cast(tup); } @@ -148,8 +193,7 @@ template auto forced_tuple_cast(any_tuple& tup, const pattern& p) -> typename cow_tuple_from_type_list< typename pattern::filtered_types - >::type -{ + >::type { typedef typename pattern::filtered_types filtered_types; typedef typename cow_tuple_from_type_list::type tuple_type; static constexpr auto impl = @@ -157,7 +201,8 @@ auto forced_tuple_cast(any_tuple& tup, const pattern& p) return detail::tuple_cast_impl::force(tup, p); } +#endif // CPPA_DOCUMENTATION } // namespace cppa -#endif // TUPLE_CAST_HPP +#endif // CPPA_TUPLE_CAST_HPP diff --git a/cppa/type_value_pair.hpp b/cppa/type_value_pair.hpp deleted file mode 100644 index 351bf07506..0000000000 --- a/cppa/type_value_pair.hpp +++ /dev/null @@ -1,134 +0,0 @@ -/******************************************************************************\ - * ___ __ * - * /\_ \ __/\ \ * - * \//\ \ /\_\ \ \____ ___ _____ _____ __ * - * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * - * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * - * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * - * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * - * \ \_\ \ \_\ * - * \/_/ \/_/ * - * * - * Copyright (C) 2011, 2012 * - * Dominik Charousset * - * * - * This file is part of libcppa. * - * libcppa is free software: you can redistribute it and/or modify it under * - * the terms of the GNU Lesser General Public License as published by the * - * Free Software Foundation, either version 3 of the License * - * or (at your option) any later version. * - * * - * libcppa is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with libcppa. If not, see . * -\******************************************************************************/ - - -#ifndef TYPE_VALUE_PAIR_HPP -#define TYPE_VALUE_PAIR_HPP - -#include - -#include "cppa/uniform_type_info.hpp" - -namespace cppa { - -typedef std::pair type_value_pair; - -class type_value_pair_const_iterator -{ - - type_value_pair const* iter; - - public: - - typedef type_value_pair const value_type; - typedef std::ptrdiff_t difference_type; - typedef type_value_pair const* pointer; - typedef const type_value_pair& reference; - typedef std::bidirectional_iterator_tag iterator_category; - - constexpr type_value_pair_const_iterator() : iter(nullptr) { } - - type_value_pair_const_iterator(type_value_pair const* i) : iter(i) { } - - type_value_pair_const_iterator(const type_value_pair_const_iterator&) - = default; - - type_value_pair_const_iterator& - operator=(const type_value_pair_const_iterator&) = default; - - inline uniform_type_info const* type() const { return iter->first; } - - inline void const* value() const { return iter->second; } - - inline decltype(iter) base() const { return iter; } - - inline decltype(iter) operator->() const { return iter; } - - inline decltype(*iter) operator*() const { return *iter; } - - inline type_value_pair_const_iterator& operator++() - { - ++iter; - return *this; - } - - inline type_value_pair_const_iterator operator++(int) - { - type_value_pair_const_iterator tmp{*this}; - ++iter; - return tmp; - } - - inline type_value_pair_const_iterator& operator--() - { - --iter; - return *this; - } - - inline type_value_pair_const_iterator operator--(int) - { - type_value_pair_const_iterator tmp{*this}; - --iter; - return tmp; - } - - inline type_value_pair_const_iterator operator+(size_t offset) - { - return iter + offset; - } - - inline type_value_pair_const_iterator& operator+=(size_t offset) - { - iter += offset; - return *this; - } - -}; - -/** - * @relates type_value_pair_const_iterator - */ -inline bool operator==(const type_value_pair_const_iterator& lhs, - const type_value_pair_const_iterator& rhs) -{ - return lhs.base() == rhs.base(); -} - -/** - * @relates type_value_pair_const_iterator - */ -inline bool operator!=(const type_value_pair_const_iterator& lhs, - const type_value_pair_const_iterator& rhs) -{ - return !(lhs == rhs); -} - -} // namespace cppa - -#endif // TYPE_VALUE_PAIR_HPP diff --git a/cppa/uniform_type_info.hpp b/cppa/uniform_type_info.hpp index 3e4ead591b..43c2874690 100644 --- a/cppa/uniform_type_info.hpp +++ b/cppa/uniform_type_info.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef UNIFORM_TYPE_INFO_HPP -#define UNIFORM_TYPE_INFO_HPP +#ifndef CPPA_UNIFORM_TYPE_INFO_HPP +#define CPPA_UNIFORM_TYPE_INFO_HPP #include #include @@ -52,7 +52,7 @@ class serializer; class deserializer; class uniform_type_info; -uniform_type_info const* uniform_typeid(const std::type_info&); +const uniform_type_info* uniform_typeid(const std::type_info&); /** * @defgroup TypeSystem libcppa's platform-independent type system. @@ -145,8 +145,7 @@ uniform_type_info const* uniform_typeid(const std::type_info&); * e.g.: namespace { class foo { }; } is mapped to * @c \@_::foo */ -class uniform_type_info -{ +class uniform_type_info { friend class object; @@ -171,7 +170,7 @@ class uniform_type_info * @returns The instance associated to @p uniform_name. * @throws std::runtime_error if no type named @p uniform_name was found. */ - static uniform_type_info* from(const std::string& uniform_name); + static const uniform_type_info* from(const std::string& uniform_name); /** * @brief Get instance by std::type_info. @@ -179,13 +178,13 @@ class uniform_type_info * @returns An instance describing the same type as @p tinfo. * @throws std::runtime_error if @p tinfo is not an announced type. */ - static uniform_type_info const* from(const std::type_info& tinfo); + static const uniform_type_info* from(const std::type_info& tinfo); /** * @brief Get all instances. * @returns A vector with all known (announced) instances. */ - static std::vector instances(); + static std::vector instances(); /** * @brief Get the internal @p libcppa name for this type. @@ -217,7 +216,7 @@ class uniform_type_info * @returns @p true if *instance1 == *instance2. * @pre @p instance1 and @p instance2 have the type of @p this. */ - virtual bool equals(void const* instance1, void const* instance2) const = 0; + virtual bool equals(const void* instance1, const void* instance2) const = 0; /** * @brief Serializes @p instance to @p sink. @@ -225,7 +224,7 @@ class uniform_type_info * @param sink Target data sink. * @pre @p instance has the type of @p this. */ - virtual void serialize(void const* instance, serializer* sink) const = 0; + virtual void serialize(const void* instance, serializer* sink) const = 0; /** * @brief Deserializes @p instance from @p source. @@ -255,7 +254,7 @@ class uniform_type_info * with the default constructor. * @pre @p instance has the type of @p this or is set to @p nullptr. */ - virtual void* new_instance(void const* instance = nullptr) const = 0; + virtual void* new_instance(const void* instance = nullptr) const = 0; private: @@ -267,8 +266,7 @@ class uniform_type_info * @relates uniform_type_info */ template -inline uniform_type_info const* uniform_typeid() -{ +inline const uniform_type_info* uniform_typeid() { return uniform_typeid(typeid(T)); } @@ -276,8 +274,7 @@ inline uniform_type_info const* uniform_typeid() * @relates uniform_type_info */ inline bool operator==(const uniform_type_info& lhs, - const uniform_type_info& rhs) -{ + const uniform_type_info& rhs) { // uniform_type_info instances are singletons, // thus, equal == identical return &lhs == &rhs; @@ -287,43 +284,38 @@ inline bool operator==(const uniform_type_info& lhs, * @relates uniform_type_info */ inline bool operator!=(const uniform_type_info& lhs, - const uniform_type_info& rhs) -{ + const uniform_type_info& rhs) { return !(lhs == rhs); } /** * @relates uniform_type_info */ -inline bool operator==(const uniform_type_info& lhs, const std::type_info& rhs) -{ +inline bool operator==(const uniform_type_info& lhs, const std::type_info& rhs) { return lhs.equals(rhs); } /** * @relates uniform_type_info */ -inline bool operator!=(const uniform_type_info& lhs, const std::type_info& rhs) -{ +inline bool operator!=(const uniform_type_info& lhs, const std::type_info& rhs) { return !(lhs.equals(rhs)); } /** * @relates uniform_type_info */ -inline bool operator==(const std::type_info& lhs, const uniform_type_info& rhs) -{ +inline bool operator==(const std::type_info& lhs, const uniform_type_info& rhs) { return rhs.equals(lhs); } /** * @relates uniform_type_info */ -inline bool operator!=(const std::type_info& lhs, const uniform_type_info& rhs) -{ +inline bool operator!=(const std::type_info& lhs, const uniform_type_info& rhs) { return !(rhs.equals(lhs)); } } // namespace cppa -#endif // UNIFORM_TYPE_INFO_HPP +#endif // CPPA_UNIFORM_TYPE_INFO_HPP diff --git a/cppa/util/abstract_uniform_type_info.hpp b/cppa/util/abstract_uniform_type_info.hpp index 180d925890..9f455a3de9 100644 --- a/cppa/util/abstract_uniform_type_info.hpp +++ b/cppa/util/abstract_uniform_type_info.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef ABSTRACT_UNIFORM_TYPE_INFO_HPP -#define ABSTRACT_UNIFORM_TYPE_INFO_HPP +#ifndef CPPA_ABSTRACT_UNIFORM_TYPE_INFO_HPP +#define CPPA_ABSTRACT_UNIFORM_TYPE_INFO_HPP #include "cppa/uniform_type_info.hpp" #include "cppa/detail/to_uniform_name.hpp" @@ -41,16 +41,13 @@ namespace cppa { namespace util { * except serialize() and deserialize(). */ template -class abstract_uniform_type_info : public uniform_type_info -{ +class abstract_uniform_type_info : public uniform_type_info { - inline static const T& deref(void const* ptr) - { - return *reinterpret_cast(ptr); + inline static const T& deref(const void* ptr) { + return *reinterpret_cast(ptr); } - inline static T& deref(void* ptr) - { + inline static T& deref(void* ptr) { return *reinterpret_cast(ptr); } @@ -58,29 +55,24 @@ class abstract_uniform_type_info : public uniform_type_info abstract_uniform_type_info(const std::string& uname = detail::to_uniform_name(typeid(T))) - : uniform_type_info(uname) - { + : uniform_type_info(uname) { } - bool equals(void const* lhs, void const* rhs) const - { + bool equals(const void* lhs, const void* rhs) const { return deref(lhs) == deref(rhs); } - void* new_instance(void const* ptr) const - { + void* new_instance(const void* ptr) const { return (ptr) ? new T(deref(ptr)) : new T(); } - void delete_instance(void* instance) const - { + void delete_instance(void* instance) const { delete reinterpret_cast(instance); } public: - bool equals(const std::type_info& tinfo) const - { + bool equals(const std::type_info& tinfo) const { return typeid(T) == tinfo; } @@ -88,4 +80,4 @@ class abstract_uniform_type_info : public uniform_type_info } } -#endif // ABSTRACT_UNIFORM_TYPE_INFO_HPP +#endif // CPPA_ABSTRACT_UNIFORM_TYPE_INFO_HPP diff --git a/cppa/util/apply_args.hpp b/cppa/util/apply_args.hpp index 007a2041fa..b15cacfe82 100644 --- a/cppa/util/apply_args.hpp +++ b/cppa/util/apply_args.hpp @@ -28,34 +28,30 @@ \******************************************************************************/ -#ifndef APPLY_ARGS_HPP -#define APPLY_ARGS_HPP +#ifndef CPPA_APPLY_ARGS_HPP +#define CPPA_APPLY_ARGS_HPP #include namespace cppa { namespace util { template -struct apply_args -{ +struct apply_args { template - static Result _(const Fun& fun, Arg0&&, Args&&... args) - { + static Result _(const Fun& fun, Arg0&&, Args&&... args) { return apply_args ::_(fun, std::forward(args)...); } }; template -struct apply_args -{ +struct apply_args { template - static Result _(const Fun& fun, Args&&... args) - { + static Result _(const Fun& fun, Args&&... args) { return fun(std::forward(args)...); } }; } } // namespace cppa::util -#endif // APPLY_ARGS_HPP +#endif // CPPA_APPLY_ARGS_HPP diff --git a/cppa/util/apply_tuple.hpp b/cppa/util/apply_tuple.hpp index 6ad85ebc01..64fa3cfdf9 100644 --- a/cppa/util/apply_tuple.hpp +++ b/cppa/util/apply_tuple.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef APPLY_TUPLE_HPP -#define APPLY_TUPLE_HPP +#ifndef CPPA_APPLY_TUPLE_HPP +#define CPPA_APPLY_TUPLE_HPP #include @@ -40,50 +40,41 @@ namespace cppa { namespace util { template -struct apply_tuple_impl -{ +struct apply_tuple_impl { template - static inline Result apply(F& f, const Tuple& args) - { + static inline Result apply(F& f, const Tuple& args) { return f(get(args)...); } }; template -struct apply_tuple_impl -{ +struct apply_tuple_impl { template - static inline Result apply(F& f, Tuple& args) - { + static inline Result apply(F& f, Tuple& args) { return f(get_ref(args)...); } }; template struct apply_tuple_util - : apply_tuple_util -{ + : apply_tuple_util { }; template struct apply_tuple_util - : apply_tuple_impl -{ + : apply_tuple_impl { }; template -struct apply_tuple_util -{ +struct apply_tuple_util { template - static Result apply(F& f, const Unused&) - { + static Result apply(F& f, const Unused&) { return f(); } }; template class Tuple, typename... T> -typename get_result_type::type apply_tuple(F&& fun, Tuple& tup) -{ +typename get_result_type::type apply_tuple(F&& fun, Tuple& tup) { typedef typename get_result_type::type result_type; typedef typename get_arg_types::types fun_args; static constexpr size_t tup_size = sizeof...(T); @@ -97,8 +88,7 @@ typename get_result_type::type apply_tuple(F&& fun, Tuple& tup) } template class Tuple, typename... T> -typename get_result_type::type apply_tuple(F&& fun, const Tuple& tup) -{ +typename get_result_type::type apply_tuple(F&& fun, const Tuple& tup) { typedef typename get_result_type::type result_type; typedef typename get_arg_types::types fun_args; static constexpr size_t tup_size = sizeof...(T); @@ -113,16 +103,14 @@ typename get_result_type::type apply_tuple(F&& fun, const Tuple& tup) template class Tuple, typename... T> -Result unchecked_apply_tuple_in_range(F&& fun, const Tuple& tup) -{ +Result unchecked_apply_tuple_in_range(F&& fun, const Tuple& tup) { return apply_tuple_util ::apply(std::forward(fun), tup); } template class Tuple, typename... T> -Result unchecked_apply_tuple_in_range(F&& fun, Tuple& tup) -{ +Result unchecked_apply_tuple_in_range(F&& fun, Tuple& tup) { return apply_tuple_util ::apply(std::forward(fun), tup); } @@ -131,8 +119,7 @@ Result unchecked_apply_tuple_in_range(F&& fun, Tuple& tup) // does not evaluate result type of functor template class Tuple, typename... T> -Result unchecked_apply_tuple(F&& fun, const Tuple& tup) -{ +Result unchecked_apply_tuple(F&& fun, const Tuple& tup) { return apply_tuple_util ::apply(std::forward(fun), tup); } @@ -141,12 +128,11 @@ Result unchecked_apply_tuple(F&& fun, const Tuple& tup) // does not evaluate result type of functor template class Tuple, typename... T> -Result unchecked_apply_tuple(F&& fun, Tuple& tup) -{ +Result unchecked_apply_tuple(F&& fun, Tuple& tup) { return apply_tuple_util ::apply(std::forward(fun), tup); } } } // namespace cppa::util -#endif // APPLY_TUPLE_HPP +#endif // CPPA_APPLY_TUPLE_HPP diff --git a/cppa/util/arg_match_t.hpp b/cppa/util/arg_match_t.hpp index ff44bfec12..56617af48e 100644 --- a/cppa/util/arg_match_t.hpp +++ b/cppa/util/arg_match_t.hpp @@ -1,6 +1,36 @@ -#ifndef ARG_MATCH_T_HPP -#define ARG_MATCH_T_HPP +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + + +#ifndef CPPA_ARG_MATCH_T_HPP +#define CPPA_ARG_MATCH_T_HPP namespace cppa { namespace util { struct arg_match_t { }; } } -#endif // ARG_MATCH_T_HPP +#endif // CPPA_ARG_MATCH_T_HPP diff --git a/cppa/util/at.hpp b/cppa/util/at.hpp index 6676da84b0..426202f8ed 100644 --- a/cppa/util/at.hpp +++ b/cppa/util/at.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef AT_HPP -#define AT_HPP +#ifndef CPPA_AT_HPP +#define CPPA_AT_HPP namespace cppa { namespace util { @@ -37,17 +37,15 @@ template struct at; template -struct at -{ +struct at { typedef typename at::type type; }; template -struct at<0, T0, Tn...> -{ +struct at<0, T0, Tn...> { typedef T0 type; }; } } // namespace cppa::util -#endif // AT_HPP +#endif // CPPA_AT_HPP diff --git a/cppa/util/callable_trait.hpp b/cppa/util/callable_trait.hpp index 7f73852846..ba2b3636f0 100644 --- a/cppa/util/callable_trait.hpp +++ b/cppa/util/callable_trait.hpp @@ -43,56 +43,48 @@ struct callable_trait; // member function pointer (const) template -struct callable_trait -{ +struct callable_trait { typedef ResultType result_type; typedef type_list arg_types; }; // member function pointer template -struct callable_trait -{ +struct callable_trait { typedef ResultType result_type; typedef type_list arg_types; }; // good ol' function template -struct callable_trait -{ +struct callable_trait { typedef ResultType result_type; typedef type_list arg_types; }; // good ol' function pointer template -struct callable_trait -{ +struct callable_trait { typedef ResultType result_type; typedef type_list arg_types; }; template -struct get_callable_trait_helper -{ +struct get_callable_trait_helper { typedef callable_trait type; }; template -struct get_callable_trait_helper -{ +struct get_callable_trait_helper { // assuming functor typedef callable_trait type; }; template -struct get_callable_trait -{ +struct get_callable_trait { typedef typename rm_ref::type fun_type; typedef typename - get_callable_trait_helper< - ( std::is_function::value + get_callable_trait_helper< ( std::is_function::value || std::is_function::type>::value), std::is_member_function_pointer::value, fun_type>::type @@ -102,25 +94,21 @@ struct get_callable_trait }; template -struct get_arg_types -{ +struct get_arg_types { typedef typename get_callable_trait::type trait_type; typedef typename trait_type::arg_types types; }; template -struct is_callable -{ +struct is_callable { template - static bool _fun(C*, typename callable_trait::result_type* = nullptr) - { + static bool _fun(C*, typename callable_trait::result_type* = nullptr) { return true; } template - static bool _fun(C*, typename callable_trait::result_type* = nullptr) - { + static bool _fun(C*, typename callable_trait::result_type* = nullptr) { return true; } @@ -136,21 +124,18 @@ struct is_callable }; template -struct get_result_type_impl -{ +struct get_result_type_impl { typedef typename get_callable_trait::type trait_type; typedef typename trait_type::result_type type; }; template -struct get_result_type_impl -{ +struct get_result_type_impl { typedef void_type type; }; template -struct get_result_type -{ +struct get_result_type { typedef typename get_result_type_impl::value, C>::type type; }; diff --git a/cppa/util/comparable.hpp b/cppa/util/comparable.hpp index 3a9885ab98..ddb5ea5411 100644 --- a/cppa/util/comparable.hpp +++ b/cppa/util/comparable.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef COMPARABLE_HPP -#define COMPARABLE_HPP +#ifndef CPPA_COMPARABLE_HPP +#define CPPA_COMPARABLE_HPP namespace cppa { namespace util { @@ -43,102 +43,82 @@ namespace cppa { namespace util { * - x == 0 if *this == other */ template -class comparable -{ +class comparable { - friend bool operator==(const Subclass& lhs, const T& rhs) - { + friend bool operator==(const Subclass& lhs, const T& rhs) { return lhs.compare(rhs) == 0; } - friend bool operator==(const T& lhs, const Subclass& rhs) - { + friend bool operator==(const T& lhs, const Subclass& rhs) { return rhs.compare(lhs) == 0; } - friend bool operator!=(const Subclass& lhs, const T& rhs) - { + friend bool operator!=(const Subclass& lhs, const T& rhs) { return lhs.compare(rhs) != 0; } - friend bool operator!=(const T& lhs, const Subclass& rhs) - { + friend bool operator!=(const T& lhs, const Subclass& rhs) { return rhs.compare(lhs) != 0; } - friend bool operator<(const Subclass& lhs, const T& rhs) - { + friend bool operator<(const Subclass& lhs, const T& rhs) { return lhs.compare(rhs) < 0; } - friend bool operator>(const Subclass& lhs, const T& rhs) - { + friend bool operator>(const Subclass& lhs, const T& rhs) { return lhs.compare(rhs) > 0; } - friend bool operator<(const T& lhs, const Subclass& rhs) - { + friend bool operator<(const T& lhs, const Subclass& rhs) { return rhs > lhs; } - friend bool operator>(const T& lhs, const Subclass& rhs) - { + friend bool operator>(const T& lhs, const Subclass& rhs) { return rhs < lhs; } - friend bool operator<=(const Subclass& lhs, const T& rhs) - { + friend bool operator<=(const Subclass& lhs, const T& rhs) { return lhs.compare(rhs) <= 0; } - friend bool operator>=(const Subclass& lhs, const T& rhs) - { + friend bool operator>=(const Subclass& lhs, const T& rhs) { return lhs.compare(rhs) >= 0; } - friend bool operator<=(const T& lhs, const Subclass& rhs) - { + friend bool operator<=(const T& lhs, const Subclass& rhs) { return rhs >= lhs; } - friend bool operator>=(const T& lhs, const Subclass& rhs) - { + friend bool operator>=(const T& lhs, const Subclass& rhs) { return rhs <= lhs; } }; template -class comparable -{ +class comparable { - friend bool operator==(const Subclass& lhs, const Subclass& rhs) - { + friend bool operator==(const Subclass& lhs, const Subclass& rhs) { return lhs.compare(rhs) == 0; } - friend bool operator!=(const Subclass& lhs, const Subclass& rhs) - { + friend bool operator!=(const Subclass& lhs, const Subclass& rhs) { return lhs.compare(rhs) != 0; } - friend bool operator<(const Subclass& lhs, const Subclass& rhs) - { + friend bool operator<(const Subclass& lhs, const Subclass& rhs) { return lhs.compare(rhs) < 0; } - friend bool operator<=(const Subclass& lhs, const Subclass& rhs) - { + friend bool operator<=(const Subclass& lhs, const Subclass& rhs) { return lhs.compare(rhs) <= 0; } - friend bool operator>(const Subclass& lhs, const Subclass& rhs) - { + friend bool operator>(const Subclass& lhs, const Subclass& rhs) { return lhs.compare(rhs) > 0; } - friend bool operator>=(const Subclass& lhs, const Subclass& rhs) - { + friend bool operator>=(const Subclass& lhs, const Subclass& rhs) { return lhs.compare(rhs) >= 0; } @@ -146,4 +126,4 @@ class comparable } } // cppa::util -#endif // COMPARABLE_HPP +#endif // CPPA_COMPARABLE_HPP diff --git a/cppa/util/compare_tuples.hpp b/cppa/util/compare_tuples.hpp index 524f640806..de4002abac 100644 --- a/cppa/util/compare_tuples.hpp +++ b/cppa/util/compare_tuples.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef COMPARE_TUPLES_HPP -#define COMPARE_TUPLES_HPP +#ifndef CPPA_COMPARE_TUPLES_HPP +#define CPPA_COMPARE_TUPLES_HPP #include "cppa/get.hpp" #include "cppa/util/at.hpp" @@ -40,26 +40,21 @@ namespace cppa { namespace detail { template class Tuple, typename... Types> const typename util::at::type& -do_get(const Tuple& t) -{ +do_get(const Tuple& t) { return ::cppa::get(t); } template -struct cmp_helper -{ - inline static bool cmp(const LhsTuple& lhs, const RhsTuple& rhs) - { +struct cmp_helper { + inline static bool cmp(const LhsTuple& lhs, const RhsTuple& rhs) { return do_get(lhs) == do_get(rhs) && cmp_helper::cmp(lhs, rhs); } }; template -struct cmp_helper<0, LhsTuple, RhsTuple> -{ - inline static bool cmp(const LhsTuple& lhs, const RhsTuple& rhs) - { +struct cmp_helper<0, LhsTuple, RhsTuple> { + inline static bool cmp(const LhsTuple& lhs, const RhsTuple& rhs) { return do_get<0>(lhs) == do_get<0>(rhs); } }; @@ -71,8 +66,7 @@ namespace cppa { namespace util { template class LhsTuple, typename... LhsTypes, template class RhsTuple, typename... RhsTypes> bool compare_tuples(const LhsTuple& lhs, - const RhsTuple& rhs) -{ + const RhsTuple& rhs) { static_assert(sizeof...(LhsTypes) == sizeof...(RhsTypes), "could not compare tuples of different size"); @@ -91,8 +85,7 @@ bool compare_tuples(const LhsTuple& lhs, template class LhsTuple, typename... LhsTypes, template class RhsTuple, typename... RhsTypes> bool compare_first_elements(const LhsTuple& lhs, - const RhsTuple& rhs) -{ + const RhsTuple& rhs) { typedef typename tl_zip< util::type_list, util::type_list @@ -109,4 +102,4 @@ bool compare_first_elements(const LhsTuple& lhs, } } // namespace cppa::util -#endif // COMPARE_TUPLES_HPP +#endif // CPPA_COMPARE_TUPLES_HPP diff --git a/cppa/util/conjunction.hpp b/cppa/util/conjunction.hpp index e042158064..6048087b0f 100644 --- a/cppa/util/conjunction.hpp +++ b/cppa/util/conjunction.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef CONJUNCTION_HPP -#define CONJUNCTION_HPP +#ifndef CPPA_CONJUNCTION_HPP +#define CPPA_CONJUNCTION_HPP #include @@ -40,8 +40,7 @@ struct conjunction; template struct conjunction - : std::integral_constant::value> -{ + : std::integral_constant::value> { }; template<> @@ -49,4 +48,4 @@ struct conjunction<> : std::true_type { }; } } // namespace cppa::util -#endif // CONJUNCTION_HPP +#endif // CPPA_CONJUNCTION_HPP diff --git a/cppa/util/deduce_ref_type.hpp b/cppa/util/deduce_ref_type.hpp index 3f1b3835ae..b14baa8c68 100644 --- a/cppa/util/deduce_ref_type.hpp +++ b/cppa/util/deduce_ref_type.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef DEDUCE_REF_TYPE_HPP -#define DEDUCE_REF_TYPE_HPP +#ifndef CPPA_DEDUCE_REF_TYPE_HPP +#define CPPA_DEDUCE_REF_TYPE_HPP #include "cppa/util/rm_ref.hpp" @@ -39,23 +39,20 @@ namespace cppa { namespace util { * @brief Deduces reference type of T0 and applies it to T1. */ template -struct deduce_ref_type -{ +struct deduce_ref_type { typedef typename util::rm_ref::type type; }; template -struct deduce_ref_type -{ +struct deduce_ref_type { typedef typename util::rm_ref::type& type; }; template -struct deduce_ref_type -{ +struct deduce_ref_type { typedef const typename util::rm_ref::type& type; }; } } // namespace cppa::util -#endif // DEDUCE_REF_TYPE_HPP +#endif // CPPA_DEDUCE_REF_TYPE_HPP diff --git a/cppa/util/disjunction.hpp b/cppa/util/disjunction.hpp index 8073070287..b706695eac 100644 --- a/cppa/util/disjunction.hpp +++ b/cppa/util/disjunction.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef DISJUNCTION_HPP -#define DISJUNCTION_HPP +#ifndef CPPA_DISJUNCTION_HPP +#define CPPA_DISJUNCTION_HPP #include @@ -40,8 +40,7 @@ struct disjunction; template struct disjunction - : std::integral_constant::value> -{ + : std::integral_constant::value> { }; template<> @@ -49,4 +48,4 @@ struct disjunction<> : std::false_type { }; } } // namespace cppa::util -#endif // DISJUNCTION_HPP +#endif // CPPA_DISJUNCTION_HPP diff --git a/cppa/util/duration.hpp b/cppa/util/duration.hpp index aec45bdfae..563da733eb 100644 --- a/cppa/util/duration.hpp +++ b/cppa/util/duration.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef DURATION_HPP -#define DURATION_HPP +#ifndef CPPA_DURATION_HPP +#define CPPA_DURATION_HPP #include #include @@ -39,8 +39,7 @@ namespace cppa { namespace util { /** * @brief SI time units to specify timeouts. */ -enum class time_unit : std::uint32_t -{ +enum class time_unit : std::uint32_t { none = 0, seconds = 1, milliseconds = 1000, @@ -52,8 +51,7 @@ enum class time_unit : std::uint32_t * {@link cppa::util::time_unit time_unit}. */ template -constexpr time_unit get_time_unit_from_period() -{ +constexpr time_unit get_time_unit_from_period() { return (Period::num != 1 ? time_unit::none : (Period::den == 1 @@ -69,32 +67,35 @@ constexpr time_unit get_time_unit_from_period() * @brief Time duration consisting of a {@link cppa::util::time_unit time_unit} * and a 32 bit unsigned integer. */ -class duration -{ +class duration { public: - constexpr duration() : unit(time_unit::none), count(0) - { - } + constexpr duration() : unit(time_unit::none), count(0) { } - constexpr duration(time_unit un, std::uint32_t val) : unit(un), count(val) - { - } + constexpr duration(time_unit u, std::uint32_t v) : unit(u), count(v) { } template constexpr duration(std::chrono::duration d) - : unit(get_time_unit_from_period()), count(d.count()) - { + : unit(get_time_unit_from_period()), count(d.count()) { static_assert(get_time_unit_from_period() != time_unit::none, "only seconds, milliseconds or microseconds allowed"); } + template + constexpr duration(std::chrono::duration > d) + : unit(time_unit::seconds), count(d.count() * 60) { } + /** * @brief Returns true if unit != time_unit::none. */ inline bool valid() const { return unit != time_unit::none; } + /** + * @brief Returns true if count == 0. + */ + inline bool is_zero() const { return count == 0; } + time_unit unit; std::uint32_t count; @@ -109,8 +110,7 @@ bool operator==(const duration& lhs, const duration& rhs); /** * @relates duration */ -inline bool operator!=(const duration& lhs, const duration& rhs) -{ +inline bool operator!=(const duration& lhs, const duration& rhs) { return !(lhs == rhs); } @@ -122,10 +122,8 @@ inline bool operator!=(const duration& lhs, const duration& rhs) template std::chrono::time_point& operator+=(std::chrono::time_point& lhs, - const cppa::util::duration& rhs) -{ - switch (rhs.unit) - { + const cppa::util::duration& rhs) { + switch (rhs.unit) { case cppa::util::time_unit::seconds: lhs += std::chrono::seconds(rhs.count); break; @@ -143,4 +141,4 @@ operator+=(std::chrono::time_point& lhs, return lhs; } -#endif // DURATION_HPP +#endif // CPPA_DURATION_HPP diff --git a/cppa/util/element_at.hpp b/cppa/util/element_at.hpp index e8ff2e962b..f08203c17d 100644 --- a/cppa/util/element_at.hpp +++ b/cppa/util/element_at.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef ELEMENT_AT_HPP -#define ELEMENT_AT_HPP +#ifndef CPPA_ELEMENT_AT_HPP +#define CPPA_ELEMENT_AT_HPP #include "cppa/util/at.hpp" @@ -42,10 +42,9 @@ struct element_at; * @brief Returns the n-th template parameter of @p C. */ template class C, typename... Tn> -struct element_at> : at -{ +struct element_at> : at { }; } } // namespace cppa::util -#endif // ELEMENT_AT_HPP +#endif // CPPA_ELEMENT_AT_HPP diff --git a/cppa/util/fiber.hpp b/cppa/util/fiber.hpp index 55e9aeb12e..37eb692db0 100644 --- a/cppa/util/fiber.hpp +++ b/cppa/util/fiber.hpp @@ -28,38 +28,30 @@ \******************************************************************************/ -#ifndef FIBER_HPP -#define FIBER_HPP +#ifndef CPPA_FIBER_HPP +#define CPPA_FIBER_HPP +#include #include "cppa/config.hpp" -#if defined(CPPA_MACOS) || defined(CPPA_LINUX) -# define CPPA_USE_UCONTEXT_IMPL -#elif defined (CPPA_WINDOWS) -# define CPPA_USE_FIBER_IMPL -#endif - #ifdef CPPA_DISABLE_CONTEXT_SWITCHING namespace cppa { namespace util { -struct fiber -{ +class fiber { + public: inline static void swap(fiber&, fiber&) { } }; -} } +} } // namespace cppa::util -#elif defined(CPPA_USE_UCONTEXT_IMPL) +#else // CPPA_DISABLE_CONTEXT_SWITCHING namespace cppa { namespace util { struct fiber_impl; -class fiber -{ - - fiber_impl* m_impl; +class fiber { -public: + public: fiber() throw(); @@ -69,44 +61,14 @@ class fiber static void swap(fiber& from, fiber& to); -}; - -} } // namespace cppa::util - -#elif defined(CPPA_USE_FIBER_IMPL) - -#include -#include - -namespace cppa { namespace util { + private: -class fiber -{ - - LPVOID handle; - - // true if this fiber was created with ConvertThreadToFiber - bool is_converted_thread; - - void init(); - -public: - - fiber(); - fiber(LPFIBER_START_ROUTINE func, LPVOID arg1); - - ~fiber(); - - inline static void swap(fiber&, fiber& to) - { - SwitchToFiber(to.handle); - } + fiber_impl* m_impl; }; } } // namespace cppa::util -#endif // CPPA_USE_UCONTEXT_IMPL - +#endif // CPPA_DISABLE_CONTEXT_SWITCHING -#endif // FIBER_HPP +#endif // CPPA_FIBER_HPP diff --git a/cppa/util/fixed_vector.hpp b/cppa/util/fixed_vector.hpp index 961d7131d8..c58e883e8b 100644 --- a/cppa/util/fixed_vector.hpp +++ b/cppa/util/fixed_vector.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef FIXED_VECTOR_HPP -#define FIXED_VECTOR_HPP +#ifndef CPPA_FIXED_VECTOR_HPP +#define CPPA_FIXED_VECTOR_HPP #include #include @@ -44,12 +44,11 @@ namespace cppa { namespace util { /** * @brief A vector with a fixed maximum size. * - * This implementation is highly optimized for arithmetic types and refuses - * any non-arithmetic template parameter. + * This implementation is highly optimized for arithmetic types and does + * not call constructors or destructors properly. */ template -class fixed_vector -{ +class fixed_vector { //static_assert(std::is_arithmetic::value || std::is_pointer::value, // "T must be an arithmetic or pointer type"); @@ -67,41 +66,36 @@ class fixed_vector typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* pointer; - typedef value_type const* const_pointer; + typedef const value_type* const_pointer; typedef T* iterator; - typedef T const* const_iterator; + typedef const T* const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; - constexpr fixed_vector() : m_size(0) { } + inline fixed_vector() : m_size(0) { } - fixed_vector(const fixed_vector& other) : m_size(other.m_size) - { + fixed_vector(const fixed_vector& other) : m_size(other.m_size) { std::copy(other.begin(), other.end(), begin()); } - fixed_vector& operator=(const fixed_vector& other) - { + fixed_vector& operator=(const fixed_vector& other) { resize(other.size()); std::copy(other.begin(), other.end(), begin()); return *this; } - void resize(size_type s) - { + void resize(size_type s) { CPPA_REQUIRE(s <= MaxSize); m_size = s; } - fixed_vector(std::initializer_list init) : m_size(init.size()) - { + fixed_vector(std::initializer_list init) : m_size(init.size()) { CPPA_REQUIRE(init.size() <= MaxSize); std::copy(init.begin(), init.end(), begin()); } - void assign(size_type count, const_reference value) - { + void assign(size_type count, const_reference value) { resize(count); std::fill(begin(), end(), value); } @@ -109,172 +103,140 @@ class fixed_vector template void assign(InputIterator first, InputIterator last, // dummy SFINAE argument - typename std::iterator_traits::pointer = 0) - { + typename std::iterator_traits::pointer = 0) { resize(std::distance(first, last)); std::copy(first, last, begin()); } - inline size_type size() const - { + inline size_type size() const { return m_size; } - inline size_type max_size() const - { + inline size_type max_size() const { return MaxSize; } - inline size_type capacity() const - { + inline size_type capacity() const { return max_size() - size(); } - inline void clear() - { + inline void clear() { m_size = 0; } - inline bool empty() const - { + inline bool empty() const { return m_size == 0; } - inline bool not_empty() const - { + inline bool not_empty() const { return m_size > 0; } - inline bool full() const - { + inline bool full() const { return m_size == MaxSize; } - inline void push_back(const_reference what) - { + inline void push_back(const_reference what) { CPPA_REQUIRE(!full()); m_data[m_size++] = what; } - inline void pop_back() - { + inline void pop_back() { CPPA_REQUIRE(not_empty()); --m_size; } - inline reference at(size_type pos) - { + inline reference at(size_type pos) { CPPA_REQUIRE(pos < m_size); return m_data[pos]; } - inline const_reference at(size_type pos) const - { + inline const_reference at(size_type pos) const { CPPA_REQUIRE(pos < m_size); return m_data[pos]; } - inline reference operator[](size_type pos) - { + inline reference operator[](size_type pos) { return at(pos); } - inline const_reference operator[](size_type pos) const - { + inline const_reference operator[](size_type pos) const { return at(pos); } - inline iterator begin() - { + inline iterator begin() { return m_data; } - inline const_iterator begin() const - { + inline const_iterator begin() const { return m_data; } - inline const_iterator cbegin() const - { + inline const_iterator cbegin() const { return begin(); } - inline iterator end() - { + inline iterator end() { return begin() + m_size; } - inline const_iterator end() const - { + inline const_iterator end() const { return begin() + m_size; } - inline const_iterator cend() const - { + inline const_iterator cend() const { return end(); } - inline reverse_iterator rbegin() - { + inline reverse_iterator rbegin() { return reverse_iterator(end()); } - inline const_reverse_iterator rbegin() const - { + inline const_reverse_iterator rbegin() const { return reverse_iterator(end()); } - inline const_reverse_iterator crbegin() const - { + inline const_reverse_iterator crbegin() const { return rbegin(); } - inline reverse_iterator rend() - { + inline reverse_iterator rend() { return reverse_iterator(begin()); } - inline const_reverse_iterator rend() const - { + inline const_reverse_iterator rend() const { return reverse_iterator(begin()); } - inline const_reverse_iterator crend() const - { + inline const_reverse_iterator crend() const { return rend(); } - inline reference front() - { + inline reference front() { CPPA_REQUIRE(!empty()); return m_data[0]; } - inline const_reference front() const - { + inline const_reference front() const { CPPA_REQUIRE(!empty()); return m_data[0]; } - inline reference back() - { + inline reference back() { CPPA_REQUIRE(!empty()); return m_data[m_size - 1]; } - inline const_reference back() const - { + inline const_reference back() const { CPPA_REQUIRE(!empty()); return m_data[m_size - 1]; } - inline T* data() - { + inline T* data() { return m_data; } - inline T const* data() const - { + inline const T* data() const { return m_data; } @@ -284,20 +246,16 @@ class fixed_vector * size() + distance(first, last) > MaxSize */ template - inline void insert(iterator pos, InputIterator first, InputIterator last) - { + inline void insert(iterator pos, InputIterator first, InputIterator last) { auto num_elements = std::distance(first, last); - if ((size() + num_elements) > MaxSize) - { + if ((size() + num_elements) > MaxSize) { throw std::length_error("fixed_vector::insert: too much elements"); } - if (pos == end()) - { + if (pos == end()) { resize(size() + num_elements); std::copy(first, last, pos); } - else - { + else { // move elements auto old_end = end(); resize(size() + num_elements); @@ -311,4 +269,4 @@ class fixed_vector } } // namespace cppa::util -#endif // FIXED_VECTOR_HPP +#endif // CPPA_FIXED_VECTOR_HPP diff --git a/cppa/util/guard.hpp b/cppa/util/guard.hpp index 31c8ef03c9..42e6eb651e 100644 --- a/cppa/util/guard.hpp +++ b/cppa/util/guard.hpp @@ -34,8 +34,7 @@ namespace cppa { namespace util { template -struct guard -{ +struct guard { virtual ~guard() { } diff --git a/cppa/util/if_else.hpp b/cppa/util/if_else.hpp index 7fdf57c466..2d44939b79 100644 --- a/cppa/util/if_else.hpp +++ b/cppa/util/if_else.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef IF_ELSE_HPP -#define IF_ELSE_HPP +#ifndef CPPA_IF_ELSE_HPP +#define CPPA_IF_ELSE_HPP #include "cppa/util/wrapped.hpp" @@ -37,14 +37,12 @@ namespace cppa { namespace util { // if (IfStmt == true) type = T; else type = Else::type; template -struct if_else_c -{ +struct if_else_c { typedef T type; }; template -struct if_else_c -{ +struct if_else_c { typedef typename Else::type type; }; @@ -60,4 +58,4 @@ struct if_else : if_else_c { }; } } // namespace cppa::util -#endif // IF_ELSE_HPP +#endif // CPPA_IF_ELSE_HPP diff --git a/cppa/util/is_array_of.hpp b/cppa/util/is_array_of.hpp index 8611056512..ccf97dc724 100644 --- a/cppa/util/is_array_of.hpp +++ b/cppa/util/is_array_of.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef IS_ARRAY_OF_HPP -#define IS_ARRAY_OF_HPP +#ifndef CPPA_IS_ARRAY_OF_HPP +#define CPPA_IS_ARRAY_OF_HPP #include @@ -41,8 +41,7 @@ namespace cppa { namespace util { * if @p T is an array of @p U. */ template -struct is_array_of -{ +struct is_array_of { typedef typename std::remove_all_extents::type step1_type; typedef typename std::remove_cv::type step2_type; static constexpr bool value = std::is_array::value @@ -51,4 +50,4 @@ struct is_array_of } } // namespace cppa::util -#endif // IS_ARRAY_OF_HPP +#endif // CPPA_IS_ARRAY_OF_HPP diff --git a/cppa/util/is_builtin.hpp b/cppa/util/is_builtin.hpp index 481d204c74..798b1978b1 100644 --- a/cppa/util/is_builtin.hpp +++ b/cppa/util/is_builtin.hpp @@ -1,23 +1,90 @@ -#ifndef IS_BUILTIN_HPP -#define IS_BUILTIN_HPP +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + +#ifndef CPPA_IS_BUILTIN_HPP +#define CPPA_IS_BUILTIN_HPP + +#include #include + +#include "cppa/atom.hpp" +#include "cppa/actor.hpp" +#include "cppa/group.hpp" +#include "cppa/channel.hpp" #include "cppa/anything.hpp" +#include "cppa/intrusive_ptr.hpp" +#include "cppa/process_information.hpp" + +namespace cppa { class any_tuple; } +namespace cppa { namespace detail { class addressed_message; } } namespace cppa { namespace util { template -struct is_builtin -{ +struct is_builtin { static constexpr bool value = std::is_arithmetic::value; }; template<> -struct is_builtin -{ - static constexpr bool value = true; -}; +struct is_builtin : std::true_type { }; + +template<> +struct is_builtin : std::true_type { }; + +template<> +struct is_builtin : std::true_type { }; + +template<> +struct is_builtin : std::true_type { }; + +template<> +struct is_builtin : std::true_type { }; + +template<> +struct is_builtin : std::true_type { }; + +template<> +struct is_builtin : std::true_type { }; + +template<> +struct is_builtin : std::true_type { }; + +template<> +struct is_builtin : std::true_type { }; + +template<> +struct is_builtin : std::true_type { }; + +template<> +struct is_builtin > : std::true_type { }; } } // namespace cppa::util -#endif // IS_BUILTIN_HPP +#endif // CPPA_IS_BUILTIN_HPP diff --git a/cppa/util/is_comparable.hpp b/cppa/util/is_comparable.hpp index fbf8137bdd..e816508a5a 100644 --- a/cppa/util/is_comparable.hpp +++ b/cppa/util/is_comparable.hpp @@ -28,16 +28,15 @@ \******************************************************************************/ -#ifndef IS_COMPARABLE_HPP -#define IS_COMPARABLE_HPP +#ifndef CPPA_IS_COMPARABLE_HPP +#define CPPA_IS_COMPARABLE_HPP #include namespace cppa { namespace util { template -class is_comparable -{ +class is_comparable { // SFINAE: If you pass a "bool*" as third argument, then // decltype(cmp_help_fun(...)) is bool if there's an @@ -48,14 +47,13 @@ class is_comparable // candidate and thus decltype(cmp_help_fun(...)) is void. template - static bool cmp_help_fun(A const* arg0, B const* arg1, - decltype(*arg0 == *arg1)* = nullptr) - { + static bool cmp_help_fun(const A* arg0, const B* arg1, + decltype(*arg0 == *arg1)* = nullptr) { return true; } template - static void cmp_help_fun(A const*, B const*, void* = nullptr) { } + static void cmp_help_fun(const A*, const B*, void* = nullptr) { } typedef decltype(cmp_help_fun(static_cast(nullptr), static_cast(nullptr), @@ -70,4 +68,4 @@ class is_comparable } } // namespace cppa::util -#endif // IS_COMPARABLE_HPP +#endif // CPPA_IS_COMPARABLE_HPP diff --git a/cppa/util/is_forward_iterator.hpp b/cppa/util/is_forward_iterator.hpp index 5e17b31e39..6985524180 100644 --- a/cppa/util/is_forward_iterator.hpp +++ b/cppa/util/is_forward_iterator.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef IS_FORWARD_ITERATOR_HPP -#define IS_FORWARD_ITERATOR_HPP +#ifndef CPPA_IS_FORWARD_ITERATOR_HPP +#define CPPA_IS_FORWARD_ITERATOR_HPP #include @@ -42,12 +42,10 @@ namespace cppa { namespace util { * @brief Checks wheter @p T behaves like a forward iterator. */ template -class is_forward_iterator -{ +class is_forward_iterator { template - static bool sfinae_fun - ( + static bool sfinae_fun ( C* iter, // check for 'C::value_type C::operator*()' returning a non-void type typename rm_ref::type* = 0, @@ -57,8 +55,7 @@ class is_forward_iterator typename std::enable_if::value>::type* = 0, // check for 'bool C::operator!=()' typename std::enable_if::value>::type* = 0 - ) - { + ) { return true; } @@ -74,4 +71,4 @@ class is_forward_iterator } } // namespace cppa::util -#endif // IS_FORWARD_ITERATOR_HPP +#endif // CPPA_IS_FORWARD_ITERATOR_HPP diff --git a/cppa/util/is_iterable.hpp b/cppa/util/is_iterable.hpp index 58f20497c6..59eb4664ea 100644 --- a/cppa/util/is_iterable.hpp +++ b/cppa/util/is_iterable.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef IS_ITERABLE_HPP -#define IS_ITERABLE_HPP +#ifndef CPPA_IS_ITERABLE_HPP +#define CPPA_IS_ITERABLE_HPP #include "cppa/util/is_primitive.hpp" #include "cppa/util/is_forward_iterator.hpp" @@ -42,27 +42,24 @@ namespace cppa { namespace util { * functions returning forward iterators. */ template -class is_iterable -{ +class is_iterable { // this horrible code would just disappear if we had concepts template - static bool sfinae_fun - ( - C const* cc, + static bool sfinae_fun ( + const C* cc, // check for 'C::begin()' returning a forward iterator typename std::enable_ifbegin())>::value>::type* = 0, // check for 'C::end()' returning the same kind of forward iterator typename std::enable_ifbegin()), decltype(cc->end())>::value>::type* = 0 - ) - { + ) { return true; } // SFNINAE default - static void sfinae_fun(void const*) { } + static void sfinae_fun(const void*) { } - typedef decltype(sfinae_fun(static_cast(nullptr))) result_type; + typedef decltype(sfinae_fun(static_cast(nullptr))) result_type; public: @@ -73,4 +70,4 @@ class is_iterable } } // namespace cppa::util -#endif // IS_ITERABLE_HPP +#endif // CPPA_IS_ITERABLE_HPP diff --git a/cppa/util/is_legal_tuple_type.hpp b/cppa/util/is_legal_tuple_type.hpp index c60f34569c..853014e1e0 100644 --- a/cppa/util/is_legal_tuple_type.hpp +++ b/cppa/util/is_legal_tuple_type.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef IS_LEGAL_TUPLE_TYPE_HPP -#define IS_LEGAL_TUPLE_TYPE_HPP +#ifndef CPPA_IS_LEGAL_TUPLE_TYPE_HPP +#define CPPA_IS_LEGAL_TUPLE_TYPE_HPP #include @@ -40,8 +40,7 @@ namespace cppa { namespace util { * @brief Checks wheter @p T is neither a reference nor a pointer nor an array. */ template -struct is_legal_tuple_type -{ +struct is_legal_tuple_type { static constexpr bool value = std::is_reference::value == false && std::is_pointer::value == false && std::is_array::value == false; @@ -49,4 +48,4 @@ struct is_legal_tuple_type } } // namespace cppa::util -#endif // IS_LEGAL_TUPLE_TYPE_HPP +#endif // CPPA_IS_LEGAL_TUPLE_TYPE_HPP diff --git a/cppa/util/is_manipulator.hpp b/cppa/util/is_manipulator.hpp index 20ef9105ac..5312557864 100644 --- a/cppa/util/is_manipulator.hpp +++ b/cppa/util/is_manipulator.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef IS_MANIPULATOR_HPP -#define IS_MANIPULATOR_HPP +#ifndef CPPA_IS_MANIPULATOR_HPP +#define CPPA_IS_MANIPULATOR_HPP #include "cppa/util/type_list.hpp" #include "cppa/util/is_mutable_ref.hpp" @@ -44,12 +44,11 @@ namespace cppa { namespace util { * @brief Checks wheter functor or function @p F takes mutable references. */ template -struct is_manipulator -{ +struct is_manipulator { static constexpr bool value = tl_exists::types, is_mutable_ref>::value; }; } } // namespace cppa::util -#endif // IS_MANIPULATOR_HPP +#endif // CPPA_IS_MANIPULATOR_HPP diff --git a/cppa/util/is_mutable_ref.hpp b/cppa/util/is_mutable_ref.hpp index 50a110a234..529fe4b24a 100644 --- a/cppa/util/is_mutable_ref.hpp +++ b/cppa/util/is_mutable_ref.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef IS_MUTABLE_REF_HPP -#define IS_MUTABLE_REF_HPP +#ifndef CPPA_IS_MUTABLE_REF_HPP +#define CPPA_IS_MUTABLE_REF_HPP namespace cppa { namespace util { @@ -37,23 +37,20 @@ namespace cppa { namespace util { * @brief Checks wheter @p T is a non-const reference. */ template -struct is_mutable_ref -{ +struct is_mutable_ref { static constexpr bool value = false; }; template -struct is_mutable_ref -{ +struct is_mutable_ref { static constexpr bool value = false; }; template -struct is_mutable_ref -{ +struct is_mutable_ref { static constexpr bool value = true; }; } } // namespace cppa::util -#endif // IS_MUTABLE_REF_HPP +#endif // CPPA_IS_MUTABLE_REF_HPP diff --git a/cppa/util/is_primitive.hpp b/cppa/util/is_primitive.hpp index 4c9d9ec595..66101642bf 100644 --- a/cppa/util/is_primitive.hpp +++ b/cppa/util/is_primitive.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef IS_PRIMITIVE_HPP -#define IS_PRIMITIVE_HPP +#ifndef CPPA_IS_PRIMITIVE_HPP +#define CPPA_IS_PRIMITIVE_HPP #include "cppa/detail/type_to_ptype.hpp" @@ -49,11 +49,10 @@ namespace cppa { namespace util { * - @c std::u32string */ template -struct is_primitive -{ +struct is_primitive { static constexpr bool value = detail::type_to_ptype::ptype != pt_null; }; } } // namespace cppa::util -#endif // IS_PRIMITIVE_HPP +#endif // CPPA_IS_PRIMITIVE_HPP diff --git a/cppa/util/left_or_right.hpp b/cppa/util/left_or_right.hpp index 5ec2851450..98e8a9377f 100644 --- a/cppa/util/left_or_right.hpp +++ b/cppa/util/left_or_right.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef LEFT_OR_RIGHT_HPP -#define LEFT_OR_RIGHT_HPP +#ifndef CPPA_LEFT_OR_RIGHT_HPP +#define CPPA_LEFT_OR_RIGHT_HPP #include "cppa/util/void_type.hpp" @@ -39,26 +39,22 @@ namespace cppa { namespace util { * @brief Evaluates to @p Right if @p Left == void_type, @p Left otherwise. */ template -struct left_or_right -{ +struct left_or_right { typedef Left type; }; template -struct left_or_right -{ +struct left_or_right { typedef Right type; }; template -struct left_or_right -{ +struct left_or_right { typedef Right type; }; template -struct left_or_right -{ +struct left_or_right { typedef Right type; }; @@ -66,17 +62,15 @@ struct left_or_right * @brief Evaluates to @p Right if @p Left != void_type, @p void_type otherwise. */ template -struct if_not_left -{ +struct if_not_left { typedef void_type type; }; template -struct if_not_left -{ +struct if_not_left { typedef Right type; }; } } // namespace cppa::util -#endif // LEFT_OR_RIGHT_HPP +#endif // CPPA_LEFT_OR_RIGHT_HPP diff --git a/cppa/util/producer_consumer_list.hpp b/cppa/util/producer_consumer_list.hpp index 975d7f6d78..771c9002e5 100644 --- a/cppa/util/producer_consumer_list.hpp +++ b/cppa/util/producer_consumer_list.hpp @@ -1,11 +1,71 @@ -#ifndef PRODUCER_CONSUMER_LIST_HPP -#define PRODUCER_CONSUMER_LIST_HPP +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + + +#ifndef CPPA_PRODUCER_CONSUMER_LIST_HPP +#define CPPA_PRODUCER_CONSUMER_LIST_HPP #define CPPA_CACHE_LINE_SIZE 64 +#include +#include #include #include -#include "cppa/detail/thread.hpp" + +// GCC hack +#if !defined(_GLIBCXX_USE_SCHED_YIELD) && !defined(__clang__) +#include +namespace std { namespace this_thread { namespace { +inline void yield() noexcept { + timespec req; + req.tv_sec = 0; + req.tv_nsec = 1; + nanosleep(&req, nullptr); +} +} } } // namespace std::this_thread:: +#endif + +// another GCC hack +#if !defined(_GLIBCXX_USE_NANOSLEEP) && !defined(__clang__) +#include +namespace std { namespace this_thread { namespace { +template +inline void sleep_for(const chrono::duration& rt) { + auto sec = chrono::duration_cast(rt); + auto nsec = chrono::duration_cast(rt - sec); + timespec req; + req.tv_sec = sec.count(); + req.tv_nsec = nsec.count(); + nanosleep(&req, nullptr); +} +} } } // namespace std::this_thread:: +#endif namespace cppa { namespace util { @@ -15,8 +75,7 @@ namespace cppa { namespace util { * For implementation details see http://drdobbs.com/cpp/211601363. */ template -class producer_consumer_list -{ +class producer_consumer_list { public: @@ -26,17 +85,15 @@ class producer_consumer_list typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* pointer; - typedef value_type const* const_pointer; + typedef const value_type* const_pointer; - struct node - { + struct node { pointer value; std::atomic next; node(pointer val) : value(val), next(nullptr) { } static constexpr size_type payload_size = sizeof(pointer) + sizeof(std::atomic); - static constexpr size_type pad_size = - (CPPA_CACHE_LINE_SIZE * ((payload_size / CPPA_CACHE_LINE_SIZE) + 1)) - payload_size; + static constexpr size_type pad_size = (CPPA_CACHE_LINE_SIZE * ((payload_size / CPPA_CACHE_LINE_SIZE) + 1)) - payload_size; // avoid false sharing char pad[pad_size]; @@ -59,12 +116,10 @@ class producer_consumer_list std::atomic m_consumer_lock; std::atomic m_producer_lock; - void push_impl(node* tmp) - { + void push_impl(node* tmp) { // acquire exclusivity - while (m_producer_lock.exchange(true)) - { - detail::this_thread::yield(); + while (m_producer_lock.exchange(true)) { + std::this_thread::yield(); } // publish & swing last forward m_last->next = tmp; @@ -75,42 +130,35 @@ class producer_consumer_list public: - producer_consumer_list() - { + producer_consumer_list() { m_first = m_last = new node(nullptr); m_consumer_lock = false; m_producer_lock = false; } - ~producer_consumer_list() - { - while (m_first) - { + ~producer_consumer_list() { + while (m_first) { node* tmp = m_first; m_first = tmp->next; delete tmp; } } - inline void push_back(pointer value) - { + inline void push_back(pointer value) { assert(value != nullptr); push_impl(new node(value)); } // returns nullptr on failure - pointer try_pop() - { + pointer try_pop() { pointer result = nullptr; - while (m_consumer_lock.exchange(true)) - { - detail::this_thread::yield(); + while (m_consumer_lock.exchange(true)) { + std::this_thread::yield(); } // only one consumer allowed node* first = m_first; node* next = m_first->next; - if (next) - { + if (next) { // queue is not empty result = next->value; // take it out of the node next->value = nullptr; @@ -123,8 +171,7 @@ class producer_consumer_list delete first; return result; } - else - { + else { // release exclusivity m_consumer_lock = false; return nullptr; @@ -135,4 +182,4 @@ class producer_consumer_list } } // namespace cppa::util -#endif // PRODUCER_CONSUMER_LIST_HPP +#endif // CPPA_PRODUCER_CONSUMER_LIST_HPP diff --git a/cppa/util/pt_dispatch.hpp b/cppa/util/pt_dispatch.hpp index e3dfbc5bbf..d6cd12a530 100644 --- a/cppa/util/pt_dispatch.hpp +++ b/cppa/util/pt_dispatch.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef PT_DISPATCH_HPP -#define PT_DISPATCH_HPP +#ifndef CPPA_PT_DISPATCH_HPP +#define CPPA_PT_DISPATCH_HPP namespace cppa { namespace util { @@ -39,10 +39,8 @@ namespace cppa { namespace util { * @note Does nothing if ptype == pt_null. */ template -void pt_dispatch(primitive_type ptype, Fun&& f) -{ - switch (ptype) - { +void pt_dispatch(primitive_type ptype, Fun&& f) { + switch (ptype) { case pt_int8: f(pt_token()); break; case pt_int16: f(pt_token()); break; case pt_int32: f(pt_token()); break; @@ -63,4 +61,4 @@ void pt_dispatch(primitive_type ptype, Fun&& f) } } // namespace cppa::util -#endif // PT_DISPATCH_HPP +#endif // CPPA_PT_DISPATCH_HPP diff --git a/cppa/util/pt_token.hpp b/cppa/util/pt_token.hpp index ac544ce707..e7098c9d26 100644 --- a/cppa/util/pt_token.hpp +++ b/cppa/util/pt_token.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef PT_TOKEN_HPP -#define PT_TOKEN_HPP +#ifndef CPPA_PT_TOKEN_HPP +#define CPPA_PT_TOKEN_HPP #include "cppa/primitive_type.hpp" @@ -43,4 +43,4 @@ struct pt_token { static const primitive_type value = PT; }; } } // namespace cppa::util -#endif // PT_TOKEN_HPP +#endif // CPPA_PT_TOKEN_HPP diff --git a/cppa/util/purge_refs.hpp b/cppa/util/purge_refs.hpp index 943c8196c9..d4ad0ec0ef 100644 --- a/cppa/util/purge_refs.hpp +++ b/cppa/util/purge_refs.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef PURGE_REFS_HPP -#define PURGE_REFS_HPP +#ifndef CPPA_PURGE_REFS_HPP +#define CPPA_PURGE_REFS_HPP #include @@ -39,26 +39,22 @@ namespace cppa { namespace util { template -struct purge_refs_impl -{ +struct purge_refs_impl { typedef T type; }; template -struct purge_refs_impl > -{ +struct purge_refs_impl > { typedef T type; }; template -struct purge_refs_impl > -{ +struct purge_refs_impl > { typedef T type; }; template -struct purge_refs_impl > -{ +struct purge_refs_impl > { typedef T type; }; @@ -66,11 +62,10 @@ struct purge_refs_impl > * @brief Removes references and reference wrappers. */ template -struct purge_refs -{ +struct purge_refs { typedef typename purge_refs_impl::type>::type type; }; } } // namespace cppa::util -#endif // PURGE_REFS_HPP +#endif // CPPA_PURGE_REFS_HPP diff --git a/cppa/util/replace_type.hpp b/cppa/util/replace_type.hpp index 3f5e5e889f..b5654262fe 100644 --- a/cppa/util/replace_type.hpp +++ b/cppa/util/replace_type.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef REPLACE_TYPE_HPP -#define REPLACE_TYPE_HPP +#ifndef CPPA_REPLACE_TYPE_HPP +#define CPPA_REPLACE_TYPE_HPP #include @@ -38,14 +38,12 @@ namespace cppa { namespace detail { template -struct replace_type -{ +struct replace_type { typedef T type; }; template -struct replace_type -{ +struct replace_type { typedef ReplaceType type; }; @@ -54,8 +52,7 @@ struct replace_type namespace cppa { namespace util { template -struct replace_type -{ +struct replace_type { static constexpr bool do_replace = disjunction::value; typedef typename detail::replace_type::type type; @@ -63,4 +60,4 @@ struct replace_type } } // namespace cppa::util -#endif // REPLACE_TYPE_HPP +#endif // CPPA_REPLACE_TYPE_HPP diff --git a/cppa/util/ripemd_160.hpp b/cppa/util/ripemd_160.hpp index 542f973ca9..1b6fcb5e42 100644 --- a/cppa/util/ripemd_160.hpp +++ b/cppa/util/ripemd_160.hpp @@ -65,8 +65,8 @@ * \******************************************************************************/ -#ifndef RIPEMD_160_HPP -#define RIPEMD_160_HPP +#ifndef CPPA_RIPEMD_160_HPP +#define CPPA_RIPEMD_160_HPP #include #include @@ -80,4 +80,4 @@ void ripemd_160(std::array& storage, const std::string& data); } } // namespace cppa::util -#endif // RIPEMD_160_HPP +#endif // CPPA_RIPEMD_160_HPP diff --git a/cppa/util/rm_option.hpp b/cppa/util/rm_option.hpp index c0c659df1e..8027c1dfab 100644 --- a/cppa/util/rm_option.hpp +++ b/cppa/util/rm_option.hpp @@ -28,25 +28,23 @@ \******************************************************************************/ -#ifndef RM_OPTION_HPP -#define RM_OPTION_HPP +#ifndef CPPA_RM_OPTION_HPP +#define CPPA_RM_OPTION_HPP #include "cppa/option.hpp" namespace cppa { namespace util { template -struct rm_option -{ +struct rm_option { typedef T type; }; template -struct rm_option > -{ +struct rm_option > { typedef T type; }; } } // namespace cppa::util -#endif // RM_OPTION_HPP +#endif // CPPA_RM_OPTION_HPP diff --git a/cppa/util/rm_ref.hpp b/cppa/util/rm_ref.hpp index 9b4c2879ea..42e1023a4e 100644 --- a/cppa/util/rm_ref.hpp +++ b/cppa/util/rm_ref.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef RM_REF_HPP -#define RM_REF_HPP +#ifndef CPPA_RM_REF_HPP +#define CPPA_RM_REF_HPP namespace cppa { namespace util { @@ -54,4 +54,4 @@ struct rm_ref { }; } } // namespace cppa::util -#endif // RM_REF_HPP +#endif // CPPA_RM_REF_HPP diff --git a/cppa/util/shared_lock_guard.hpp b/cppa/util/shared_lock_guard.hpp index 85d3559282..37774eb08b 100644 --- a/cppa/util/shared_lock_guard.hpp +++ b/cppa/util/shared_lock_guard.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef SHARED_LOCK_GUARD_HPP -#define SHARED_LOCK_GUARD_HPP +#ifndef CPPA_SHARED_LOCK_GUARD_HPP +#define CPPA_SHARED_LOCK_GUARD_HPP namespace cppa { namespace util { @@ -37,30 +37,25 @@ namespace cppa { namespace util { * @brief Similar to std::lock_guard but performs shared locking. */ template -class shared_lock_guard -{ +class shared_lock_guard { SharedLockable* m_lockable; public: - explicit shared_lock_guard(SharedLockable& lockable) : m_lockable(&lockable) - { + explicit shared_lock_guard(SharedLockable& lockable) : m_lockable(&lockable) { m_lockable->lock_shared(); } - ~shared_lock_guard() - { + ~shared_lock_guard() { if (m_lockable) m_lockable->unlock_shared(); } - bool owns_lock() const - { + bool owns_lock() const { return m_lockable != nullptr; } - SharedLockable* release() - { + SharedLockable* release() { auto result = m_lockable; m_lockable = nullptr; return result; @@ -69,4 +64,4 @@ class shared_lock_guard } } // namespace cppa::util -#endif // SHARED_LOCK_GUARD_HPP +#endif // CPPA_SHARED_LOCK_GUARD_HPP diff --git a/cppa/util/shared_spinlock.hpp b/cppa/util/shared_spinlock.hpp index 75156f3ea8..2cf0ff5fb5 100644 --- a/cppa/util/shared_spinlock.hpp +++ b/cppa/util/shared_spinlock.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef SHARED_SPINLOCK_HPP -#define SHARED_SPINLOCK_HPP +#ifndef CPPA_SHARED_SPINLOCK_HPP +#define CPPA_SHARED_SPINLOCK_HPP #include #include @@ -39,8 +39,7 @@ namespace cppa { namespace util { /** * @brief A spinlock implementation providing shared and exclusive locking. */ -class shared_spinlock -{ +class shared_spinlock { std::atomic m_flag; @@ -66,4 +65,4 @@ class shared_spinlock } } // namespace cppa::util -#endif // SHARED_SPINLOCK_HPP +#endif // CPPA_SHARED_SPINLOCK_HPP diff --git a/cppa/util/static_foreach.hpp b/cppa/util/static_foreach.hpp index fa8aaf4aa7..ac789c1b3b 100644 --- a/cppa/util/static_foreach.hpp +++ b/cppa/util/static_foreach.hpp @@ -28,50 +28,43 @@ \******************************************************************************/ -#ifndef STATIC_FOREACH_HPP -#define STATIC_FOREACH_HPP +#ifndef CPPA_STATIC_FOREACH_HPP +#define CPPA_STATIC_FOREACH_HPP #include "cppa/get.hpp" namespace cppa { namespace util { template -struct static_foreach_impl -{ +struct static_foreach_impl { template - static inline void _(const Container& c, Fun& f, Args&&... args) - { + static inline void _(const Container& c, Fun& f, Args&&... args) { f(get(c), std::forward(args)...); static_foreach_impl<(Begin+1 < End), Begin+1, End> ::_(c, f, std::forward(args)...); } template - static inline void _ref(Container& c, Fun& f, Args&&... args) - { + static inline void _ref(Container& c, Fun& f, Args&&... args) { f(get_ref(c), std::forward(args)...); static_foreach_impl<(Begin+1 < End), Begin+1, End> ::_ref(c, f, std::forward(args)...); } template - static inline void _auto(Container& c, Fun& f, Args&&... args) - { + static inline void _auto(Container& c, Fun& f, Args&&... args) { _ref(c, f, std::forward(args)...); } template - static inline void _auto(const Container& c, Fun& f, Args&&... args) - { + static inline void _auto(const Container& c, Fun& f, Args&&... args) { _(c, f, std::forward(args)...); } template - static inline bool eval(const Container& c, Fun& f, Args&&... args) - { + static inline bool eval(const Container& c, Fun& f, Args&&... args) { return f(get(c), std::forward(args)...) && static_foreach_impl<(Begin+1 < End), Begin+1, End> ::eval(c, f, std::forward(args)...); } template - static inline bool eval_or(const Container& c, Fun& f, Args&&... args) - { + static inline bool eval_or(const Container& c, Fun& f, Args&&... args) { return f(get(c), std::forward(args)...) || static_foreach_impl<(Begin+1 < End), Begin+1, End> ::eval_or(c, f, std::forward(args)...); @@ -79,8 +72,7 @@ struct static_foreach_impl }; template -struct static_foreach_impl -{ +struct static_foreach_impl { template static inline void _(Args&&...) { } template @@ -98,10 +90,9 @@ struct static_foreach_impl * @brief A for loop that can be used with tuples. */ template -struct static_foreach : static_foreach_impl<(Begin < End), Begin, End> -{ +struct static_foreach : static_foreach_impl<(Begin < End), Begin, End> { }; } } // namespace cppa::util -#endif // STATIC_FOREACH_HPP +#endif // CPPA_STATIC_FOREACH_HPP diff --git a/cppa/util/tbind.hpp b/cppa/util/tbind.hpp index a1b5e0e1e0..00b07a2345 100644 --- a/cppa/util/tbind.hpp +++ b/cppa/util/tbind.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef TBIND_HPP -#define TBIND_HPP +#ifndef CPPA_TBIND_HPP +#define CPPA_TBIND_HPP namespace cppa { namespace util { @@ -38,15 +38,13 @@ namespace cppa { namespace util { * @brief Predefines the first template parameter of @p Tp1. */ template class Tpl, typename Arg1> -struct tbind -{ +struct tbind { template - struct type - { + struct type { static constexpr bool value = Tpl::value; }; }; } } // namespace cppa::util -#endif // TBIND_HPP +#endif // CPPA_TBIND_HPP diff --git a/cppa/util/type_list.hpp b/cppa/util/type_list.hpp index 7a14d30445..b0cc53a4a8 100644 --- a/cppa/util/type_list.hpp +++ b/cppa/util/type_list.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef LIBCPPA_UTIL_TYPE_LIST_HPP -#define LIBCPPA_UTIL_TYPE_LIST_HPP +#ifndef CPPA_UTIL_TYPE_LIST_HPP +#define CPPA_UTIL_TYPE_LIST_HPP #include #include @@ -43,7 +43,7 @@ namespace cppa { // forward declarations class uniform_type_info; -uniform_type_info const* uniform_typeid(const std::type_info&); +const uniform_type_info* uniform_typeid(const std::type_info&); } // namespace cppa @@ -61,8 +61,7 @@ namespace cppa { namespace util { template struct type_list; template<> -struct type_list<> -{ +struct type_list<> { typedef void_type head; typedef void_type back; typedef type_list<> tail; @@ -73,8 +72,7 @@ struct type_list<> * @brief A list of types. */ template -struct type_list -{ +struct type_list { typedef Head head; @@ -90,14 +88,12 @@ struct type_list }; template -struct is_type_list -{ +struct is_type_list { static constexpr bool value = false; }; template -struct is_type_list > -{ +struct is_type_list > { static constexpr bool value = true; }; @@ -105,8 +101,7 @@ struct is_type_list > template -struct tl_slice_impl -{ +struct tl_slice_impl { typedef typename tl_slice_impl< LeftOffset - 1, Remaining, @@ -118,8 +113,7 @@ struct tl_slice_impl }; template -struct tl_slice_impl<0, Remaining, PadType, List, T...> -{ +struct tl_slice_impl<0, Remaining, PadType, List, T...> { typedef typename tl_slice_impl< 0, Remaining - 1, @@ -131,8 +125,7 @@ struct tl_slice_impl<0, Remaining, PadType, List, T...> }; template -struct tl_slice_impl<0, Remaining, PadType, type_list<>, T...> -{ +struct tl_slice_impl<0, Remaining, PadType, type_list<>, T...> { typedef typename tl_slice_impl< 0, Remaining - 1, @@ -144,32 +137,27 @@ struct tl_slice_impl<0, Remaining, PadType, type_list<>, T...> }; template -struct tl_slice_impl<0, 0, PadType, List, T...> -{ +struct tl_slice_impl<0, 0, PadType, List, T...> { typedef type_list type; }; template -struct tl_slice_impl<0, 0, PadType, type_list<>, T...> -{ +struct tl_slice_impl<0, 0, PadType, type_list<>, T...> { typedef type_list type; }; template -struct tl_slice_ -{ +struct tl_slice_ { typedef typename tl_slice_impl< - First, - (Last - First), + First, (Last - First), PadType, List >::type type; }; template -struct tl_slice_ -{ +struct tl_slice_ { typedef List type; }; @@ -177,8 +165,7 @@ struct tl_slice_ * @brief Creates a new list from range (First, Last]. */ template -struct tl_slice -{ +struct tl_slice { static_assert(First <= Last, "First > Last"); typedef typename tl_slice_::type type; }; @@ -197,8 +184,7 @@ struct tl_zip_impl; template class Fun> -struct tl_zip_impl, type_list, Fun> -{ +struct tl_zip_impl, type_list, Fun> { static_assert(sizeof...(LhsElements) == sizeof...(RhsElements), "Lists have different size"); typedef type_list::type...> type; @@ -206,10 +192,8 @@ struct tl_zip_impl, type_list, Fun> template class Fun = to_type_pair> -struct tl_zip -{ - static constexpr size_t result_size = - (ListA::size < ListB::size) ? ListA::size +struct tl_zip { + static constexpr size_t result_size = (ListA::size < ListB::size) ? ListA::size : ListB::size; typedef typename tl_zip_impl< @@ -225,10 +209,8 @@ template class Fun = to_type_pair> -struct tl_zip_all -{ - static constexpr size_t result_size = - (ListA::size > ListB::size) ? ListA::size +struct tl_zip_all { + static constexpr size_t result_size = (ListA::size > ListB::size) ? ListA::size : ListB::size; typedef typename tl_zip_impl< @@ -253,8 +235,7 @@ template struct tl_unzip; template -struct tl_unzip< type_list > -{ +struct tl_unzip< type_list > { typedef type_list first; typedef type_list second; }; @@ -266,27 +247,23 @@ struct tl_zip_with_index_impl; template struct tl_zip_with_index_impl - : tl_zip_with_index_impl -{ + : tl_zip_with_index_impl { }; template -struct tl_zip_with_index_impl, Pos, Range...> -{ +struct tl_zip_with_index_impl, Pos, Range...> { typedef type_list, Ts>...> type; }; template -struct tl_zip_with_index -{ +struct tl_zip_with_index { typedef typename tl_zip_with_index_impl::type type; }; template<> -struct tl_zip_with_index > -{ +struct tl_zip_with_index > { typedef type_list<> type; }; @@ -296,14 +273,12 @@ template struct tl_reverse_impl; template -struct tl_reverse_impl, E...> -{ +struct tl_reverse_impl, E...> { typedef typename tl_reverse_impl, T0, E...>::type type; }; template -struct tl_reverse_impl, E...> -{ +struct tl_reverse_impl, E...> { typedef type_list type; }; @@ -311,8 +286,7 @@ struct tl_reverse_impl, E...> * @brief Creates a new list wih elements in reversed order. */ template -struct tl_reverse -{ +struct tl_reverse { typedef typename tl_reverse_impl::type type; }; @@ -326,15 +300,13 @@ template class Predicate, int Pos = 0> struct tl_find_impl; template class Predicate, int Pos> -struct tl_find_impl, Predicate, Pos> -{ +struct tl_find_impl, Predicate, Pos> { static constexpr int value = -1; }; template class Predicate, int Pos, typename Head, typename... Tail> -struct tl_find_impl, Predicate, Pos> -{ +struct tl_find_impl, Predicate, Pos> { static constexpr int value = Predicate::value ? Pos @@ -346,8 +318,7 @@ struct tl_find_impl, Predicate, Pos> * index @p Pos. */ template -struct tl_find -{ +struct tl_find { static constexpr int value = tl_find_impl::template type, @@ -360,8 +331,7 @@ struct tl_find * index @p Pos. */ template class Predicate, int Pos = 0> -struct tl_find_if -{ +struct tl_find_if { static constexpr int value = tl_find_impl::value; }; @@ -371,22 +341,19 @@ struct tl_find_if * @brief Tests whether a predicate holds for all elements of a list. */ template class Predicate> -struct tl_forall -{ +struct tl_forall { static constexpr bool value = Predicate::value && tl_forall::value; }; template class Predicate> -struct tl_forall, Predicate> -{ +struct tl_forall, Predicate> { static constexpr bool value = true; }; template class Predicate> -struct tl_forall2_impl -{ +struct tl_forall2_impl { static constexpr bool value = Predicate::value && tl_forall2_impl< @@ -397,8 +364,7 @@ struct tl_forall2_impl }; template class Predicate> -struct tl_forall2_impl, type_list<>, Predicate> -{ +struct tl_forall2_impl, type_list<>, Predicate> { static constexpr bool value = true; }; @@ -407,8 +373,7 @@ struct tl_forall2_impl, type_list<>, Predicate> * corresponding elements of @p ListA and @p ListB. */ template class Predicate> -struct tl_binary_forall -{ +struct tl_binary_forall { static constexpr bool value = ListA::size == ListB::size && tl_forall2_impl::value; @@ -418,16 +383,14 @@ struct tl_binary_forall * @brief Tests whether a predicate holds for some of the elements of a list. */ template class Predicate> -struct tl_exists -{ +struct tl_exists { static constexpr bool value = - Predicate::value - || tl_exists::value; + Predicate::value + || tl_exists::value; }; template class Predicate> -struct tl_exists, Predicate> -{ +struct tl_exists, Predicate> { static constexpr bool value = false; }; @@ -438,16 +401,13 @@ struct tl_exists, Predicate> * @brief Counts the number of elements in the list which satisfy a predicate. */ template class Predicate> -struct tl_count -{ - static constexpr size_t value = - (Predicate::value ? 1 : 0) - + tl_count::value; +struct tl_count { + static constexpr size_t value = (Predicate::value ? 1 : 0) + + tl_count::value; }; template class Predicate> -struct tl_count, Predicate> -{ +struct tl_count, Predicate> { static constexpr size_t value = 0; }; @@ -457,16 +417,13 @@ struct tl_count, Predicate> * @brief Counts the number of elements in the list which satisfy a predicate. */ template class Predicate> -struct tl_count_not -{ - static constexpr size_t value = - (Predicate::value ? 0 : 1) - + tl_count_not::value; +struct tl_count_not { + static constexpr size_t value = (Predicate::value ? 0 : 1) + + tl_count_not::value; }; template class Predicate> -struct tl_count_not, Predicate> -{ +struct tl_count_not, Predicate> { static constexpr size_t value = 0; }; @@ -476,8 +433,7 @@ struct tl_count_not, Predicate> * @brief Tests whether a predicate holds for all elements of a zipped list. */ template class Predicate> -struct tl_zipped_forall -{ +struct tl_zipped_forall { typedef typename ZippedList::head head; static constexpr bool value = Predicate::value @@ -485,8 +441,7 @@ struct tl_zipped_forall }; template class Predicate> -struct tl_zipped_forall, Predicate> -{ +struct tl_zipped_forall, Predicate> { static constexpr bool value = true; }; @@ -497,8 +452,7 @@ struct tl_concat_impl; * @brief Concatenates two lists. */ template -struct tl_concat_impl, type_list > -{ +struct tl_concat_impl, type_list > { typedef type_list type; }; @@ -511,14 +465,12 @@ template struct tl_concat; template -struct tl_concat -{ +struct tl_concat { typedef List0 type; }; template -struct tl_concat -{ +struct tl_concat { typedef typename tl_concat< typename tl_concat_impl::type, Lists... @@ -535,8 +487,7 @@ struct tl_push_back; * @brief Appends @p What to given list. */ template -struct tl_push_back, What> -{ +struct tl_push_back, What> { typedef type_list type; }; @@ -547,8 +498,7 @@ struct tl_push_front; * @brief Appends @p What to given list. */ template -struct tl_push_front, What> -{ +struct tl_push_front, What> { typedef type_list type; }; @@ -558,16 +508,14 @@ template class... Funs> struct tl_apply_all; template -struct tl_apply_all -{ +struct tl_apply_all { typedef T type; }; template class Fun0, template class... Funs> -struct tl_apply_all -{ +struct tl_apply_all { typedef typename tl_apply_all::type, Funs...>::type type; }; @@ -579,8 +527,7 @@ template class... Funs> struct tl_map; template class... Funs> -struct tl_map, Funs...> -{ +struct tl_map, Funs...> { typedef type_list::type...> type; }; @@ -592,8 +539,7 @@ template class Trait, bool TraitResult, template class... Funs> -struct tl_map_conditional -{ +struct tl_map_conditional { typedef typename tl_concat< type_list< typename std::conditional< @@ -615,8 +561,7 @@ struct tl_map_conditional template class Trait, bool TraitResult, template class... Funs> -struct tl_map_conditional, Trait, TraitResult, Funs...> -{ +struct tl_map_conditional, Trait, TraitResult, Funs...> { typedef type_list<> type; }; @@ -628,8 +573,7 @@ template class Trait, bool TraitResult, template class... Funs> -struct tl_map_conditional, Trait, TraitResult, Funs...> -{ +struct tl_map_conditional, Trait, TraitResult, Funs...> { typedef type_list< typename std::conditional< Trait::value == TraitResult, @@ -651,8 +595,7 @@ struct tl_zipped_map; * to each element. */ template class Fun> -struct tl_zipped_map, Fun> -{ +struct tl_zipped_map, Fun> { typedef type_list::type...> type; }; @@ -663,14 +606,12 @@ struct tl_zipped_map, Fun> * @brief Creates a new list wih all but the last element of @p List. */ template -struct tl_pop_back -{ +struct tl_pop_back { typedef typename tl_slice::type type; }; template<> -struct tl_pop_back > -{ +struct tl_pop_back > { typedef type_list<> type; }; @@ -681,14 +622,12 @@ struct tl_at_impl; template -struct tl_at_impl -{ +struct tl_at_impl { typedef typename tl_at_impl::type type; }; template -struct tl_at_impl<0, E0, E...> -{ +struct tl_at_impl<0, E0, E...> { typedef E0 type; }; @@ -699,8 +638,7 @@ struct tl_at; * @brief Gets element at index @p N of @p List. */ template -struct tl_at, N> -{ +struct tl_at, N> { static_assert(N < sizeof...(E), "N >= List::size"); typedef typename tl_at_impl::type type; }; @@ -714,8 +652,7 @@ struct tl_prepend; * @brief Creates a new list with @p What prepended to @p List. */ template -struct tl_prepend, What> -{ +struct tl_prepend, What> { typedef type_list type; }; @@ -727,20 +664,17 @@ template struct tl_filter_impl; template<> -struct tl_filter_impl< type_list<> > -{ +struct tl_filter_impl< type_list<> > { typedef type_list<> type; }; template -struct tl_filter_impl, false, S...> -{ +struct tl_filter_impl, false, S...> { typedef typename tl_filter_impl, S...>::type type; }; template -struct tl_filter_impl, true, S...> -{ +struct tl_filter_impl, true, S...> { typedef typename tl_prepend, S...>::type, T0>::type type; }; @@ -751,8 +685,7 @@ struct tl_filter; * @brief Create a new list containing all elements which satisfy @p Predicate. */ template class Predicate, typename... T> -struct tl_filter, Predicate> -{ +struct tl_filter, Predicate> { typedef typename tl_filter_impl, Predicate::value...>::type type; }; @@ -764,14 +697,12 @@ template class Predicate> struct tl_filter_not; template class Predicate> -struct tl_filter_not, Predicate> -{ +struct tl_filter_not, Predicate> { typedef type_list<> type; }; template class Predicate, typename... T> -struct tl_filter_not, Predicate> -{ +struct tl_filter_not, Predicate> { typedef typename tl_filter_impl, !Predicate::value...>::type type; }; @@ -783,8 +714,7 @@ template struct tl_filter_type; template -struct tl_filter_type, Type> -{ +struct tl_filter_type, Type> { typedef typename tl_filter_impl, std::is_same::value...>::type type; }; @@ -796,8 +726,7 @@ template struct tl_filter_not_type; template -struct tl_filter_not_type, Type> -{ +struct tl_filter_not_type, Type> { typedef typename tl_filter_impl, (!std::is_same::value)...>::type type; }; @@ -813,8 +742,7 @@ template<> struct tl_distinct > { typedef type_list<> type; }; template -struct tl_distinct > -{ +struct tl_distinct > { typedef typename tl_concat< type_list, typename tl_distinct< @@ -831,23 +759,19 @@ template -struct tl_pad_right_impl -{ +struct tl_pad_right_impl { typedef typename tl_slice::type type; }; template -struct tl_pad_right_impl -{ +struct tl_pad_right_impl { typedef List type; }; template -struct tl_pad_right_impl -{ +struct tl_pad_right_impl { typedef typename tl_pad_right_impl< - typename tl_push_back::type, - (OldSize + 1) < NewSize, + typename tl_push_back::type, (OldSize + 1) < NewSize, OldSize + 1, NewSize, FillType @@ -860,8 +784,7 @@ struct tl_pad_right_impl * @p FillType to initialize the new elements with. */ template -struct tl_pad_right -{ +struct tl_pad_right { typedef typename tl_pad_right_impl< List, (List::size < NewSize), List::size, NewSize, FillType >::type @@ -871,8 +794,7 @@ struct tl_pad_right // bool pad_left(list, N) template -struct tl_pad_left_impl -{ +struct tl_pad_left_impl { typedef typename tl_pad_left_impl< typename tl_push_front::type, OldSize + 1, @@ -883,8 +805,7 @@ struct tl_pad_left_impl }; template -struct tl_pad_left_impl -{ +struct tl_pad_left_impl { typedef List type; }; @@ -893,13 +814,11 @@ struct tl_pad_left_impl * @p FillType to initialize prepended elements with. */ template -struct tl_pad_left -{ +struct tl_pad_left { //static_assert(NewSize >= List::size, "List too big"); typedef typename tl_pad_left_impl< List, - List::size, - (List::size > NewSize) ? List::size : NewSize, + List::size, (List::size > NewSize) ? List::size : NewSize, FillType >::type type; @@ -908,8 +827,7 @@ struct tl_pad_left // bool is_zipped(list) template -struct tl_is_zipped -{ +struct tl_is_zipped { static constexpr bool value = tl_forall::value; }; @@ -917,10 +835,9 @@ struct tl_is_zipped * @brief Removes trailing @p What elements from the end. */ template -struct tl_trim -{ +struct tl_trim { typedef typename util::if_else< - std::is_same, + std::is_same, typename tl_trim::type, What>::type, util::wrapped >::type @@ -928,8 +845,7 @@ struct tl_trim }; template -struct tl_trim, What> -{ +struct tl_trim, What> { typedef type_list<> type; }; @@ -939,20 +855,17 @@ template struct tl_group_by_impl_step; template -struct tl_group_by_impl_step > -{ +struct tl_group_by_impl_step > { typedef type_list > type; }; template -struct tl_group_by_impl_step -{ +struct tl_group_by_impl_step { typedef type_list > type; }; template class Predicate> -struct tl_group_by_impl -{ +struct tl_group_by_impl { typedef typename Out::back last_group; typedef typename tl_group_by_impl_step< Predicate::value, @@ -972,8 +885,7 @@ struct tl_group_by_impl }; template class Predicate, typename Head, typename... Tail> -struct tl_group_by_impl, type_list<>, Predicate> -{ +struct tl_group_by_impl, type_list<>, Predicate> { typedef typename tl_group_by_impl< type_list, type_list >, @@ -983,15 +895,13 @@ struct tl_group_by_impl, type_list<>, Predicate> }; template class Predicate> -struct tl_group_by_impl, Out, Predicate> -{ +struct tl_group_by_impl, Out, Predicate> { typedef Out type; }; template class Predicate> -struct tl_group_by -{ +struct tl_group_by { typedef typename tl_group_by_impl, Predicate>::type type; }; @@ -1002,8 +912,7 @@ template class VarArgTemplate> struct tl_apply; template class VarArgTemplate> -struct tl_apply, VarArgTemplate> -{ +struct tl_apply, VarArgTemplate> { typedef VarArgTemplate type; }; @@ -1012,4 +921,4 @@ struct tl_apply, VarArgTemplate> */ } } // namespace cppa::util -#endif // LIBCPPA_UTIL_TYPE_LIST_HPP +#endif // CPPA_UTIL_TYPE_LIST_HPP diff --git a/cppa/util/type_pair.hpp b/cppa/util/type_pair.hpp index 3ce39e96ba..0e34a63153 100644 --- a/cppa/util/type_pair.hpp +++ b/cppa/util/type_pair.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef TYPE_PAIR_HPP -#define TYPE_PAIR_HPP +#ifndef CPPA_TYPE_PAIR_HPP +#define CPPA_TYPE_PAIR_HPP namespace cppa { namespace util { @@ -38,30 +38,26 @@ namespace cppa { namespace util { * @brief A pair of two types. */ template -struct type_pair -{ +struct type_pair { typedef First first; typedef Second second; }; template -struct to_type_pair -{ +struct to_type_pair { typedef type_pair type; }; template -struct is_type_pair -{ +struct is_type_pair { static constexpr bool value = false; }; template -struct is_type_pair > -{ +struct is_type_pair > { static constexpr bool value = true; }; } } // namespace cppa::util -#endif // TYPE_PAIR_HPP +#endif // CPPA_TYPE_PAIR_HPP diff --git a/cppa/util/upgrade_lock_guard.hpp b/cppa/util/upgrade_lock_guard.hpp index a31543f463..7bdb66b9db 100644 --- a/cppa/util/upgrade_lock_guard.hpp +++ b/cppa/util/upgrade_lock_guard.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef UPGRADE_LOCK_GUARD_HPP -#define UPGRADE_LOCK_GUARD_HPP +#ifndef CPPA_UPGRADE_LOCK_GUARD_HPP +#define CPPA_UPGRADE_LOCK_GUARD_HPP namespace cppa { namespace util { @@ -37,27 +37,23 @@ namespace cppa { namespace util { * @brief Upgrades shared ownership to exclusive ownership. */ template -class upgrade_lock_guard -{ +class upgrade_lock_guard { UpgradeLockable* m_lockable; public: template class LockType> - upgrade_lock_guard(LockType& other) - { + upgrade_lock_guard(LockType& other) { m_lockable = other.release(); if (m_lockable) m_lockable->lock_upgrade(); } - ~upgrade_lock_guard() - { + ~upgrade_lock_guard() { if (m_lockable) m_lockable->unlock(); } - bool owns_lock() const - { + bool owns_lock() const { return m_lockable != nullptr; } @@ -65,4 +61,4 @@ class upgrade_lock_guard } } // namespace cppa::util -#endif // UPGRADE_LOCK_GUARD_HPP +#endif // CPPA_UPGRADE_LOCK_GUARD_HPP diff --git a/cppa/util/void_type.hpp b/cppa/util/void_type.hpp index 37836cd07d..1ca6bc526c 100644 --- a/cppa/util/void_type.hpp +++ b/cppa/util/void_type.hpp @@ -28,30 +28,19 @@ \******************************************************************************/ -#ifndef LIBCPPA_UTIL_VOID_TYPE_HPP -#define LIBCPPA_UTIL_VOID_TYPE_HPP +#ifndef CPPA_UTIL_VOID_TYPE_HPP +#define CPPA_UTIL_VOID_TYPE_HPP namespace cppa { namespace util { -// forward declaration -template struct type_list; - -struct void_type -{ - typedef void_type head; - typedef type_list<> tail; - +struct void_type { constexpr void_type() { } constexpr void_type(const void_type&) { } - void_type& operator=(const void_type&) = default; - // anything could be used to initialize a void... - template - void_type(Arg0&&, Args&&...) { } + template + constexpr void_type(const Arg&) { } }; -inline bool operator==(const void_type&, const void_type&) { return true; } - } } // namespace cppa::util -#endif // LIBCPPA_UTIL_VOID_TYPE_HPP +#endif // CPPA_UTIL_VOID_TYPE_HPP diff --git a/cppa/util/wrapped.hpp b/cppa/util/wrapped.hpp index 5e282eea1b..0b90fdd21a 100644 --- a/cppa/util/wrapped.hpp +++ b/cppa/util/wrapped.hpp @@ -28,8 +28,8 @@ \******************************************************************************/ -#ifndef WRAPPED_HPP -#define WRAPPED_HPP +#ifndef CPPA_WRAPPED_HPP +#define CPPA_WRAPPED_HPP namespace cppa { namespace util { @@ -38,17 +38,15 @@ namespace cppa { namespace util { * @brief A type wrapper as used in {@link cppa::util::if_else if_else}. */ template -struct wrapped -{ +struct wrapped { typedef T type; }; template -struct wrapped< wrapped > -{ +struct wrapped< wrapped > { typedef typename wrapped::type type; }; } } // namespace cppa::util -#endif // WRAPPED_HPP +#endif // CPPA_WRAPPED_HPP diff --git a/cr_makefile_am.sh b/cr_makefile_am.sh deleted file mode 100755 index bc1d373f1b..0000000000 --- a/cr_makefile_am.sh +++ /dev/null @@ -1,30 +0,0 @@ -cpp_files=($(cat cppa.files | grep "src/.*\.cpp$" | sort)) -num_cpp_files=${#cpp_files[@]} -hpp_files=($(cat cppa.files | grep "cppa/.*\.hpp$" | sort)) -num_hpp_files=${#hpp_files[@]} - -echo "ACLOCAL_AMFLAGS = -I m4" -echo "" -echo "lib_LTLIBRARIES = libcppa.la" -echo "" -echo "libcppa_la_SOURCES = \\" -for i in $(seq 0 $(($num_cpp_files - 2))); do echo " ${cpp_files[$i]} \\" ; done -echo " ${cpp_files[$(($num_cpp_files - 1))]}" -echo "" -echo "if VERSIONED_INCLUDE_DIR" -echo "library_includedir = \$(includedir)/cppa/\$(PACKAGE_VERSION)/" -echo "else" -echo "library_includedir = \$(includedir)/" -echo "endif" -echo "" -echo "nobase_library_include_HEADERS = \\" -for i in $(seq 0 $(($num_hpp_files - 2))); do echo " ${hpp_files[$i]} \\" ; done -echo " ${hpp_files[$(($num_hpp_files - 1))]}" -echo "" -echo "libcppa_la_CXXFLAGS = --std=c++0x -pedantic -Wall -Wextra" -echo "libcppa_la_LDFLAGS = -release \$(PACKAGE_VERSION) \$(BOOST_CPPFLAGS)" -echo "" -echo "pkgconfigdir = \$(libdir)/pkgconfig" -echo "pkgconfig_DATA = libcppa.pc" -echo "" -echo "SUBDIRS = . unit_testing examples benchmarks" diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000000..63c681c3ad --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 2.6) +project(cppa_examples CXX) + +# Set up environment paths to cmake modules and libcppa +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +add_executable(announce_example_1 announce_example_1.cpp) +add_executable(announce_example_2 announce_example_2.cpp) +add_executable(announce_example_3 announce_example_3.cpp) +add_executable(announce_example_4 announce_example_4.cpp) +add_executable(announce_example_5 announce_example_5.cpp) +add_executable(dancing_kirby dancing_kirby.cpp) +add_executable(dining_philosophers dining_philosophers.cpp) +add_executable(hello_world_example hello_world_example.cpp) +add_executable(math_actor_example math_actor_example.cpp) + +# search for libs +if(NOT cppa_LIBRARY) + find_package(Libcppa REQUIRED) +endif (NOT cppa_LIBRARY) + +find_package(Boost COMPONENTS thread REQUIRED) + +link_directories(${Boost_LIBRARY_DIRS}) +include_directories(. ${cppa_INCLUDE} ${Boost_INCLUDE_DIRS}) + +set(EXAMPLE_LIBS ${CMAKE_DL_LIBS} ${CPPA_LIBRARY} ${Boost_THREAD_LIBRARY}) + +target_link_libraries(announce_example_1 ${EXAMPLE_LIBS}) +target_link_libraries(announce_example_2 ${EXAMPLE_LIBS}) +target_link_libraries(announce_example_3 ${EXAMPLE_LIBS}) +target_link_libraries(announce_example_4 ${EXAMPLE_LIBS}) +target_link_libraries(announce_example_5 ${EXAMPLE_LIBS}) +target_link_libraries(dancing_kirby ${EXAMPLE_LIBS}) +target_link_libraries(dining_philosophers ${EXAMPLE_LIBS}) +target_link_libraries(hello_world_example ${EXAMPLE_LIBS}) +target_link_libraries(math_actor_example ${EXAMPLE_LIBS}) diff --git a/examples/FindLibcppa.cmake b/examples/FindLibcppa.cmake new file mode 100644 index 0000000000..c1f1d2236a --- /dev/null +++ b/examples/FindLibcppa.cmake @@ -0,0 +1,65 @@ +# - Try to find libcppa +# Once done this will define +# +# CPPA_FOUND - system has libcppa +# CPPA_INCLUDE - libcppa include dir +# CPPA_LIBRARY - link againgst libcppa +# + +if (CPPA_LIBRARY AND CPPA_INCLUDE) + set(CPPA_FOUND TRUE) +else (CPPA_LIBRARY AND CPPA_INCLUDE) + + find_path(CPPA_INCLUDE + NAMES + cppa/cppa.hpp + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ${CPPA_INCLUDE_PATH} + ${CPPA_LIBRARY_PATH} + ${CMAKE_INCLUDE_PATH} + ${CMAKE_INSTALL_PREFIX}/include + ) + + if (CPPA_INCLUDE) + message (STATUS "Header files found ...") + else (CPPA_INCLUDE) + message (SEND_ERROR "Header files NOT found. Provide absolute path with -DCPPA_INCLUDE_PATH=.") + endif (CPPA_INCLUDE) + + find_library(CPPA_LIBRARY + NAMES + libcppa + cppa + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ${CPPA_INCLUDE_PATH} + ${CPPA_INCLUDE_PATH}/.libs + ${CPPA_LIBRARY_PATH} + ${CPPA_LIBRARY_PATH}/.libs + ${CMAKE_LIBRARY_PATH} + ${CMAKE_INSTALL_PREFIX}/lib + ${LIBRARY_OUTPUT_PATH} + ) + + if (CPPA_LIBRARY) + message (STATUS "Library found ...") + else (CPPA_LIBRARY) + message (SEND_ERROR "Library NOT found. Provide absolute path with -DCPPA_LIBRARY_PATH=.") + endif (CPPA_LIBRARY) + + if (CPPA_INCLUDE AND CPPA_LIBRARY) + set(CPPA_FOUND TRUE) + set(CPPA_INCLUDE ${CPPA_INCLUDE}) + set(CPPA_LIBRARY ${CPPA_LIBRARY}) + else (CPPA_INCLUDE AND CPPA_LIBRARY) + message (FATAL_ERROR "CPPA LIBRARY AND/OR HEADER NOT FOUND!") + endif (CPPA_INCLUDE AND CPPA_LIBRARY) + +endif (CPPA_LIBRARY AND CPPA_INCLUDE) diff --git a/examples/Makefile.am b/examples/Makefile.am deleted file mode 100644 index 01999b5f11..0000000000 --- a/examples/Makefile.am +++ /dev/null @@ -1,37 +0,0 @@ -AUTOMAKE_OPTIONS = subdir-objects -ACLOCAL_AMFLAGS = -I ../m4 - -AM_CXXFLAGS = -I../ --std=c++0x -pedantic -Wall -Wextra - -noinst_PROGRAMS = announce_example_1 \ - announce_example_2 \ - announce_example_3 \ - announce_example_4 \ - announce_example_5 \ - hello_world_example \ - math_actor_example \ - dancing_kirby \ - dining_philosophers - -announce_example_1_SOURCES = announce_example_1.cpp -announce_example_2_SOURCES = announce_example_2.cpp -announce_example_3_SOURCES = announce_example_3.cpp -announce_example_4_SOURCES = announce_example_4.cpp -announce_example_5_SOURCES = announce_example_5.cpp -hello_world_example_SOURCES = hello_world_example.cpp -math_actor_example_SOURCES = math_actor_example.cpp -dancing_kirby_SOURCES = dancing_kirby.cpp -dining_philosophers_SOURCES = dining_philosophers.cpp - -EXAMPLES_LIBS = -L../.libs/ -lcppa $(BOOST_LDFLAGS) $(BOOST_THREAD_LIB) - -announce_example_1_LDADD = $(EXAMPLES_LIBS) -announce_example_2_LDADD = $(EXAMPLES_LIBS) -announce_example_3_LDADD = $(EXAMPLES_LIBS) -announce_example_4_LDADD = $(EXAMPLES_LIBS) -announce_example_5_LDADD = $(EXAMPLES_LIBS) -hello_world_example_LDADD = $(EXAMPLES_LIBS) -math_actor_example_LDADD = $(EXAMPLES_LIBS) -dancing_kirby_LDADD = $(EXAMPLES_LIBS) -dining_philosophers_LDADD = $(EXAMPLES_LIBS) - diff --git a/examples/announce_example_1.cpp b/examples/announce_example_1.cpp index 832ed562a8..61b0f8087f 100644 --- a/examples/announce_example_1.cpp +++ b/examples/announce_example_1.cpp @@ -11,15 +11,13 @@ using std::endl; using namespace cppa; // POD struct -struct foo -{ +struct foo { std::vector a; int b; }; // announce requires foo to have the equal operator implemented -bool operator==(const foo& lhs, const foo& rhs) -{ +bool operator==(const foo& lhs, const foo& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } @@ -30,8 +28,7 @@ typedef std::pair foo_pair; // another pair of two ints typedef std::pair foo_pair2; -int main(int, char**) -{ +int main(int, char**) { // announces foo to the libcppa type system; // the function expects member pointers to all elements of foo assert(announce(&foo::a, &foo::b) == true); @@ -46,7 +43,7 @@ int main(int, char**) assert(announce(&foo_pair2::first, &foo_pair2::second) == false); // send a foo to ourselves - send(self, foo{ { 1, 2, 3, 4 }, 5 }); + send(self, foo{std::vector{1, 2, 3, 4}, 5}); // send a foo_pair2 to ourselves send(self, foo_pair2{3, 4}); // quits the program @@ -58,27 +55,22 @@ int main(int, char**) // receive two messages int i = 0; - receive_for(i, 2) - ( + receive_for(i, 2) ( // 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) - { + on() >> [](const foo_pair& val) { cout << "foo_pair(" << val.first << "," << val.second << ")" << endl; }, - on() >> [](const foo& val) - { + on() >> [](const foo& val) { cout << "foo({"; auto i = val.a.begin(); auto end = val.a.end(); - if (i != end) - { + if (i != end) { cout << *i; - while (++i != end) - { + while (++i != end) { cout << "," << *i; } } diff --git a/examples/announce_example_2.cpp b/examples/announce_example_2.cpp index cc76b7dde3..0acbed69c9 100644 --- a/examples/announce_example_2.cpp +++ b/examples/announce_example_2.cpp @@ -10,8 +10,7 @@ using std::make_pair; using namespace cppa; // a simple class using getter and setter member functions -class foo -{ +class foo { int m_a; int m_b; @@ -37,14 +36,12 @@ class foo }; // announce requires foo to have the equal operator implemented -bool operator==(const foo& lhs, const foo& rhs) -{ +bool operator==(const foo& lhs, const foo& rhs) { return lhs.a() == rhs.a() && lhs.b() == rhs.b(); } -int main(int, char**) -{ +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(make_pair(&foo::a, &foo::set_a), @@ -52,11 +49,9 @@ int main(int, char**) // send a foo to ourselves ... send(self, foo{1,2}); - receive - ( + receive ( // ... and receive it - on() >> [](const foo& val) - { + on() >> [](const foo& val) { cout << "foo(" << val.a() << "," << val.b() << ")" diff --git a/examples/announce_example_3.cpp b/examples/announce_example_3.cpp index 56e3f501c4..a791dd896b 100644 --- a/examples/announce_example_3.cpp +++ b/examples/announce_example_3.cpp @@ -10,8 +10,7 @@ using std::make_pair; using namespace cppa; // a simple class using overloaded getter and setter member functions -class foo -{ +class foo { int m_a; int m_b; @@ -37,8 +36,7 @@ class foo }; // announce requires foo to have the equal operator implemented -bool operator==(const foo& lhs, const foo& rhs) -{ +bool operator==(const foo& lhs, const foo& rhs) { return lhs.a() == rhs.a() && lhs.b() == rhs.b(); } @@ -48,8 +46,7 @@ typedef int (foo::*foo_getter)() const; // a member function pointer to set an attribute of foo typedef void (foo::*foo_setter)(int); -int main(int, char**) -{ +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; @@ -70,11 +67,9 @@ int main(int, char**) // send a foo to ourselves ... send(self, foo{1,2}); - receive - ( + receive ( // ... and receive it - on() >> [](const foo& val) - { + on() >> [](const foo& val) { cout << "foo(" << val.a() << "," << val.b() << ")" diff --git a/examples/announce_example_4.cpp b/examples/announce_example_4.cpp index bce8289876..8749c42d23 100644 --- a/examples/announce_example_4.cpp +++ b/examples/announce_example_4.cpp @@ -9,8 +9,7 @@ using std::make_pair; using namespace cppa; // the foo class from example 3 -class foo -{ +class foo { int m_a; int m_b; @@ -36,29 +35,25 @@ class foo }; // needed for operator==() of bar -bool operator==(const foo& lhs, const foo& rhs) -{ +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 -{ +struct bar { foo f; int i; }; // announce requires bar to have the equal operator implemented -bool operator==(const bar& lhs, const bar& rhs) -{ +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 -{ +class baz { foo m_f; @@ -78,14 +73,12 @@ class baz }; // even worst case classes have to implement operator== -bool operator==(const baz& lhs, const baz& rhs) -{ +bool operator==(const baz& lhs, const baz& rhs) { return lhs.f() == rhs.f() && lhs.b == rhs.b; } -int main(int, char**) -{ +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; @@ -116,18 +109,15 @@ int main(int, char**) // receive two messages int i = 0; - receive_for(i, 2) - ( - on() >> [](const bar& val) - { + receive_for(i, 2) ( + on() >> [](const bar& val) { cout << "bar(foo(" << val.f.a() << "," << val.f.b() << ")," << val.i << ")" << endl; }, - on() >> [](const baz& val) - { + on() >> [](const baz& val) { // prints: baz ( foo ( 1, 2 ), bar ( foo ( 3, 4 ), 5 ) ) cout << to_string(val) << endl; } diff --git a/examples/announce_example_5.cpp b/examples/announce_example_5.cpp index 293a2ced28..1419263f89 100644 --- a/examples/announce_example_5.cpp +++ b/examples/announce_example_5.cpp @@ -21,17 +21,14 @@ using std::endl; using namespace cppa; // a node containing an integer and a vector of children -struct tree_node -{ +struct tree_node { std::uint32_t value; std::vector children; - tree_node(std::uint32_t v = 0) : value(v) - { + tree_node(std::uint32_t v = 0) : value(v) { } - tree_node& add_child(std::uint32_t v = 0) - { + tree_node& add_child(std::uint32_t v = 0) { children.push_back({ v }); return *this; } @@ -39,20 +36,16 @@ struct tree_node tree_node(const tree_node&) = default; // recursively print this node and all of its children to stdout - void print() const - { + void print() const { // format is: value { children0, children1, ..., childrenN } // e.g., 10 { 20 { 21, 22 }, 30 } cout << value; - if (children.empty() == false) - { + if (children.empty() == false) { cout << " { "; auto begin = children.begin(); auto end = children.end(); - for (auto i = begin; i != end; ++i) - { - if (i != begin) - { + for (auto i = begin; i != end; ++i) { + if (i != begin) { cout << ", "; } i->print(); @@ -64,13 +57,11 @@ struct tree_node }; // a very primitive tree implementation -struct tree -{ +struct tree { tree_node root; // print tree to stdout - void print() const - { + void print() const { cout << "tree::print: "; root.print(); cout << endl; @@ -79,13 +70,11 @@ struct tree }; // tree nodes are equals if values and all values of all children are equal -bool operator==(const tree_node& lhs, const tree_node& rhs) -{ +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) -{ +bool operator==(const tree& lhs, const tree& rhs) { return lhs.root == rhs.root; } @@ -94,13 +83,11 @@ bool operator==(const tree& lhs, const tree& rhs) // - does have a default constructor // - does have a copy constructor // - does provide operator== -class tree_type_info : public util::abstract_uniform_type_info -{ +class tree_type_info : public util::abstract_uniform_type_info { protected: - void serialize(const void* ptr, serializer* sink) const - { + void serialize(const void* ptr, serializer* sink) const { // ptr is guaranteed to be a pointer of type tree auto tree_ptr = reinterpret_cast(ptr); // serialization always begins with begin_object(name()) @@ -112,14 +99,12 @@ class tree_type_info : public util::abstract_uniform_type_info sink->end_object(); } - void deserialize(void* ptr, deserializer* source) const - { + void deserialize(void* ptr, deserializer* source) const { // seek_object() gets the uniform name of the next object in the // stream without modifying the deserializer std::string cname = source->seek_object(); // this name has to be our type name - if (cname != name()) - { + if (cname != name()) { throw std::logic_error("wrong type name found"); } // ptr is guaranteed to be a pointer of type tree @@ -134,26 +119,22 @@ class tree_type_info : public util::abstract_uniform_type_info private: - void serialize_node(const tree_node& node, serializer* sink) const - { + 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) - { + for (const tree_node& subnode : node.children) { serialize_node(subnode, sink); } sink->end_sequence(); } - void deserialize_node(tree_node& node, deserializer* source) const - { + void deserialize_node(tree_node& node, deserializer* source) const { // value, ... children ... auto value = get(source->read_value(pt_uint32)); node.value = value; auto num_children = source->begin_sequence(); - for (size_t i = 0; i < num_children; ++i) - { + for (size_t i = 0; i < num_children; ++i) { node.add_child(); deserialize_node(node.children.back(), source); } @@ -162,8 +143,7 @@ class tree_type_info : public util::abstract_uniform_type_info }; -int main() -{ +int main() { // the tree_type_info is owned by libcppa after this function call announce(typeid(tree), new tree_type_info); @@ -200,11 +180,9 @@ int main() // receive both messages int i = 0; - receive_for(i, 2) - ( + receive_for(i, 2) ( // ... and receive it - on() >> [](const tree& tmsg) - { + on() >> [](const tree& tmsg) { // prints the tree in its serialized format: // @<> ( { tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } ) } ) cout << "to_string(self->last_dequeued()): " @@ -214,8 +192,7 @@ int main() // 0 { 10 { 11, 12, 13 } , 20 { 21, 22 } } tmsg.print(); }, - on() >> [](const tree_vector& trees) - { + on() >> [](const tree_vector& trees) { // prints "received 2 trees" cout << "received " << trees.size() << " trees" << endl; // prints: diff --git a/examples/dancing_kirby.cpp b/examples/dancing_kirby.cpp index 1cf5ac2bb7..cb1168985f 100644 --- a/examples/dancing_kirby.cpp +++ b/examples/dancing_kirby.cpp @@ -6,16 +6,14 @@ using std::endl; using namespace cppa; // ASCII art figures -constexpr const char* figures[] = -{ +constexpr const char* figures[] = { "<(^.^<)", "<(^.^)>", "(>^.^)>" }; // array of {figure, offset} pairs -constexpr size_t animation_steps[][2] = -{ +constexpr size_t animation_steps[][2] = { {1, 7}, {0, 7}, {0, 6}, {0, 5}, {1, 5}, {2, 5}, {2, 6}, {2, 7}, {2, 8}, {2, 9}, {2, 10}, {1, 10}, {0, 10}, {0, 9}, {1, 9}, {2, 10}, {2, 11}, {2, 12}, {2, 13}, {1, 13}, {0, 13}, @@ -25,8 +23,7 @@ constexpr size_t animation_steps[][2] = constexpr size_t animation_width = 20; // "draws" an animation step: {offset_whitespaces}{figure}{padding} -void draw_kirby(size_t const (&animation)[2]) -{ +void draw_kirby(size_t const (&animation)[2]) { cout.width(animation_width); cout << '\r'; std::fill_n(std::ostream_iterator{cout}, animation[1], ' '); @@ -35,25 +32,21 @@ void draw_kirby(size_t const (&animation)[2]) cout.flush(); } -void dancing_kirby() -{ +void dancing_kirby() { // let's get it started send(self, atom("Step")); // iterate over animation_steps auto i = std::begin(animation_steps); - receive_for(i, std::end(animation_steps)) - ( - on() >> [&]() - { + receive_for(i, std::end(animation_steps)) ( + on() >> [&]() { draw_kirby(*i); // animate next step in 150ms - future_send(self, std::chrono::milliseconds(150), atom("Step")); + delayed_send(self, std::chrono::milliseconds(150), atom("Step")); } ); } -int main() -{ +int main() { cout << endl; dancing_kirby(); cout << endl; diff --git a/examples/dining_philosophers.cpp b/examples/dining_philosophers.cpp index ecdb32639c..3a1fb6723c 100644 --- a/examples/dining_philosophers.cpp +++ b/examples/dining_philosophers.cpp @@ -12,34 +12,26 @@ using std::chrono::seconds; using namespace cppa; // either taken by a philosopher or available -struct chopstick : fsm_actor -{ +struct chopstick : sb_actor { behavior& init_state; // a reference to available behavior available; - behavior taken_by(const actor_ptr& philos) - { + behavior taken_by(const actor_ptr& philos) { // create a behavior new on-the-fly - return - ( - on() >> [=](actor_ptr other) - { + return ( + on() >> [=](actor_ptr other) { send(other, atom("busy"), this); }, - on(atom("put"), philos) >> [=]() - { + on(atom("put"), philos) >> [=]() { become(&available); } ); } - chopstick() : init_state(available) - { - available = - ( - on() >> [=](actor_ptr philos) - { + chopstick() : init_state(available) { + available = ( + on() >> [=](actor_ptr philos) { send(philos, atom("taken"), this); become(taken_by(philos)); } @@ -81,8 +73,7 @@ struct chopstick : fsm_actor * [ X = right => Y = left ] */ -struct philosopher : fsm_actor -{ +struct philosopher : sb_actor { std::string name; // the name of this philosopher actor_ptr left; // left chopstick @@ -97,12 +88,9 @@ struct philosopher : fsm_actor behavior init_state; // wait for second chopstick - behavior waiting_for(const actor_ptr& what) - { - return - ( - on(atom("taken"), what) >> [=]() - { + behavior waiting_for(const actor_ptr& what) { + return ( + on(atom("taken"), what) >> [=]() { // create message in memory to avoid interleaved // messages on the terminal std::ostringstream oss; @@ -114,11 +102,10 @@ struct philosopher : fsm_actor << " and starts to eat\n"; cout << oss.str(); // eat some time - future_send(this, seconds(5), atom("think")); + delayed_send(this, seconds(5), atom("think")); become(&eating); }, - on(atom("busy"), what) >> [=]() - { + on(atom("busy"), what) >> [=]() { send((what == left) ? right : left, atom("put"), this); send(this, atom("eat")); become(&thinking); @@ -127,69 +114,55 @@ struct philosopher : fsm_actor } philosopher(const std::string& n, const actor_ptr& l, const actor_ptr& r) - : name(n), left(l), right(r) - { + : name(n), left(l), right(r) { // a philosopher that receives {eat} stops thinking and becomes hungry - thinking = - ( - on(atom("eat")) >> [=]() - { + thinking = ( + on(atom("eat")) >> [=]() { become(&hungry); send(left, atom("take"), this); send(right, atom("take"), this); } ); // wait for the first answer of a chopstick - hungry = - ( - on(atom("taken"), left) >> [=]() - { + hungry = ( + on(atom("taken"), left) >> [=]() { become(waiting_for(right)); }, - on(atom("taken"), right) >> [=]() - { + on(atom("taken"), right) >> [=]() { become(waiting_for(left)); }, - on() >> [=]() - { + on() >> [=]() { become(&denied); } ); // philosopher was not able to obtain the first chopstick - denied = - ( - on() >> [=](actor_ptr& ptr) - { + denied = ( + on() >> [=](actor_ptr& ptr) { send(ptr, atom("put"), this); send(this, atom("eat")); become(&thinking); }, - on() >> [=]() - { + on() >> [=]() { send(this, atom("eat")); become(&thinking); } ); // philosopher obtained both chopstick and eats (for five seconds) - eating = - ( - on(atom("think")) >> [=]() - { + eating = ( + on(atom("think")) >> [=]() { send(left, atom("put"), this); send(right, atom("put"), this); - future_send(this, seconds(5), atom("eat")); + delayed_send(this, seconds(5), atom("eat")); cout << ( name + " puts down his chopsticks and starts to think\n"); become(&thinking); } ); // philosophers start to think after receiving {think} - init_state = - ( - on(atom("think")) >> [=]() - { + init_state = ( + on(atom("think")) >> [=]() { cout << (name + " starts to think\n"); - future_send(this, seconds(5), atom("eat")); + delayed_send(this, seconds(5), atom("eat")); become(&thinking); } ); @@ -197,14 +170,12 @@ struct philosopher : fsm_actor }; -int main(int, char**) -{ +int main(int, char**) { // create five chopsticks cout << "chopstick ids:"; std::vector chopsticks; - for (size_t i = 0; i < 5; ++i) - { - chopsticks.push_back(spawn(new chopstick)); + for (size_t i = 0; i < 5; ++i) { + chopsticks.push_back(spawn()); cout << " " << chopsticks.back()->id(); } cout << endl; @@ -213,10 +184,11 @@ int main(int, char**) // spawn five philosopher, each joining the Dinner Club std::vector names = { "Plato", "Hume", "Kant", "Nietzsche", "Descartes" }; - for (size_t i = 0; i < 5; ++i) - { - spawn(new philosopher(names[i], chopsticks[i], - chopsticks[(i+1)%5]) )->join(dinner_club); + for (size_t i = 0; i < 5; ++i) { + spawn_in_group(dinner_club, + names[i], + chopsticks[i], + chopsticks[(i+1) % chopsticks.size()]); } // tell philosophers to start thinking send(dinner_club, atom("think")); diff --git a/examples/hello_world_example.cpp b/examples/hello_world_example.cpp index d3b1acc678..e5c7f3fbf7 100644 --- a/examples/hello_world_example.cpp +++ b/examples/hello_world_example.cpp @@ -4,14 +4,11 @@ using namespace cppa; -void echo_actor() -{ +void echo_actor() { // wait for a message - receive - ( + receive ( // invoke this lambda expression if we receive a string - on() >> [](const std::string& what) - { + on() >> [](const std::string& what) { // prints "Hello World!" std::cout << what << std::endl; // replies "!dlroW olleH" @@ -20,18 +17,15 @@ void echo_actor() ); } -int main() -{ +int main() { // create a new actor that invokes the function echo_actor auto hello_actor = spawn(echo_actor); // send "Hello World!" to our new actor - // note: libcppa converts string literals to std::string objects + // note: libcppa converts string literals to std::string send(hello_actor, "Hello World!"); // wait for a response and print it - receive - ( - on() >> [](const std::string& what) - { + receive ( + on() >> [](const std::string& what) { // prints "!dlroW olleH" std::cout << what << std::endl; } diff --git a/examples/math_actor_example.cpp b/examples/math_actor_example.cpp index 661bb3b8f4..4eb0b85f6d 100644 --- a/examples/math_actor_example.cpp +++ b/examples/math_actor_example.cpp @@ -7,26 +7,20 @@ using std::cout; using std::endl; using namespace cppa; -void math_fun() -{ +void math_fun() { bool done = false; - // receive messages until we receive {quit} - do_receive - ( + do_receive ( // "arg_match" matches the parameter types of given lambda expression // thus, it's equal to // - on() // - on(atom("plus"), val, val) - on(atom("plus"), arg_match) >> [](int a, int b) - { + on(atom("plus"), arg_match) >> [](int a, int b) { reply(atom("result"), a + b); }, - on() >> [](int a, int b) - { + on() >> [](int a, int b) { reply(atom("result"), a - b); }, - on(atom("quit")) >> [&]() - { + on(atom("quit")) >> [&]() { // note: quit(exit_reason::normal) would terminate the actor // but is best avoided since it forces stack unwinding // by throwing an exception @@ -34,39 +28,31 @@ void math_fun() } ) .until(gref(done)); - //.until([&]() { return done; }); } -struct math_actor : event_based_actor -{ - void init() - { +struct math_actor : event_based_actor { + void init() { // execute this behavior until actor terminates - become - ( - on(atom("plus"), arg_match) >> [](int a, int b) - { + become ( + on(atom("plus"), arg_match) >> [](int a, int b) { reply(atom("result"), a + b); }, - on(atom("minus"), arg_match) >> [](int a, int b) - { + on(atom("minus"), arg_match) >> [](int a, int b) { reply(atom("result"), a - b); }, // the [=] capture copies the 'this' pointer into the lambda // thus, it has access to all members and member functions - on(atom("quit")) >> [=]() - { + on(atom("quit")) >> [=]() { // set an empty behavior // (terminates actor with normal exit reason) - become_void(); + quit(); } ); } }; // utility function -int fetch_result(actor_ptr& calculator, atom_value operation, int a, int b) -{ +int fetch_result(actor_ptr& calculator, atom_value operation, int a, int b) { // send request send(calculator, operation, a, b); // wait for result @@ -77,12 +63,11 @@ int fetch_result(actor_ptr& calculator, atom_value operation, int a, int b) return result; } -int main() -{ +int main() { // spawn a context-switching actor that invokes math_fun auto a1 = spawn(math_fun); // spawn an event-based math actor - auto a2 = spawn(new math_actor); + auto a2 = spawn(); // do some testing on both implementations assert((fetch_result(a1, atom("plus"), 1, 2) == 3)); assert((fetch_result(a2, atom("plus"), 1, 2) == 3)); diff --git a/gen_server/parallel_send.cpp b/gen_server/parallel_send.cpp index e881d39d8c..14c42e64f6 100644 --- a/gen_server/parallel_send.cpp +++ b/gen_server/parallel_send.cpp @@ -7,18 +7,14 @@ using std::endl; using boost::timer; using namespace cppa; -void counter_actor() -{ +void counter_actor() { long count = 0; - receive_loop - ( - on() >> [&](actor_ptr client) - { + receive_loop ( + on() >> [&](actor_ptr client) { send(client, count); count = 0; }, - on() >> [&](long val) - { + on() >> [&](long val) { count += val; } ); @@ -26,34 +22,27 @@ void counter_actor() constexpr long s_val = 100; -void send_range(actor_ptr counter, actor_ptr parent, int from, int to) -{ - for (int i = from; i < to; ++i) - { +void send_range(actor_ptr counter, actor_ptr parent, int from, int to) { + for (int i = from; i < to; ++i) { send(counter, atom("AddCount"), s_val); } send(parent, atom("Done")); } -long the_test(int msg_count) -{ +long the_test(int msg_count) { actor_ptr self_ptr = self(); auto counter = spawn(counter_actor); - for (int i = 1; i < (msg_count / 1000); ++i) - { + for (int i = 1; i < (msg_count / 1000); ++i) { spawn(send_range, counter, self_ptr, (i-1)*1000, i*1000); } auto rule = on() >> []() { }; - for (int i = 1; i < (msg_count / 1000); ++i) - { + for (int i = 1; i < (msg_count / 1000); ++i) { receive(rule); } send(counter, atom("Get"), self()); long result = 0; - receive - ( - on() >> [&](long value) - { + receive ( + on() >> [&](long value) { result = value; } ); @@ -61,8 +50,7 @@ long the_test(int msg_count) return result; } -void run_test(int msg_count) -{ +void run_test(int msg_count) { timer t0; long count = the_test(msg_count); auto elapsed = t0.elapsed(); @@ -71,8 +59,7 @@ void run_test(int msg_count) << "Throughput = " << (msg_count / elapsed) << " per sec" << endl; } -int main() -{ +int main() { run_test(3000000); await_all_others_done(); return 0; diff --git a/gen_server/sequential_send.cpp b/gen_server/sequential_send.cpp index f6f4c23185..f7d83f8e34 100644 --- a/gen_server/sequential_send.cpp +++ b/gen_server/sequential_send.cpp @@ -7,39 +7,31 @@ using std::endl; using boost::timer; using namespace cppa; -void counter_actor() -{ +void counter_actor() { long count = 0; - receive_loop - ( - on() >> [&](long val) - { + receive_loop ( + on() >> [&](long val) { count += val; }, - on() >> [&](actor_ptr client) - { + on() >> [&](actor_ptr client) { send(client, count); count = 0; } ); } -long the_test(int msg_count) -{ +long the_test(int msg_count) { constexpr long val = 100; auto counter = spawn(counter_actor); auto msg = make_tuple(atom("AddCount"), val); - for (int i = 0; i < msg_count; ++i) - { + for (int i = 0; i < msg_count; ++i) { counter << msg; //send(counter, atom("AddCount"), val); } send(counter, atom("Get"), self); long result = 0; - receive - ( - on() >> [&](long value) - { + receive ( + on() >> [&](long value) { result = value; } ); @@ -47,8 +39,7 @@ long the_test(int msg_count) return result; } -void run_test(int msg_count) -{ +void run_test(int msg_count) { timer t0; long count = the_test(msg_count); auto elapsed = t0.elapsed(); @@ -58,8 +49,7 @@ void run_test(int msg_count) << " per sec" << endl; } -int main() -{ +int main() { run_test(3000000); await_all_others_done(); return 0; diff --git a/libcppa.pc.in b/libcppa.pc.in deleted file mode 100644 index e7bd42299f..0000000000 --- a/libcppa.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libcppa -Description: C++ actors library. -#Requires: -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lcppa -Cflags: -I${includedir}/cppa/@PACKAGE_VERSION@ diff --git a/m4/ax_boost_base.m4 b/m4/ax_boost_base.m4 deleted file mode 100644 index b2a00b8b62..0000000000 --- a/m4/ax_boost_base.m4 +++ /dev/null @@ -1,219 +0,0 @@ -# =========================================================================== -# http://www.nongnu.org/autoconf-archive/ax_boost_base.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_BASE([MINIMUM-VERSION]) -# -# DESCRIPTION -# -# Test for the Boost C++ libraries of a particular version (or newer) -# -# If no path to the installed boost library is given the macro searchs -# under /usr, /usr/local, /opt and /opt/local and evaluates the -# $BOOST_ROOT environment variable. Further documentation is available at -# . -# -# This macro calls: -# -# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) -# -# And sets: -# -# HAVE_BOOST -# -# LICENSE -# -# Copyright (c) 2008 Thomas Porschberg -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. - -AC_DEFUN([AX_BOOST_BASE], -[ -AC_ARG_WITH([boost], - AS_HELP_STRING([--with-boost@<:@=DIR@:>@], [use boost (default is yes) - it is possible to specify the root directory for boost (optional)]), - [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ac_boost_path="" - else - want_boost="yes" - ac_boost_path="$withval" - fi - ], - [want_boost="yes"]) - - -AC_ARG_WITH([boost-libdir], - AS_HELP_STRING([--with-boost-libdir=LIB_DIR], - [Force given directory for boost libraries. Note that this will overwrite library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]), - [ - if test -d $withval - then - ac_boost_lib_path="$withval" - else - AC_MSG_ERROR(--with-boost-libdir expected directory name) - fi - ], - [ac_boost_lib_path=""] -) - -if test "x$want_boost" = "xyes"; then - boost_lib_version_req=ifelse([$1], ,1.20.0,$1) - boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'` - boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'` - boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` - boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` - if test "x$boost_lib_version_req_sub_minor" = "x" ; then - boost_lib_version_req_sub_minor="0" - fi - WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor` - AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req) - succeeded=no - - dnl first we check the system location for boost libraries - dnl this location ist chosen if boost libraries are installed with the --layout=system option - dnl or if you install boost with RPM - if test "$ac_boost_path" != ""; then - BOOST_LDFLAGS="-L$ac_boost_path/lib" - BOOST_CPPFLAGS="-I$ac_boost_path/include" - else - for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do - if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then - BOOST_LDFLAGS="-L$ac_boost_path_tmp/lib" - BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include" - break; - fi - done - fi - - dnl overwrite ld flags if we have required special directory with - dnl --with-boost-libdir parameter - if test "$ac_boost_lib_path" != ""; then - BOOST_LDFLAGS="-L$ac_boost_lib_path" - fi - - CPPFLAGS_SAVED="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - - LDFLAGS_SAVED="$LDFLAGS" - LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" - export LDFLAGS - - AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - @%:@include - ]], [[ - #if BOOST_VERSION >= $WANT_BOOST_VERSION - // Everything is okay - #else - # error Boost version is too old - #endif - ]])],[ - AC_MSG_RESULT(yes) - succeeded=yes - found_system=yes - ],[ - ]) - AC_LANG_POP([C++]) - - - - dnl if we found no boost with system layout we search for boost libraries - dnl built and installed without the --layout=system option or for a staged(not installed) version - if test "x$succeeded" != "xyes"; then - _version=0 - if test "$ac_boost_path" != ""; then - if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then - for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do - _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` - V_CHECK=`expr $_version_tmp \> $_version` - if test "$V_CHECK" = "1" ; then - _version=$_version_tmp - fi - VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` - BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" - done - fi - else - for ac_boost_path in /usr /usr/local /opt /opt/local ; do - if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then - for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do - _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` - V_CHECK=`expr $_version_tmp \> $_version` - if test "$V_CHECK" = "1" ; then - _version=$_version_tmp - best_path=$ac_boost_path - fi - done - fi - done - - VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` - BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" - if test "$ac_boost_lib_path" = "" - then - BOOST_LDFLAGS="-L$best_path/lib" - fi - - if test "x$BOOST_ROOT" != "x"; then - if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/lib" && test -r "$BOOST_ROOT/stage/lib"; then - version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` - stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` - stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` - V_CHECK=`expr $stage_version_shorten \>\= $_version` - if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then - AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) - BOOST_CPPFLAGS="-I$BOOST_ROOT" - BOOST_LDFLAGS="-L$BOOST_ROOT/stage/lib" - fi - fi - fi - fi - - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" - export LDFLAGS - - AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - @%:@include - ]], [[ - #if BOOST_VERSION >= $WANT_BOOST_VERSION - // Everything is okay - #else - # error Boost version is too old - #endif - ]])],[ - AC_MSG_RESULT(yes) - succeeded=yes - found_system=yes - ],[ - ]) - AC_LANG_POP([C++]) - fi - - if test "$succeeded" != "yes" ; then - if test "$_version" = "0" ; then - AC_MSG_ERROR([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) - else - AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) - fi - else - AC_SUBST(BOOST_CPPFLAGS) - AC_SUBST(BOOST_LDFLAGS) - AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) - fi - - CPPFLAGS="$CPPFLAGS_SAVED" - LDFLAGS="$LDFLAGS_SAVED" -fi - -]) diff --git a/m4/ax_boost_thread.m4 b/m4/ax_boost_thread.m4 deleted file mode 100644 index 6ac10bbee3..0000000000 --- a/m4/ax_boost_thread.m4 +++ /dev/null @@ -1,149 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_thread.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_THREAD -# -# DESCRIPTION -# -# Test for Thread library from the Boost C++ libraries. The macro requires -# a preceding call to AX_BOOST_BASE. Further documentation is available at -# . -# -# This macro calls: -# -# AC_SUBST(BOOST_THREAD_LIB) -# -# And sets: -# -# HAVE_BOOST_THREAD -# -# LICENSE -# -# Copyright (c) 2009 Thomas Porschberg -# Copyright (c) 2009 Michael Tindal -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 23 - -AC_DEFUN([AX_BOOST_THREAD], -[ - AC_ARG_WITH([boost-thread], - AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@], - [use the Thread library from boost - it is possible to specify a certain library for the linker - e.g. --with-boost-thread=boost_thread-gcc-mt ]), - [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ax_boost_user_thread_lib="" - else - want_boost="yes" - ax_boost_user_thread_lib="$withval" - fi - ], - [want_boost="yes"] - ) - - if test "x$want_boost" = "xyes"; then - AC_REQUIRE([AC_PROG_CC]) - AC_REQUIRE([AC_CANONICAL_BUILD]) - CPPFLAGS_SAVED="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" - export CPPFLAGS - - LDFLAGS_SAVED="$LDFLAGS" - LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" - export LDFLAGS - - AC_CACHE_CHECK(whether the Boost::Thread library is available, - ax_cv_boost_thread, - [AC_LANG_PUSH([C++]) - CXXFLAGS_SAVE=$CXXFLAGS - - if test "x$host_os" = "xsolaris" ; then - CXXFLAGS="-pthreads $CXXFLAGS" - elif test "x$host_os" = "xmingw32" ; then - CXXFLAGS="-mthreads $CXXFLAGS" - else - CXXFLAGS="-pthread $CXXFLAGS" - fi - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::thread_group thrds; - return 0;]])], - ax_cv_boost_thread=yes, ax_cv_boost_thread=no) - CXXFLAGS=$CXXFLAGS_SAVE - AC_LANG_POP([C++]) - ]) - if test "x$ax_cv_boost_thread" = "xyes"; then - if test "x$host_os" = "xsolaris" ; then - BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS" - elif test "x$host_os" = "xmingw32" ; then - BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS" - else - BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS" - fi - - AC_SUBST(BOOST_CPPFLAGS) - - AC_DEFINE(HAVE_BOOST_THREAD,,[define if the Boost::Thread library is available]) - BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` - - LDFLAGS_SAVE=$LDFLAGS - case "x$host_os" in - *bsd* ) - LDFLAGS="-pthread $LDFLAGS" - break; - ;; - esac - if test "x$ax_boost_user_thread_lib" = "x"; then - for libextension in `ls $BOOSTLIBDIR/libboost_thread*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_thread.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_thread*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_thread.*\)\.a*$;\1;'`; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], - [link_thread="no"]) - done - if test "x$link_thread" != "xyes"; then - for libextension in `ls $BOOSTLIBDIR/boost_thread*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_thread.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_thread*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_thread.*\)\.a*$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], - [link_thread="no"]) - done - fi - - else - for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do - AC_CHECK_LIB($ax_lib, exit, - [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], - [link_thread="no"]) - done - - fi - if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) - fi - if test "x$link_thread" = "xno"; then - AC_MSG_ERROR(Could not link against $ax_lib !) - else - case "x$host_os" in - *bsd* ) - BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS" - break; - ;; - esac - - fi - fi - - CPPFLAGS="$CPPFLAGS_SAVED" - LDFLAGS="$LDFLAGS_SAVED" - fi -]) diff --git a/old_configure.sh b/old_configure.sh deleted file mode 100755 index 821d463e9e..0000000000 --- a/old_configure.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/bash - -# some neede variables to create 'Makefile.rules' -HEADERS="" -SOURCES="" -NLINE="\\n" -BSLASH="\\\\" -# appends *.hpp from $1 to $HEADERS -function append_hpp_from() -{ - for i in "$1"/*.hpp ; do - HEADERS="$HEADERS ${BSLASH}${NLINE} $i" - done -} -# appends *.cpp from $1 to $SOURCES -function append_cpp_from() -{ - for i in "$1/"*.cpp ; do - SOURCES="$SOURCES ${BSLASH}${NLINE} $i" - done -} -# default flags -gcc_flags="-std=c++0x -pedantic -Wall -Wextra -g -O0 -I/opt/local/include/ -fpermissive -Wno-deprecated-declarations" -# get all g++ binaries -gcc_found=$(find /bin/ /usr/bin /usr/local/bin /opt/bin /opt/local/bin -regex "^.*/g\+\+.*$" 2>/dev/null) -# holds the finally selected g++ binary -gcc_selected="" -# checks if g++ binary $1 is able to compile cpp0x_test.cpp -function compatibility_test() -{ - if $1 $gcc_flags -o variadic_templates_test variadic_templates_test.cpp &>/dev/null ; then - if test "x$(./variadic_templates_test)" "!=" "xyes" ; then - return -1 - else - return 0 - fi - fi -} -# iterates over all found g++ binaries until a suitable binary is found -for i in $gcc_found ; do - version=$($i -v 2>&1 | grep -oE "gcc version [0-9](\.[0-9]){2}" | grep -oE "[0-9](\.[0-9]){2}") - if test "!" $version "<" 4.6.0 ; then - if compatibility_test "$i" ; then - gcc_selected=$i - break - fi - fi -done -# did we found a suitable g++ binary? -if test -z "$gcc_selected" ; then - echo "no GCC >= 4.6.0 found ... quit" - exit -fi -echo "chosen g++ binary: $gcc_selected" -# ok, write makefiles now -echo "build Makefiles..." -# link file descriptor #6 to stdout -exec 6>&1 -# redirect stdout to Makefile.rules -exec >Makefile.rules -printf "%b\n" "CXX = $gcc_selected" -printf "%b\n" "CXXFLAGS = $gcc_flags" -if test $(uname) = "Darwin" ; then - printf "%b\n" "LIBS = -L/opt/local/lib -lboost_thread-mt" -else - printf "%b\n" "LIBS = -lboost_thread" -fi -# redirect stdout to libcppa.Makefile -exec >libcppa.Makefile -append_hpp_from "cppa" -append_hpp_from "cppa/detail" -append_hpp_from "cppa/util" -append_cpp_from "src" -printf "%b\n" "include Makefile.rules" -printf "%b\n" "INCLUDE_FLAGS = \$(INCLUDES) -I./" -printf "\n" -printf "%b\n" "HEADERS =$HEADERS" -printf "\n" -printf "%b\n" "SOURCES =$SOURCES" -printf "\n" -printf "%b\n" "OBJECTS = \$(SOURCES:.cpp=.o)" -printf "\n" -printf "%b\n" "LIB_NAME = $LIB_NAME" -printf "\n" -printf "%b\n" "%.o : %.cpp \$(HEADERS)" -printf "%b\n" "\t\$(CXX) \$(CXXFLAGS) \$(INCLUDE_FLAGS) -fPIC -c \$< -o \$@" -printf "\n" -printf "%b\n" "libcppa.so.0.0.0 : \$(OBJECTS) \$(HEADERS)" -if test "$(uname)" "=" "Darwin" ; then - printf "%b\n" "\t\$(CXX) \$(LIBS) -dynamiclib -o libcppa.dylib \$(OBJECTS)" -else - printf "%b\n" "\t\$(CXX) \$(LIBS) -shared -Wl,-soname,libcppa.so.0 -o libcppa.so.0.0.0 \$(OBJECTS)" - printf "%b\n" "\tln -s libcppa.so.0.0.0 libcppa.so.0.0" - printf "%b\n" "\tln -s libcppa.so.0.0.0 libcppa.so.0" - printf "%b\n" "\tln -s libcppa.so.0.0.0 libcppa.so" -fi -printf "\n" -printf "%b\n" "all : libcppa.so.0.0.0 \$(OBJECTS)" -printf "\n" -printf "%b\n" "clean:" -printf "%b\n" "\trm -f libcppa.so libcppa.so.0 libcppa.so.0.0 libcppa.so.0.0.0 \$(OBJECTS)" -# redirect stdout to Makefile -exec >Makefile -printf "%b\n" "all:" -printf "%b\n" "\tmake -f libcppa.Makefile" -printf "%b\n" "\tmake -C unit_testing" -printf "%b\n" "\tmake -C queue_performances" -printf "\n" -printf "%b\n" "clean:" -printf "%b\n" "\tmake -f libcppa.Makefile clean" -printf "%b\n" "\tmake -C unit_testing clean" -printf "%b\n" "\tmake -C queue_performances clean" - -# restore stdout -exec 1>&6 - -echo "done" diff --git a/queue_performances/blocking_cached_stack.hpp b/queue_performances/blocking_cached_stack.hpp index 305b99838d..6d5cbd2a2a 100644 --- a/queue_performances/blocking_cached_stack.hpp +++ b/queue_performances/blocking_cached_stack.hpp @@ -8,8 +8,7 @@ // This class is intrusive. template -class blocking_cached_stack -{ +class blocking_cached_stack { // singly linked list, serves as cache T* m_head; @@ -28,16 +27,12 @@ class blocking_cached_stack // read all elements of m_stack, convert them to FIFO order and store // them in m_head // precondition: m_head == nullptr - bool consume_stack() - { + bool consume_stack() { T* e = m_stack.load(); - while (e) - { - if (m_stack.compare_exchange_weak(e, 0)) - { + while (e) { + if (m_stack.compare_exchange_weak(e, 0)) { // m_stack is now empty (m_stack == nullptr) - while (e) - { + while (e) { T* next = e->next; // enqueue to m_head e->next = m_head; @@ -52,10 +47,8 @@ class blocking_cached_stack return false; } - void wait_for_data() - { - if (!m_head && !(m_stack.load())) - { + void wait_for_data() { + if (!m_head && !(m_stack.load())) { lock_type lock(m_mtx); while (!(m_stack.load())) m_cv.wait(lock); } @@ -63,17 +56,13 @@ class blocking_cached_stack public: - blocking_cached_stack() : m_head(0) - { + blocking_cached_stack() : m_head(0) { m_stack = 0; } - ~blocking_cached_stack() - { - do - { - while (m_head) - { + ~blocking_cached_stack() { + do { + while (m_head) { T* next = m_head->next; delete m_head; m_head = next; @@ -83,17 +72,13 @@ class blocking_cached_stack while (consume_stack()); } - void push(T* what) - { + void push(T* what) { T* e = m_stack.load(); - for (;;) - { + for (;;) { what->next = e; - if (!e) - { + if (!e) { lock_type lock(m_mtx); - if (m_stack.compare_exchange_weak(e, what)) - { + if (m_stack.compare_exchange_weak(e, what)) { m_cv.notify_one(); return; } @@ -104,10 +89,8 @@ class blocking_cached_stack } } - T* try_pop() - { - if (m_head || consume_stack()) - { + T* try_pop() { + if (m_head || consume_stack()) { T* result = m_head; m_head = m_head->next; return result; @@ -115,8 +98,7 @@ class blocking_cached_stack return 0; } - T* pop() - { + T* pop() { wait_for_data(); return try_pop(); } diff --git a/queue_performances/blocking_cached_stack2.hpp b/queue_performances/blocking_cached_stack2.hpp index bc8a78902a..91a74fceab 100644 --- a/queue_performances/blocking_cached_stack2.hpp +++ b/queue_performances/blocking_cached_stack2.hpp @@ -8,8 +8,7 @@ // This class is intrusive. template -class blocking_cached_stack2 -{ +class blocking_cached_stack2 { // singly linked list, serves as cache T* m_head; @@ -31,19 +30,15 @@ class blocking_cached_stack2 // read all elements of m_stack, convert them to FIFO order and store // them in m_head // precondition: m_head == nullptr - void consume_stack() - { + void consume_stack() { T* e = m_stack.load(); - while (e) - { + while (e) { // enqueue dummy instead of nullptr to reduce // lock operations - if (m_stack.compare_exchange_weak(e, m_dummy)) - { + if (m_stack.compare_exchange_weak(e, m_dummy)) { // m_stack is now empty (m_stack == m_dummy) // m_dummy marks always the end of the stack - while (e && e != m_dummy) - { + while (e && e != m_dummy) { T* next = e->next; // enqueue to m_head e->next = m_head; @@ -57,17 +52,13 @@ class blocking_cached_stack2 // nothing to consume } - void wait_for_data() - { - if (!m_head) - { + void wait_for_data() { + if (!m_head) { T* e = m_stack.load(); - while (e == m_dummy) - { + while (e == m_dummy) { if (m_stack.compare_exchange_weak(e, 0)) e = 0; } - if (!e) - { + if (!e) { lock_type lock(m_mtx); while (!(m_stack.load())) m_cv.wait(lock); } @@ -75,10 +66,8 @@ class blocking_cached_stack2 } } - void delete_head() - { - while (m_head) - { + void delete_head() { + while (m_head) { T* next = m_head->next; delete m_head; m_head = next; @@ -88,35 +77,28 @@ class blocking_cached_stack2 public: - blocking_cached_stack2() : m_head(0) - { + blocking_cached_stack2() : m_head(0) { m_stack = 0; m_dummy = new T; } - ~blocking_cached_stack2() - { + ~blocking_cached_stack2() { delete_head(); T* e = m_stack.load(); - if (e && e != m_dummy) - { + if (e && e != m_dummy) { consume_stack(); delete_head(); } delete m_dummy; } - void push(T* what) - { + void push(T* what) { T* e = m_stack.load(); - for (;;) - { + for (;;) { what->next = e; - if (!e) - { + if (!e) { lock_type lock(m_mtx); - if (m_stack.compare_exchange_weak(e, what)) - { + if (m_stack.compare_exchange_weak(e, what)) { m_cv.notify_one(); return; } @@ -127,8 +109,7 @@ class blocking_cached_stack2 } } - T* pop() - { + T* pop() { wait_for_data(); T* result = m_head; m_head = m_head->next; diff --git a/queue_performances/blocking_sutter_list.hpp b/queue_performances/blocking_sutter_list.hpp index f944f36511..c887f90ac5 100644 --- a/queue_performances/blocking_sutter_list.hpp +++ b/queue_performances/blocking_sutter_list.hpp @@ -12,11 +12,9 @@ // T is any type template -class blocking_sutter_list -{ +class blocking_sutter_list { - struct node - { + struct node { node(T* val = 0) : value(val), next(0) { } T* value; std::atomic next; @@ -43,16 +41,13 @@ class blocking_sutter_list public: - blocking_sutter_list() - { + blocking_sutter_list() { m_first = m_last = new node; m_producer_lock = false; } - ~blocking_sutter_list() - { - while (m_first) - { + ~blocking_sutter_list() { + while (m_first) { node* tmp = m_first; m_first = tmp->next; delete tmp; @@ -60,13 +55,11 @@ class blocking_sutter_list } // takes ownership of what - void push(T* what) - { + void push(T* what) { bool consumer_might_sleep = 0; node* tmp = new node(what); // acquire exclusivity - while (m_producer_lock.exchange(true)) - { + while (m_producer_lock.exchange(true)) { std::this_thread::yield(); } // do we have to wakeup a sleeping consumer? @@ -79,23 +72,19 @@ class blocking_sutter_list // release exclusivity m_producer_lock = false; // wakeup consumer if needed - if (consumer_might_sleep) - { + if (consumer_might_sleep) { lock_type lock(m_mtx); m_cv.notify_one(); } } // polls the queue until an element was dequeued - T* pop() - { + T* pop() { node* first = m_first; node* next = m_first->next; - if (!next) - { + if (!next) { lock_type lock(m_mtx); - while (!(next = m_first->next)) - { + while (!(next = m_first->next)) { m_cv.wait(lock); } } diff --git a/queue_performances/cached_stack.hpp b/queue_performances/cached_stack.hpp index 00c867e209..1bf752a722 100644 --- a/queue_performances/cached_stack.hpp +++ b/queue_performances/cached_stack.hpp @@ -8,8 +8,7 @@ // This class is intrusive. template -class cached_stack -{ +class cached_stack { // singly linked list, serves as cache T* m_head; @@ -21,16 +20,12 @@ class cached_stack // read all elements of m_stack, convert them to FIFO order and store // them in m_head // precondition: m_head == nullptr - bool consume_stack() - { + bool consume_stack() { T* e = m_stack.load(); - while (e) - { - if (m_stack.compare_exchange_weak(e, 0)) - { + while (e) { + if (m_stack.compare_exchange_weak(e, 0)) { // m_stack is now empty (m_stack == nullptr) - while (e) - { + while (e) { T* next = e->next; // enqueue to m_head e->next = m_head; @@ -47,17 +42,13 @@ class cached_stack public: - cached_stack() : m_head(0) - { + cached_stack() : m_head(0) { m_stack = 0; } - ~cached_stack() - { - do - { - while (m_head) - { + ~cached_stack() { + do { + while (m_head) { T* next = m_head->next; delete m_head; m_head = next; @@ -67,11 +58,9 @@ class cached_stack while (consume_stack()); } - void push(T* what) - { + void push(T* what) { T* e = m_stack.load(); - for (;;) - { + for (;;) { what->next = e; // compare_exchange_weak stores the // new value to e if the operation fails @@ -79,10 +68,8 @@ class cached_stack } } - T* try_pop() - { - if (m_head || consume_stack()) - { + T* try_pop() { + if (m_head || consume_stack()) { T* result = m_head; m_head = m_head->next; return result; @@ -90,11 +77,9 @@ class cached_stack return 0; } - T* pop() - { + T* pop() { T* result = try_pop(); - while (!result) - { + while (!result) { std::this_thread::yield(); result = try_pop(); } diff --git a/queue_performances/intrusive_sutter_list.hpp b/queue_performances/intrusive_sutter_list.hpp index 5f0e1063fe..4fac1c0138 100644 --- a/queue_performances/intrusive_sutter_list.hpp +++ b/queue_performances/intrusive_sutter_list.hpp @@ -12,13 +12,11 @@ // T is any type template -class intrusive_sutter_list -{ +class intrusive_sutter_list { public: - struct node - { + struct node { node(T val = T()) : value(val), next(0) { } T value; std::atomic next; @@ -40,16 +38,13 @@ class intrusive_sutter_list public: - intrusive_sutter_list() - { + intrusive_sutter_list() { m_first = m_last = new node; m_producer_lock = false; } - ~intrusive_sutter_list() - { - while (m_first) - { + ~intrusive_sutter_list() { + while (m_first) { node* tmp = m_first; m_first = tmp->next; delete tmp; @@ -57,11 +52,9 @@ class intrusive_sutter_list } // takes ownership of what - void push(node* tmp) - { + void push(node* tmp) { // acquire exclusivity - while (m_producer_lock.exchange(true)) - { + while (m_producer_lock.exchange(true)) { std::this_thread::yield(); } // publish & swing last forward @@ -72,13 +65,11 @@ class intrusive_sutter_list } // returns nullptr on failure - bool try_pop(T& result) - { + bool try_pop(T& result) { // no critical section; only one consumer allowed node* first = m_first; node* next = m_first->next; - if (next) - { + if (next) { // queue is not empty result = next->value; // take it out of the node // swing first forward @@ -92,11 +83,9 @@ class intrusive_sutter_list } // polls the queue until an element was dequeued - T pop() - { + T pop() { T result; - while (!try_pop(result)) - { + while (!try_pop(result)) { std::this_thread::yield(); } return result; diff --git a/queue_performances/lockfree_list.hpp b/queue_performances/lockfree_list.hpp index 47e46c676d..6ca8ea0c1b 100644 --- a/queue_performances/lockfree_list.hpp +++ b/queue_performances/lockfree_list.hpp @@ -12,13 +12,11 @@ // T is any type template -class lockfree_list -{ +class lockfree_list { public: - struct node - { + struct node { node(T val = T()) : value(val), next(0) { } T value; std::atomic next; @@ -36,15 +34,12 @@ class lockfree_list public: - lockfree_list() - { + lockfree_list() { m_first = m_last = new node; } - ~lockfree_list() - { - while (m_first) - { + ~lockfree_list() { + while (m_first) { node* tmp = m_first; m_first = tmp->next; delete tmp; @@ -52,8 +47,7 @@ class lockfree_list } // takes ownership of what - void push(node* tmp) - { + void push(node* tmp) { // m_last becomes our predecessor node* predecessor = m_last.load(); // swing last forward @@ -63,13 +57,11 @@ class lockfree_list } // returns nullptr on failure - bool try_pop(T& result) - { + bool try_pop(T& result) { // no critical section; only one consumer allowed node* first = m_first; node* next = m_first->next; - if (next) - { + if (next) { // queue is not empty result = next->value; // take it out next->value = 0; // of the node @@ -85,11 +77,9 @@ class lockfree_list } // polls the queue until an element was dequeued - T pop() - { + T pop() { T result; - while (!try_pop(result)) - { + while (!try_pop(result)) { std::this_thread::yield(); } return result; diff --git a/queue_performances/main.cpp b/queue_performances/main.cpp index 4e83ad46fc..4522151fcf 100644 --- a/queue_performances/main.cpp +++ b/queue_performances/main.cpp @@ -30,31 +30,25 @@ namespace { } // namespace template -void producer(Queue& q, Allocator& a, size_t begin, size_t end) -{ - for ( ; begin != end; ++begin) - { +void producer(Queue& q, Allocator& a, size_t begin, size_t end) { + for ( ; begin != end; ++begin) { q.push(a(begin)); } } template -void consumer(Queue& q, Processor& p, size_t num_messages) -{ +void consumer(Queue& q, Processor& p, size_t num_messages) { // vector scales better (in memory) than bool[num_messages] // std::vector received(num_messages); // for (size_t i = 0; i < num_messages; ++i) received[i] = false; - for (size_t i = 0; i < num_messages; ++i) - { + for (size_t i = 0; i < num_messages; ++i) { size_t value; p(q.pop(), value); /* - if (value >= num_messages) - { + if (value >= num_messages) { throw std::runtime_error("value out of bounds"); } - else if (received[value]) - { + else if (received[value]) { std::ostringstream oss; oss << "ERROR: received element nr. " << value << " two times"; throw std::runtime_error(oss.str()); @@ -65,8 +59,7 @@ void consumer(Queue& q, Processor& p, size_t num_messages) // done } -void usage() -{ +void usage() { cout << "usage:" << endl << "queue_test [messages] [producer threads] " "[list impl.] {format string}" << endl @@ -91,21 +84,18 @@ void usage() template double run_test(size_t num_messages, size_t num_producers, - Allocator element_allocator, Processor element_processor) -{ + Allocator element_allocator, Processor element_processor) { size_t num_messages_per_producer = num_messages / num_producers; // measurement boost::timer t0; // locals Queue list; std::vector producer_threads(num_producers); - for (size_t i = 0; i < num_producers; ++i) - { + for (size_t i = 0; i < num_producers; ++i) { producer_threads[i] = new std::thread(producer, std::ref(list), std::ref(element_allocator), - i * num_messages_per_producer, - (i+1) * num_messages_per_producer); + i * num_messages_per_producer, (i+1) * num_messages_per_producer); } // run consumer in main thread consumer(list, element_processor, num_messages); @@ -114,45 +104,37 @@ double run_test(size_t num_messages, size_t num_producers, } -struct cs_element -{ +struct cs_element { size_t value; std::atomic next; cs_element(size_t val = 0) : value(val), next(0) { } }; -int main(int argc, char** argv) -{ - if (argc < 4 || argc > 5) - { +int main(int argc, char** argv) { + if (argc < 4 || argc > 5) { usage(); return -1; } size_t num_messages = boost::lexical_cast(argv[1]); size_t num_producers = boost::lexical_cast(argv[2]); - if (num_messages == 0 || num_producers == 0) - { + if (num_messages == 0 || num_producers == 0) { cerr << "invalid arguments" << endl; return -2; } - if ((num_messages % num_producers) != 0) - { + if ((num_messages % num_producers) != 0) { cerr << "(num_messages % num_producers) != 0" << endl; return -3; } std::string format_string; - if (argc == 5) - { + if (argc == 5) { format_string = argv[4]; } - else - { + else { format_string = "$MESSAGES $TIME"; } std::string list_name = argv[3]; double elapsed_time; - if (list_name == "sutter_list") - { + if (list_name == "sutter_list") { elapsed_time = run_test>( num_messages, num_producers, @@ -165,8 +147,7 @@ int main(int argc, char** argv) } ); } - else if (list_name == "intrusive_sutter_list") - { + else if (list_name == "intrusive_sutter_list") { typedef intrusive_sutter_list isl; elapsed_time = run_test( num_messages, @@ -180,8 +161,7 @@ int main(int argc, char** argv) ); } - else if (list_name == "lockfree_list") - { + else if (list_name == "lockfree_list") { typedef lockfree_list isl; elapsed_time = run_test( num_messages, @@ -194,8 +174,7 @@ int main(int argc, char** argv) } ); } - else if (list_name == "blocking_sutter_list") - { + else if (list_name == "blocking_sutter_list") { elapsed_time = run_test>( num_messages, num_producers, @@ -208,8 +187,7 @@ int main(int argc, char** argv) } ); } - else if (list_name == "cached_stack") - { + else if (list_name == "cached_stack") { elapsed_time = run_test>( num_messages, num_producers, @@ -222,8 +200,7 @@ int main(int argc, char** argv) } ); } - else if (list_name == "blocking_cached_stack") - { + else if (list_name == "blocking_cached_stack") { elapsed_time = run_test>( num_messages, num_producers, @@ -236,8 +213,7 @@ int main(int argc, char** argv) } ); } - else if (list_name == "blocking_cached_stack2") - { + else if (list_name == "blocking_cached_stack2") { elapsed_time = run_test>( num_messages, num_producers, @@ -250,26 +226,19 @@ int main(int argc, char** argv) } ); } - else - { + else { cerr << "unknown list" << endl; usage(); return -4; } // build output message - std::vector> replacements = { - { "MESSAGES", argv[1] }, - { "PRODUCERS", argv[2] }, - { "MSG_IN_MILLION", boost::lexical_cast(num_messages / 1000000.0) }, - { "TIME", boost::lexical_cast(elapsed_time) } + std::vector> replacements = { { "MESSAGES", argv[1] }, { "PRODUCERS", argv[2] }, { "MSG_IN_MILLION", boost::lexical_cast(num_messages / 1000000.0) }, { "TIME", boost::lexical_cast(elapsed_time) } }; - for (auto i = replacements.begin(); i != replacements.end(); ++i) - { + for (auto i = replacements.begin(); i != replacements.end(); ++i) { const std::string& needle = i->first; const std::string& value = i->second; std::string::size_type pos = format_string.find(needle); - if (pos != std::string::npos) - { + if (pos != std::string::npos) { format_string.replace(pos, pos + needle.size(), value); } } diff --git a/queue_performances/sutter_list.hpp b/queue_performances/sutter_list.hpp index bac022b743..868f18bf84 100644 --- a/queue_performances/sutter_list.hpp +++ b/queue_performances/sutter_list.hpp @@ -12,11 +12,9 @@ // T is any type template -class sutter_list -{ +class sutter_list { - struct node - { + struct node { node(T* val = 0) : value(val), next(0) { } T* value; std::atomic next; @@ -36,16 +34,13 @@ class sutter_list public: - sutter_list() - { + sutter_list() { m_first = m_last = new node; m_producer_lock = false; } - ~sutter_list() - { - while (m_first) - { + ~sutter_list() { + while (m_first) { node* tmp = m_first; m_first = tmp->next; delete tmp; @@ -53,12 +48,10 @@ class sutter_list } // takes ownership of what - void push(T* what) - { + void push(T* what) { node* tmp = new node(what); // acquire exclusivity - while (m_producer_lock.exchange(true)) - { + while (m_producer_lock.exchange(true)) { std::this_thread::yield(); } // publish & swing last forward @@ -69,13 +62,11 @@ class sutter_list } // returns nullptr on failure - T* try_pop() - { + T* try_pop() { // no critical section; only one consumer allowed node* first = m_first; node* next = m_first->next; - if (next) - { + if (next) { // queue is not empty T* result = next->value; // take it out next->value = 0; // of the node @@ -91,11 +82,9 @@ class sutter_list } // polls the queue until an element was dequeued - T* pop() - { + T* pop() { T* result = try_pop(); - while (!result) - { + while (!result) { std::this_thread::yield(); result = try_pop(); } diff --git a/src/abstract_event_based_actor.cpp b/src/abstract_event_based_actor.cpp deleted file mode 100644 index 390c1dc8a9..0000000000 --- a/src/abstract_event_based_actor.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/******************************************************************************\ - * ___ __ * - * /\_ \ __/\ \ * - * \//\ \ /\_\ \ \____ ___ _____ _____ __ * - * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * - * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * - * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * - * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * - * \ \_\ \ \_\ * - * \/_/ \/_/ * - * * - * Copyright (C) 2011, 2012 * - * Dominik Charousset * - * * - * This file is part of libcppa. * - * libcppa is free software: you can redistribute it and/or modify it under * - * the terms of the GNU Lesser General Public License as published by the * - * Free Software Foundation, either version 3 of the License * - * or (at your option) any later version. * - * * - * libcppa is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with libcppa. If not, see . * -\******************************************************************************/ - - -#include -#include "cppa/to_string.hpp" - -#include "cppa/self.hpp" -#include "cppa/detail/invokable.hpp" -#include "cppa/abstract_event_based_actor.hpp" - -namespace cppa { - -abstract_event_based_actor::abstract_event_based_actor() - : super(abstract_event_based_actor::blocked) - , m_mailbox_pos(m_mailbox.cache().end()) -{ - //m_mailbox_pos = m_mailbox.cache().end(); -} - -void abstract_event_based_actor::dequeue(behavior&) -{ - quit(exit_reason::unallowed_function_call); -} - -void abstract_event_based_actor::dequeue(partial_function&) -{ - quit(exit_reason::unallowed_function_call); -} - -bool abstract_event_based_actor::handle_message(queue_node& node) -{ - CPPA_REQUIRE(m_loop_stack.empty() == false); - auto& bhvr = *(m_loop_stack.back()); - if (bhvr.timeout().valid()) - { - switch (dq(node, bhvr.get_partial_function())) - { - case dq_timeout_occured: - { - bhvr.handle_timeout(); - // fall through - } - case dq_done: - { - // callback might have called become()/unbecome() - // request next timeout if needed - if (!m_loop_stack.empty()) - { - auto& next_bhvr = *(m_loop_stack.back()); - request_timeout(next_bhvr.timeout()); - } - return true; - } - default: return false; - } - } - else - { - return dq(node, bhvr.get_partial_function()) == dq_done; - } -} - -bool abstract_event_based_actor::invoke_from_cache() -{ - for (auto i = m_mailbox_pos; i != m_mailbox.cache().end(); ++i) - { - auto& ptr = *i; - CPPA_REQUIRE(ptr.get() != nullptr); - if (handle_message(*ptr)) - { - m_mailbox.cache().erase(i); - return true; - } - } - return false; -} - -void abstract_event_based_actor::resume(util::fiber*, resume_callback* callback) -{ - self.set(this); - auto& mbox_cache = m_mailbox.cache(); - try - { - for (;;) - { - if (m_loop_stack.empty()) - { - cleanup(exit_reason::normal); - m_state.store(abstract_scheduled_actor::done); - m_loop_stack.clear(); - on_exit(); - callback->exec_done(); - return; - } - while (m_mailbox_pos == mbox_cache.end()) - { - // try fetch more - if (m_mailbox.can_fetch_more() == false) - { - m_state.store(abstract_scheduled_actor::about_to_block); - CPPA_MEMORY_BARRIER(); - if (m_mailbox.can_fetch_more() == false) - { - switch (compare_exchange_state(abstract_scheduled_actor::about_to_block, - abstract_scheduled_actor::blocked)) - { - case abstract_scheduled_actor::ready: - { - // someone preempt us - break; - } - case abstract_scheduled_actor::blocked: - { - // done - return; - } - default: exit(7); // illegal state - }; - } - } - m_mailbox_pos = m_mailbox.try_fetch_more(); - } - m_mailbox_pos = (invoke_from_cache()) ? mbox_cache.begin() - : mbox_cache.end(); - } - } - catch (actor_exited& what) - { - cleanup(what.reason()); - } - catch (...) - { - cleanup(exit_reason::unhandled_exception); - } - m_state.store(abstract_scheduled_actor::done); - m_loop_stack.clear(); - on_exit(); - callback->exec_done(); -} - -void abstract_event_based_actor::on_exit() -{ -} - -} // namespace cppa diff --git a/src/abstract_scheduled_actor.cpp b/src/abstract_scheduled_actor.cpp index 9c400e592c..3c2bd01981 100644 --- a/src/abstract_scheduled_actor.cpp +++ b/src/abstract_scheduled_actor.cpp @@ -49,8 +49,7 @@ abstract_scheduled_actor::abstract_scheduled_actor(scheduler* sched) , m_state(ready) , m_scheduler(sched) , m_has_pending_timeout_request(false) - , m_active_timeout_id(0) -{ + , m_active_timeout_id(0) { CPPA_REQUIRE(sched != nullptr); } @@ -59,43 +58,32 @@ abstract_scheduled_actor::abstract_scheduled_actor(int state) , m_state(state) , m_scheduler(nullptr) , m_has_pending_timeout_request(false) - , m_active_timeout_id(0) -{ + , m_active_timeout_id(0) { } -abstract_scheduled_actor::resume_callback::~resume_callback() -{ +abstract_scheduled_actor::resume_callback::~resume_callback() { } -void abstract_scheduled_actor::quit(std::uint32_t reason) -{ +void abstract_scheduled_actor::quit(std::uint32_t reason) { cleanup(reason); throw actor_exited(reason); } -void abstract_scheduled_actor::enqueue_node(queue_node* node) -{ - if (m_mailbox._push_back(node)) - { - for (;;) - { +void abstract_scheduled_actor::enqueue_node(queue_node* node) { + if (m_mailbox._push_back(node)) { + for (;;) { int state = m_state.load(); - switch (state) - { - case blocked: - { - if (m_state.compare_exchange_weak(state, ready)) - { + switch (state) { + case blocked: { + if (m_state.compare_exchange_weak(state, ready)) { CPPA_REQUIRE(m_scheduler != nullptr); m_scheduler->enqueue(this); return; } break; } - case about_to_block: - { - if (m_state.compare_exchange_weak(state, ready)) - { + case about_to_block: { + if (m_state.compare_exchange_weak(state, ready)) { return; } break; @@ -106,26 +94,21 @@ void abstract_scheduled_actor::enqueue_node(queue_node* node) } } -void abstract_scheduled_actor::enqueue(actor* sender, any_tuple&& msg) -{ +void abstract_scheduled_actor::enqueue(actor* sender, any_tuple&& msg) { enqueue_node(fetch_node(sender, std::move(msg))); //enqueue_node(new queue_node(sender, std::move(msg))); } -void abstract_scheduled_actor::enqueue(actor* sender, const any_tuple& msg) -{ +void abstract_scheduled_actor::enqueue(actor* sender, const any_tuple& msg) { enqueue_node(fetch_node(sender, msg)); //enqueue_node(new queue_node(sender, msg)); } int abstract_scheduled_actor::compare_exchange_state(int expected, - int new_value) -{ + int new_value) { int e = expected; - do - { - if (m_state.compare_exchange_weak(e, new_value)) - { + do { + if (m_state.compare_exchange_weak(e, new_value)) { return new_value; } } @@ -133,36 +116,28 @@ int abstract_scheduled_actor::compare_exchange_state(int expected, return e; } -void abstract_scheduled_actor::request_timeout(const util::duration& d) -{ - if (d.valid()) - { +void abstract_scheduled_actor::request_timeout(const util::duration& d) { + if (d.valid()) { future_send(this, d, atom(":Timeout"), ++m_active_timeout_id); m_has_pending_timeout_request = true; } } -auto abstract_scheduled_actor::filter_msg(const any_tuple& msg) -> filter_result -{ +auto abstract_scheduled_actor::filter_msg(const any_tuple& msg) -> filter_result { if ( msg.size() == 2 && msg.type_at(0) == t_atom_ui32_types[0] - && msg.type_at(1) == t_atom_ui32_types[1]) - { + && msg.type_at(1) == t_atom_ui32_types[1]) { auto v0 = *reinterpret_cast(msg.at(0)); auto v1 = *reinterpret_cast(msg.at(1)); - if (v0 == atom(":Exit")) - { - if (m_trap_exit == false) - { - if (v1 != exit_reason::normal) - { + if (v0 == atom(":Exit")) { + if (m_trap_exit == false) { + if (v1 != exit_reason::normal) { quit(v1); } return normal_exit_signal; } } - else if (v0 == atom(":Timeout")) - { + else if (v0 == atom(":Timeout")) { return (v1 == m_active_timeout_id) ? timeout_message : expired_timeout_message; } @@ -171,20 +146,16 @@ auto abstract_scheduled_actor::filter_msg(const any_tuple& msg) -> filter_result } auto abstract_scheduled_actor::dq(queue_node& node, - partial_function& fun) -> dq_result -{ + partial_function& fun) -> dq_result { CPPA_REQUIRE(node.msg.cvals().get() != nullptr); if (node.marked) return dq_indeterminate; - switch (filter_msg(node.msg)) - { + switch (filter_msg(node.msg)) { case normal_exit_signal: - case expired_timeout_message: - { + case expired_timeout_message: { // skip message return dq_indeterminate; } - case timeout_message: - { + case timeout_message: { // m_active_timeout_id is already invalid m_has_pending_timeout_request = false; return dq_timeout_occured; @@ -197,13 +168,11 @@ auto abstract_scheduled_actor::dq(queue_node& node, //m_last_sender = node.sender; // make sure no timeout is handled incorrectly in a nested receive ++m_active_timeout_id; - // lifetime scope of qguard - { + // lifetime scope of qguard { // make sure nested receives do not process this node again queue_node_guard qguard{&node}; // try to invoke given function - if (fun(m_last_dequeued)) - { + if (fun(m_last_dequeued)) { // client erases node later (keep it marked until it's removed) qguard.release(); // this members are only valid during invocation @@ -223,46 +192,36 @@ auto abstract_scheduled_actor::dq(queue_node& node, // dummy -void scheduled_actor_dummy::resume(util::fiber*, resume_callback*) -{ +void scheduled_actor_dummy::resume(util::fiber*, resume_callback*) { } -void scheduled_actor_dummy::quit(std::uint32_t) -{ +void scheduled_actor_dummy::quit(std::uint32_t) { } -void scheduled_actor_dummy::dequeue(behavior&) -{ +void scheduled_actor_dummy::dequeue(behavior&) { } -void scheduled_actor_dummy::dequeue(partial_function&) -{ +void scheduled_actor_dummy::dequeue(partial_function&) { } -void scheduled_actor_dummy::link_to(intrusive_ptr&) -{ +void scheduled_actor_dummy::link_to(intrusive_ptr&) { } -void scheduled_actor_dummy::unlink_from(intrusive_ptr&) -{ +void scheduled_actor_dummy::unlink_from(intrusive_ptr&) { } -bool scheduled_actor_dummy::establish_backlink(intrusive_ptr&) -{ +bool scheduled_actor_dummy::establish_backlink(intrusive_ptr&) { return false; } -bool scheduled_actor_dummy::remove_backlink(intrusive_ptr&) -{ +bool scheduled_actor_dummy::remove_backlink(intrusive_ptr&) { return false; } -void scheduled_actor_dummy::detach(const attachable::token&) -{ +void scheduled_actor_dummy::detach(const attachable::token&) { } -bool scheduled_actor_dummy::attach(attachable*) -{ +bool scheduled_actor_dummy::attach(attachable*) { return false; } diff --git a/src/abstract_tuple.cpp b/src/abstract_tuple.cpp index dd4d0e4e90..20603aa4ef 100644 --- a/src/abstract_tuple.cpp +++ b/src/abstract_tuple.cpp @@ -32,8 +32,7 @@ namespace cppa { namespace detail { -bool abstract_tuple::equals(const abstract_tuple &other) const -{ +bool abstract_tuple::equals(const abstract_tuple &other) const { return this == &other || ( size() == other.size() && std::equal(begin(), end(), other.begin(), detail::full_eq)); @@ -41,22 +40,18 @@ bool abstract_tuple::equals(const abstract_tuple &other) const abstract_tuple::abstract_tuple(const abstract_tuple& other) : ref_counted() - , m_impl_type(other.m_impl_type) -{ + , m_impl_type(other.m_impl_type) { } -std::type_info const* abstract_tuple::type_token() const -{ +const std::type_info* abstract_tuple::type_token() const { return &typeid(void); } -void const* abstract_tuple::native_data() const -{ +const void* abstract_tuple::native_data() const { return nullptr; } -void* abstract_tuple::mutable_native_data() -{ +void* abstract_tuple::mutable_native_data() { return nullptr; } diff --git a/src/actor.cpp b/src/actor.cpp index 3bb9d55d52..c729cfa0c5 100644 --- a/src/actor.cpp +++ b/src/actor.cpp @@ -36,6 +36,7 @@ #include #include "cppa/actor.hpp" +#include "cppa/any_tuple.hpp" #include "cppa/util/shared_spinlock.hpp" #include "cppa/util/shared_lock_guard.hpp" @@ -45,8 +46,7 @@ namespace { -inline cppa::detail::actor_registry& registry() -{ +inline cppa::detail::actor_registry& registry() { return *(cppa::detail::singleton_manager::get_actor_registry()); } @@ -55,60 +55,40 @@ inline cppa::detail::actor_registry& registry() namespace cppa { actor::actor(std::uint32_t aid, const process_information_ptr& pptr) - : m_id(aid), m_is_proxy(true), m_parent_process(pptr) -{ - if (!pptr) - { + : m_id(aid), m_is_proxy(true), m_parent_process(pptr) { + if (!pptr) { throw std::logic_error("parent == nullptr"); } } +bool actor::chained_enqueue(actor* sender, any_tuple msg) { + enqueue(sender, std::move(msg)); + return false; +} + actor::actor(const process_information_ptr& pptr) - : m_id(registry().next_id()), m_is_proxy(false), m_parent_process(pptr) -{ - if (!pptr) - { + : m_id(registry().next_id()), m_is_proxy(false), m_parent_process(pptr) { + if (!pptr) { throw std::logic_error("parent == nullptr"); } } -actor::~actor() -{ -} - -void actor::join(group_ptr& what) -{ - if (!what) return; - attach(what->subscribe(this)); -} - -void actor::leave(const group_ptr& what) -{ - if (!what) return; - attachable::token group_token(typeid(group::unsubscriber), what.get()); - detach(group_token); -} - -void actor::link_to(intrusive_ptr&& other) -{ +void actor::link_to(intrusive_ptr&& other) { intrusive_ptr tmp(std::move(other)); link_to(tmp); } -void actor::unlink_from(intrusive_ptr&& other) -{ +void actor::unlink_from(intrusive_ptr&& other) { intrusive_ptr tmp(std::move(other)); unlink_from(tmp); } -bool actor::remove_backlink(intrusive_ptr&& to) -{ +bool actor::remove_backlink(intrusive_ptr&& to) { intrusive_ptr tmp(std::move(to)); return remove_backlink(tmp); } -bool actor::establish_backlink(intrusive_ptr&& to) -{ +bool actor::establish_backlink(intrusive_ptr&& to) { intrusive_ptr tmp(std::move(to)); return establish_backlink(tmp); } diff --git a/src/actor_count.cpp b/src/actor_count.cpp index 31523120d5..1d99117602 100644 --- a/src/actor_count.cpp +++ b/src/actor_count.cpp @@ -34,18 +34,15 @@ namespace cppa { namespace detail { -void inc_actor_count() -{ +void inc_actor_count() { singleton_manager::get_actor_registry()->inc_running(); } -void dec_actor_count() -{ +void dec_actor_count() { singleton_manager::get_actor_registry()->dec_running(); } -void actor_count_wait_until(size_t value) -{ +void actor_count_wait_until(size_t value) { singleton_manager::get_actor_registry()->await_running_count_equal(value); } diff --git a/src/actor_proxy.cpp b/src/actor_proxy.cpp index 2119b423b0..0ccd0d112f 100644 --- a/src/actor_proxy.cpp +++ b/src/actor_proxy.cpp @@ -34,104 +34,78 @@ #include "cppa/actor_proxy.hpp" #include "cppa/exit_reason.hpp" #include "cppa/detail/mailman.hpp" - -namespace { - -inline constexpr std::uint64_t to_int(cppa::atom_value value) -{ - return static_cast(value); -} - -} // namespace +#include "cppa/detail/network_manager.hpp" +#include "cppa/detail/singleton_manager.hpp" namespace cppa { actor_proxy::actor_proxy(std::uint32_t mid, const process_information_ptr& pptr) - : super(mid, pptr) -{ - attach(get_scheduler()->register_hidden_context()); + : super(mid, pptr) { + //attach(get_scheduler()->register_hidden_context()); } void actor_proxy::forward_message(const process_information_ptr& piptr, actor* sender, - const any_tuple& msg) -{ - auto mailman_msg = new detail::mailman_job(piptr, sender, this, msg); - detail::mailman_queue().push_back(mailman_msg); -} - -void actor_proxy::enqueue(actor* sender, any_tuple&& msg) -{ - any_tuple tmp(std::move(msg)); - enqueue(sender, tmp); + any_tuple&& msg) { + detail::addressed_message amsg{sender, this, std::move(msg)}; + detail::singleton_manager::get_network_manager() + ->send_to_mailman(make_any_tuple(piptr, std::move(amsg))); } -void actor_proxy::enqueue(actor* sender, const any_tuple& msg) -{ +void actor_proxy::enqueue(actor* sender, any_tuple msg) { if ( msg.size() == 2 && *(msg.type_at(0)) == typeid(atom_value) - && msg.get_as(0) == atom(":KillProxy") - && *(msg.type_at(1)) == typeid(std::uint32_t)) - { + && msg.get_as(0) == atom("KILL_PROXY") + && *(msg.type_at(1)) == typeid(std::uint32_t)) { cleanup(msg.get_as(1)); return; } - forward_message(parent_process_ptr(), sender, msg); + forward_message(parent_process_ptr(), sender, std::move(msg)); } -void actor_proxy::link_to(intrusive_ptr& other) -{ - if (link_to_impl(other)) - { +void actor_proxy::link_to(intrusive_ptr& other) { + if (link_to_impl(other)) { // causes remote actor to link to (proxy of) other forward_message(parent_process_ptr(), other.get(), - make_cow_tuple(atom(":Link"), other)); + make_cow_tuple(atom("LINK"), other)); } } -void actor_proxy::local_link_to(intrusive_ptr& other) -{ +void actor_proxy::local_link_to(intrusive_ptr& other) { link_to_impl(other); } -void actor_proxy::unlink_from(intrusive_ptr& other) -{ - if (unlink_from_impl(other)) - { +void actor_proxy::unlink_from(intrusive_ptr& other) { + if (unlink_from_impl(other)) { // causes remote actor to unlink from (proxy of) other forward_message(parent_process_ptr(), other.get(), - make_cow_tuple(atom(":Unlink"), other)); + make_cow_tuple(atom("UNLINK"), other)); } } -void actor_proxy::local_unlink_from(intrusive_ptr& other) -{ +void actor_proxy::local_unlink_from(intrusive_ptr& other) { unlink_from_impl(other); } -bool actor_proxy::establish_backlink(intrusive_ptr& other) -{ +bool actor_proxy::establish_backlink(intrusive_ptr& other) { bool result = super::establish_backlink(other); - if (result) - { + if (result) { // causes remote actor to unlink from (proxy of) other forward_message(parent_process_ptr(), other.get(), - make_cow_tuple(atom(":Link"), other)); + make_cow_tuple(atom("LINK"), other)); } return result; } -bool actor_proxy::remove_backlink(intrusive_ptr& other) -{ +bool actor_proxy::remove_backlink(intrusive_ptr& other) { bool result = super::remove_backlink(other); - if (result) - { + if (result) { forward_message(parent_process_ptr(), nullptr, - make_cow_tuple(atom(":Unlink"), actor_ptr(this))); + make_cow_tuple(atom("UNLINK"), actor_ptr(this))); } return result; } diff --git a/src/actor_proxy_cache.cpp b/src/actor_proxy_cache.cpp index a568361e61..8f6951b7af 100644 --- a/src/actor_proxy_cache.cpp +++ b/src/actor_proxy_cache.cpp @@ -28,80 +28,100 @@ \******************************************************************************/ +#include +#include + #include "cppa/atom.hpp" #include "cppa/any_tuple.hpp" -#include "cppa/detail/thread.hpp" + +#include "cppa/util/shared_lock_guard.hpp" +#include "cppa/util/upgrade_lock_guard.hpp" + +#include "cppa/detail/network_manager.hpp" #include "cppa/detail/actor_proxy_cache.hpp" +#include "cppa/detail/singleton_manager.hpp" // thread_specific_ptr -#include +//#include namespace { -boost::thread_specific_ptr s_proxy_cache; +//boost::thread_specific_ptr s_proxy_cache; + +cppa::detail::actor_proxy_cache s_proxy_cache; } // namespace namespace cppa { namespace detail { -actor_proxy_cache& get_actor_proxy_cache() -{ - if (s_proxy_cache.get() == nullptr) - { +actor_proxy_cache& get_actor_proxy_cache() { + /* + if (s_proxy_cache.get() == nullptr) { s_proxy_cache.reset(new actor_proxy_cache); } return *s_proxy_cache; + */ + return s_proxy_cache; } -process_information_ptr -actor_proxy_cache::get_pinfo(const actor_proxy_cache::key_tuple& key) -{ - auto i = m_pinfos.find(key); - if (i != m_pinfos.end()) - { - return i->second; - } - process_information_ptr tmp(new process_information(std::get<1>(key), - std::get<2>(key))); - m_pinfos.insert(std::make_pair(key, tmp)); - return tmp; +actor_proxy_ptr actor_proxy_cache::get(actor_id aid, + std::uint32_t process_id, + const process_information::node_id_type& node_id) { + key_tuple k{node_id, process_id, aid}; + return get_impl(k); } -actor_proxy_ptr actor_proxy_cache::get(const key_tuple& key) -{ - auto i = m_proxies.find(key); - if (i != m_proxies.end()) - { - return i->second; +actor_proxy_ptr actor_proxy_cache::get_impl(const key_tuple& key) { + { // lifetime scope of shared guard + util::shared_lock_guard guard{m_lock}; + auto i = m_entries.find(key); + if (i != m_entries.end()) { + return i->second; + } + } + actor_proxy_ptr result{new actor_proxy(std::get<2>(key), new process_information(std::get<1>(key), std::get<0>(key)))}; + { // lifetime scope of exclusive guard + std::lock_guard guard{m_lock}; + auto i = m_entries.find(key); + if (i != m_entries.end()) { + return i->second; + } + m_entries.insert(std::make_pair(key, result)); } - // get_pinfo(key) also inserts to m_pinfos - actor_proxy_ptr result(new actor_proxy(std::get<0>(key), get_pinfo(key))); - m_proxies.insert(std::make_pair(key, result)); - if (m_new_cb) m_new_cb(result); - // insert to m_proxies - //result->enqueue(message(result, nullptr, atom(":Monitor"))); + result->attach_functor([result](std::uint32_t) { + get_actor_proxy_cache().erase(result); + }); + result->enqueue(nullptr, make_any_tuple(atom("MONITOR"))); return result; } -void actor_proxy_cache::add(actor_proxy_ptr& pptr) -{ +bool actor_proxy_cache::erase(const actor_proxy_ptr& pptr) { auto pinfo = pptr->parent_process_ptr(); - key_tuple key(pptr->id(), pinfo->process_id(), pinfo->node_id()); - m_pinfos.insert(std::make_pair(key, pptr->parent_process_ptr())); - m_proxies.insert(std::make_pair(key, pptr)); - if (m_new_cb) m_new_cb(pptr); + key_tuple key(pinfo->node_id(), pinfo->process_id(), pptr->id()); { + std::lock_guard guard{m_lock}; + return m_entries.erase(key) > 0; + } + return false; } -void actor_proxy_cache::erase(const actor_proxy_ptr& pptr) -{ - auto pinfo = pptr->parent_process_ptr(); - key_tuple key(pptr->id(), pinfo->process_id(), pinfo->node_id()); - m_proxies.erase(key); +bool actor_proxy_cache::key_tuple_less::operator()(const key_tuple& lhs, + const key_tuple& rhs) const { + int cmp_res = strncmp(reinterpret_cast(std::get<0>(lhs).data()), + reinterpret_cast(std::get<0>(rhs).data()), + process_information::node_id_size); + if (cmp_res < 0) { + return true; + } + else if (cmp_res == 0) { + if (std::get<1>(lhs) < std::get<1>(rhs)) { + return true; + } + else if (std::get<1>(lhs) == std::get<1>(rhs)) { + return std::get<2>(lhs) < std::get<2>(rhs); + } + } + return false; } -size_t actor_proxy_cache::size() const -{ - return m_proxies.size(); -} } } // namespace cppa::detail diff --git a/src/actor_registry.cpp b/src/actor_registry.cpp index d62a42f83c..8f2457da30 100644 --- a/src/actor_registry.cpp +++ b/src/actor_registry.cpp @@ -39,7 +39,7 @@ namespace { -typedef cppa::detail::lock_guard exclusive_guard; +typedef std::lock_guard exclusive_guard; typedef cppa::util::shared_lock_guard shared_guard; typedef cppa::util::upgrade_lock_guard upgrade_guard; @@ -47,50 +47,39 @@ typedef cppa::util::upgrade_lock_guard upgrade_guar namespace cppa { namespace detail { -actor_registry::actor_registry() : m_running(0), m_ids(1) -{ +actor_registry::actor_registry() : m_running(0), m_ids(1) { } -actor_ptr actor_registry::get(actor_id key) const -{ +actor_ptr actor_registry::get(actor_id key) const { shared_guard guard(m_instances_mtx); auto i = m_instances.find(key); - if (i != m_instances.end()) - { + if (i != m_instances.end()) { return i->second; } return nullptr; } -void actor_registry::put(actor_id key, const actor_ptr& value) -{ +void actor_registry::put(actor_id key, const actor_ptr& value) { bool add_attachable = false; - if (value != nullptr) - { + if (value != nullptr) { shared_guard guard(m_instances_mtx); auto i = m_instances.find(key); - if (i == m_instances.end()) - { + if (i == m_instances.end()) { upgrade_guard uguard(guard); m_instances.insert(std::make_pair(key, value)); add_attachable = true; } } - if (add_attachable) - { - struct eraser : attachable - { + if (add_attachable) { + struct eraser : attachable { actor_id m_id; actor_registry* m_singleton; - eraser(actor_id id, actor_registry* s) : m_id(id), m_singleton(s) - { + eraser(actor_id id, actor_registry* s) : m_id(id), m_singleton(s) { } - void actor_exited(std::uint32_t) - { + void actor_exited(std::uint32_t) { m_singleton->erase(m_id); } - bool matches(const token&) - { + bool matches(const token&) { return false; } }; @@ -98,47 +87,43 @@ void actor_registry::put(actor_id key, const actor_ptr& value) } } -void actor_registry::erase(actor_id key) -{ +void actor_registry::erase(actor_id key) { exclusive_guard guard(m_instances_mtx); - m_instances.insert(std::pair(key, nullptr)); + auto i = std::find_if(m_instances.begin(), m_instances.end(), + [=](const std::pair& p) { + return p.first == key; + }); + if (i != m_instances.end()) + m_instances.erase(i); } -std::uint32_t actor_registry::next_id() -{ +std::uint32_t actor_registry::next_id() { return m_ids.fetch_add(1); } -void actor_registry::inc_running() -{ +void actor_registry::inc_running() { ++m_running; } -size_t actor_registry::running() const -{ +size_t actor_registry::running() const { return m_running.load(); } -void actor_registry::dec_running() -{ +void actor_registry::dec_running() { size_t new_val = --m_running; /* - if (new_val == std::numeric_limits::max()) - { + if (new_val == std::numeric_limits::max()) { throw std::underflow_error("actor_count::dec()"); } - else*/ if (new_val <= 1) - { - unique_lock guard(m_running_mtx); + else*/ if (new_val <= 1) { + std::unique_lock guard(m_running_mtx); m_running_cv.notify_all(); } } -void actor_registry::await_running_count_equal(size_t expected) -{ - unique_lock guard(m_running_mtx); - while (m_running.load() != expected) - { +void actor_registry::await_running_count_equal(size_t expected) { + std::unique_lock guard(m_running_mtx); + while (m_running.load() != expected) { m_running_cv.wait(guard); } } diff --git a/src/addressed_message.cpp b/src/addressed_message.cpp index 7b6ad22f3e..2708573d3a 100644 --- a/src/addressed_message.cpp +++ b/src/addressed_message.cpp @@ -33,22 +33,11 @@ namespace cppa { namespace detail { -addressed_message::addressed_message(const actor_ptr& from, - const channel_ptr& to, - const any_tuple& ut) - : m_sender(from), m_receiver(to), m_content(ut) -{ +addressed_message::addressed_message(actor_ptr from, channel_ptr to, any_tuple ut) + : m_sender(std::move(from)), m_receiver(std::move(to)), m_content(std::move(ut)) { } -addressed_message::addressed_message(const actor_ptr& from, - const channel_ptr& to, - any_tuple&& ut) - : m_sender(from), m_receiver(to), m_content(std::move(ut)) -{ -} - -bool operator==(const addressed_message& lhs, const addressed_message& rhs) -{ +bool operator==(const addressed_message& lhs, const addressed_message& rhs) { return lhs.sender() == rhs.sender() && lhs.receiver() == rhs.receiver() && lhs.content() == rhs.content(); diff --git a/src/any_tuple.cpp b/src/any_tuple.cpp index bf58983f4e..43ae0f9d2f 100644 --- a/src/any_tuple.cpp +++ b/src/any_tuple.cpp @@ -32,67 +32,50 @@ #include "cppa/detail/empty_tuple.hpp" #include "cppa/detail/singleton_manager.hpp" -namespace { +namespace cppa { -inline cppa::detail::empty_tuple* s_empty_tuple() -{ - return cppa::detail::singleton_manager::get_empty_tuple(); +namespace { +inline detail::empty_tuple* s_empty_tuple() { + return detail::singleton_manager::get_empty_tuple(); } - } // namespace -namespace cppa { +any_tuple::any_tuple() : m_vals(s_empty_tuple()) { } -any_tuple::any_tuple() : m_vals(s_empty_tuple()) -{ -} - -any_tuple::any_tuple(detail::abstract_tuple* ptr) : m_vals(ptr) -{ -} +any_tuple::any_tuple(detail::abstract_tuple* ptr) : m_vals(ptr) { } -any_tuple::any_tuple(any_tuple&& other) : m_vals(s_empty_tuple()) -{ +any_tuple::any_tuple(any_tuple&& other) : m_vals(s_empty_tuple()) { m_vals.swap(other.m_vals); } -any_tuple::any_tuple(const cow_ptr& vals) : m_vals(vals) -{ -} +any_tuple::any_tuple(const value_ptr& vals) : m_vals(vals) { } -any_tuple& any_tuple::operator=(any_tuple&& other) -{ +any_tuple& any_tuple::operator=(any_tuple&& other) { m_vals.swap(other.m_vals); return *this; } -void any_tuple::reset() -{ +void any_tuple::reset() { m_vals.reset(s_empty_tuple()); } -size_t any_tuple::size() const -{ +size_t any_tuple::size() const { return m_vals->size(); } -void* any_tuple::mutable_at(size_t p) -{ +void* any_tuple::mutable_at(size_t p) { return m_vals->mutable_at(p); } -const void* any_tuple::at(size_t p) const -{ +const void* any_tuple::at(size_t p) const { return m_vals->at(p); } -const uniform_type_info* any_tuple::type_at(size_t p) const -{ +const uniform_type_info* any_tuple::type_at(size_t p) const { return m_vals->type_at(p); } -bool any_tuple::equals(const any_tuple& other) const -{ +bool any_tuple::equals(const any_tuple& other) const { return m_vals->equals(*other.vals()); } diff --git a/src/atom.cpp b/src/atom.cpp index 319cf52e6d..18c49b2eb1 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -32,8 +32,7 @@ namespace cppa { -std::string to_string(const atom_value& what) -{ +std::string to_string(const atom_value& what) { auto x = static_cast(what); std::string result; result.reserve(11); @@ -41,14 +40,11 @@ std::string to_string(const atom_value& what) // first four bits set? bool read_chars = ((x & 0xF000000000000000) >> 60) == 0xF; std::uint64_t mask = 0x0FC0000000000000; - for (int bitshift = 54; bitshift >= 0; bitshift -= 6, mask >>= 6) - { - if (read_chars) - { + for (int bitshift = 54; bitshift >= 0; bitshift -= 6, mask >>= 6) { + if (read_chars) { result += detail::decoding_table[(x & mask) >> bitshift]; } - else if (((x & mask) >> bitshift) == 0xF) - { + else if (((x & mask) >> bitshift) == 0xF) { read_chars = true; } } diff --git a/src/attachable.cpp b/src/attachable.cpp index 1c67f15f05..89ec4f3231 100644 --- a/src/attachable.cpp +++ b/src/attachable.cpp @@ -32,17 +32,7 @@ namespace cppa { -attachable::~attachable() -{ +attachable::~attachable() { } -//void attachable::detach(std::uint32_t) -//{ -//} - -//bool attachable::matches(const attachable::token&) -//{ -// return false; -//} - } // namespace cppa::detail diff --git a/src/stacked_event_based_actor.cpp b/src/behavior_stack.cpp similarity index 70% rename from src/stacked_event_based_actor.cpp rename to src/behavior_stack.cpp index 0bb1ec12e9..fc53348cec 100644 --- a/src/stacked_event_based_actor.cpp +++ b/src/behavior_stack.cpp @@ -28,31 +28,42 @@ \******************************************************************************/ -#include "cppa/stacked_event_based_actor.hpp" +#include "cppa/local_actor.hpp" +#include "cppa/detail/behavior_stack.hpp" -namespace cppa { +namespace cppa { namespace detail { -void stacked_event_based_actor::become_void() -{ - m_loop_stack.clear(); +// executes the behavior stack +void behavior_stack::exec() { + while (!empty()) { + self->dequeue(back()); + cleanup(); + } +} + +void behavior_stack::pop_back() { + if (m_elements.empty() == false) { + m_erased_elements.emplace_back(std::move(m_elements.back())); + m_elements.pop_back(); + } +} + +void behavior_stack::push_back(behavior* what, bool has_ownership) { + value_type new_element{what}; + if (!has_ownership) new_element.get_deleter().disable(); + m_elements.push_back(std::move(new_element)); } -void stacked_event_based_actor::unbecome() -{ - if (!m_loop_stack.empty()) - { - m_loop_stack.pop_back(); +void behavior_stack::clear() { + if (m_elements.empty() == false) { + std::move(m_elements.begin(), m_elements.end(), + std::back_inserter(m_erased_elements)); + m_elements.clear(); } } -void stacked_event_based_actor::do_become(behavior* bhvr, - bool has_ownership) -{ - reset_timeout(); - request_timeout(bhvr->timeout()); - stack_element se{bhvr}; - if (!has_ownership) se.get_deleter().disable(); - m_loop_stack.push_back(std::move(se)); +void behavior_stack::cleanup() { + m_erased_elements.clear(); } -} // namespace cppa +} } // namespace cppa::detail diff --git a/src/binary_deserializer.cpp b/src/binary_deserializer.cpp index 8306c16ad4..6f70e7aa3d 100644 --- a/src/binary_deserializer.cpp +++ b/src/binary_deserializer.cpp @@ -45,10 +45,8 @@ namespace { typedef const char* iterator; -inline void range_check(iterator begin, iterator end, size_t read_size) -{ - if ((begin + read_size) > end) - { +inline void range_check(iterator begin, iterator end, size_t read_size) { + if ((begin + read_size) > end) { throw std::out_of_range("binary_deserializer::read()"); } } @@ -56,22 +54,19 @@ inline void range_check(iterator begin, iterator end, size_t read_size) // @returns the next iterator position template iterator read(iterator, iterator, T&, - typename enable_if::value>::type* = 0) -{ + typename enable_if::value>::type* = 0) { throw std::logic_error("read floating point not implemented yet"); } template iterator read(iterator begin, iterator end, T& storage, - typename enable_if::value>::type* = 0) -{ + typename enable_if::value>::type* = 0) { range_check(begin, end, sizeof(T)); memcpy(&storage, begin, sizeof(T)); return begin + sizeof(T); } -iterator read(iterator begin, iterator end, std::string& storage) -{ +iterator read(iterator begin, iterator end, std::string& storage) { std::uint32_t str_size; begin = read(begin, end, str_size); range_check(begin, end, str_size); @@ -83,13 +78,11 @@ iterator read(iterator begin, iterator end, std::string& storage) } template -iterator read_unicode_string(iterator begin, iterator end, StringType& str) -{ +iterator read_unicode_string(iterator begin, iterator end, StringType& str) { std::uint32_t str_size; begin = read(begin, end, str_size); str.reserve(str_size); - for (size_t i = 0; i < str_size; ++i) - { + for (size_t i = 0; i < str_size; ++i) { CharType c; begin = read(begin, end, c); str += static_cast(c); @@ -97,22 +90,19 @@ iterator read_unicode_string(iterator begin, iterator end, StringType& str) return begin; } -iterator read(iterator begin, iterator end, std::u16string& storage) -{ +iterator read(iterator begin, iterator end, std::u16string& storage) { // char16_t is guaranteed to has *at least* 16 bytes, // but not to have *exactly* 16 bytes; thus use uint16_t return read_unicode_string(begin, end, storage); } -iterator read(iterator begin, iterator end, std::u32string& storage) -{ +iterator read(iterator begin, iterator end, std::u32string& storage) { // char32_t is guaranteed to has *at least* 32 bytes, // but not to have *exactly* 32 bytes; thus use uint32_t return read_unicode_string(begin, end, storage); } -struct pt_reader -{ +struct pt_reader { iterator begin; iterator end; @@ -120,8 +110,7 @@ struct pt_reader pt_reader(iterator bbegin, iterator bend) : begin(bbegin), end(bend) { } template - inline void operator()(T& value) - { + inline void operator()(T& value) { begin = read(begin, end, value); } @@ -130,39 +119,32 @@ struct pt_reader } // namespace binary_deserializer::binary_deserializer(const char* buf, size_t buf_size) - : pos(buf), end(buf + buf_size) -{ + : pos(buf), end(buf + buf_size) { } binary_deserializer::binary_deserializer(const char* bbegin, const char* bend) - : pos(bbegin), end(bend) -{ + : pos(bbegin), end(bend) { } -std::string binary_deserializer::seek_object() -{ +std::string binary_deserializer::seek_object() { std::string result; pos = read(pos, end, result); return result; } -std::string binary_deserializer::peek_object() -{ +std::string binary_deserializer::peek_object() { std::string result; read(pos, end, result); return result; } -void binary_deserializer::begin_object(const std::string&) -{ +void binary_deserializer::begin_object(const std::string&) { } -void binary_deserializer::end_object() -{ +void binary_deserializer::end_object() { } -size_t binary_deserializer::begin_sequence() -{ +size_t binary_deserializer::begin_sequence() { static_assert(sizeof(size_t) >= sizeof(std::uint32_t), "sizeof(size_t) < sizeof(uint32_t)"); std::uint32_t result; @@ -170,12 +152,10 @@ size_t binary_deserializer::begin_sequence() return static_cast(result); } -void binary_deserializer::end_sequence() -{ +void binary_deserializer::end_sequence() { } -primitive_variant binary_deserializer::read_value(primitive_type ptype) -{ +primitive_variant binary_deserializer::read_value(primitive_type ptype) { primitive_variant val(ptype); pt_reader ptr(pos, end); val.apply(ptr); @@ -185,10 +165,8 @@ primitive_variant binary_deserializer::read_value(primitive_type ptype) void binary_deserializer::read_tuple(size_t size, const primitive_type* ptypes, - primitive_variant* storage) -{ - for (auto end = ptypes + size; ptypes != end; ++ptypes) - { + primitive_variant* storage) { + for (auto end = ptypes + size; ptypes != end; ++ptypes) { *storage = std::move(read_value(*ptypes)); ++storage; } diff --git a/src/binary_serializer.cpp b/src/binary_serializer.cpp index 6ae736aa4a..c3b58e2850 100644 --- a/src/binary_serializer.cpp +++ b/src/binary_serializer.cpp @@ -41,6 +41,7 @@ using std::enable_if; namespace { constexpr size_t chunk_size = 512; +constexpr size_t ui32_size = sizeof(std::uint32_t); } // namespace @@ -48,8 +49,7 @@ namespace cppa { namespace detail { -class binary_writer -{ +class binary_writer { binary_serializer* m_serializer; @@ -58,15 +58,13 @@ class binary_writer binary_writer(binary_serializer* s) : m_serializer(s) { } template - inline static void write_int(binary_serializer* bs, const T& value) - { + inline static void write_int(binary_serializer* bs, const T& value) { memcpy(bs->m_wr_pos, &value, sizeof(T)); bs->m_wr_pos += sizeof(T); } inline static void write_string(binary_serializer* bs, - const std::string& str) - { + const std::string& str) { write_int(bs, static_cast(str.size())); memcpy(bs->m_wr_pos, str.c_str(), str.size()); bs->m_wr_pos += str.size(); @@ -74,43 +72,36 @@ class binary_writer template void operator()(const T& value, - typename enable_if::value>::type* = 0) - { + typename enable_if::value>::type* = 0) { m_serializer->acquire(sizeof(T)); write_int(m_serializer, value); } template void operator()(const T&, - typename enable_if::value>::type* = 0) - { + typename enable_if::value>::type* = 0) { throw std::logic_error("binary_serializer::write_floating_point " "not implemented yet"); } - void operator()(const std::string& str) - { + void operator()(const std::string& str) { m_serializer->acquire(sizeof(std::uint32_t) + str.size()); write_string(m_serializer, str); } - void operator()(const std::u16string& str) - { + void operator()(const std::u16string& str) { m_serializer->acquire(sizeof(std::uint32_t) + str.size()); write_int(m_serializer, static_cast(str.size())); - for (char16_t c : str) - { + for (char16_t c : str) { // force writer to use exactly 16 bit write_int(m_serializer, static_cast(c)); } } - void operator()(const std::u32string& str) - { + void operator()(const std::u32string& str) { m_serializer->acquire(sizeof(std::uint32_t) + str.size()); write_int(m_serializer, static_cast(str.size())); - for (char32_t c : str) - { + for (char32_t c : str) { // force writer to use exactly 32 bit write_int(m_serializer, static_cast(c)); } @@ -120,43 +111,35 @@ class binary_writer } // namespace detail -binary_serializer::binary_serializer() : m_begin(0), m_end(0), m_wr_pos(0) -{ +binary_serializer::binary_serializer() : m_begin(0), m_end(0), m_wr_pos(0) { } -binary_serializer::~binary_serializer() -{ +binary_serializer::~binary_serializer() { delete[] m_begin; } -void binary_serializer::acquire(size_t num_bytes) -{ - if (!m_begin) - { +void binary_serializer::acquire(size_t num_bytes) { + if (!m_begin) { + num_bytes += ui32_size; size_t new_size = chunk_size; - while (new_size <= num_bytes) - { + while (new_size <= num_bytes) { new_size += chunk_size; } m_begin = new char[new_size]; m_end = m_begin + new_size; - m_wr_pos = m_begin; + m_wr_pos = m_begin + ui32_size; } - else - { + else { char* next_wr_pos = m_wr_pos + num_bytes; - if (next_wr_pos > m_end) - { + if (next_wr_pos > m_end) { size_t new_size = static_cast(m_end - m_begin) + chunk_size; - while ((m_begin + new_size) < next_wr_pos) - { + while ((m_begin + new_size) < next_wr_pos) { new_size += chunk_size; } char* begin = new char[new_size]; auto used_bytes = static_cast(m_wr_pos - m_begin); - if (used_bytes > 0) - { + if (used_bytes > 0) { memcpy(m_begin, begin, used_bytes); } delete[] m_begin; @@ -167,63 +150,55 @@ void binary_serializer::acquire(size_t num_bytes) } } -void binary_serializer::begin_object(const std::string& tname) -{ +void binary_serializer::begin_object(const std::string& tname) { acquire(sizeof(std::uint32_t) + tname.size()); detail::binary_writer::write_string(this, tname); } -void binary_serializer::end_object() -{ +void binary_serializer::end_object() { } -void binary_serializer::begin_sequence(size_t list_size) -{ +void binary_serializer::begin_sequence(size_t list_size) { acquire(sizeof(std::uint32_t)); detail::binary_writer::write_int(this, static_cast(list_size)); } -void binary_serializer::end_sequence() -{ +void binary_serializer::end_sequence() { } -void binary_serializer::write_value(const primitive_variant& value) -{ +void binary_serializer::write_value(const primitive_variant& value) { value.apply(detail::binary_writer(this)); } void binary_serializer::write_tuple(size_t size, - const primitive_variant* values) -{ + const primitive_variant* values) { const primitive_variant* end = values + size; - for ( ; values != end; ++values) - { + for ( ; values != end; ++values) { write_value(*values); } } -std::pair binary_serializer::take_buffer() -{ - char* begin = m_begin; - char* end = m_end; - m_begin = m_end = m_wr_pos = nullptr; - return { static_cast(end - begin), begin }; +size_t binary_serializer::sendable_size() const { + return static_cast(m_wr_pos - m_begin); } -size_t binary_serializer::size() const -{ - return static_cast(m_wr_pos - m_begin); +size_t binary_serializer::size() const { + return sendable_size() - ui32_size; +} + +const char* binary_serializer::data() const { + return m_begin + ui32_size; } -const char* binary_serializer::data() const -{ +const char* binary_serializer::sendable_data() { + auto s = static_cast(size()); + memcpy(m_begin, &s, ui32_size); return m_begin; } -void binary_serializer::reset() -{ - m_wr_pos = m_begin; +void binary_serializer::reset() { + m_wr_pos = m_begin + ui32_size; } } // namespace cppa diff --git a/src/context_switching_actor.cpp b/src/context_switching_actor.cpp new file mode 100644 index 0000000000..48f91125f8 --- /dev/null +++ b/src/context_switching_actor.cpp @@ -0,0 +1,131 @@ +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + + +#include "cppa/context_switching_actor.hpp" +#ifndef CPPA_DISABLE_CONTEXT_SWITCHING + +#include + +#include "cppa/cppa.hpp" +#include "cppa/self.hpp" + +namespace cppa { + +context_switching_actor::context_switching_actor() +: m_fiber(&context_switching_actor::trampoline, this) { +} + +context_switching_actor::context_switching_actor(std::function fun) +: super(std::move(fun)), m_fiber(&context_switching_actor::trampoline, this) { +} + +void context_switching_actor::trampoline(void* this_ptr) { + auto _this = reinterpret_cast(this_ptr); + bool cleanup_called = false; + try { _this->run(); } + catch (actor_exited&) { + // cleanup already called by scheduled_actor::quit + cleanup_called = true; + } + catch (...) { + _this->cleanup(exit_reason::unhandled_exception); + cleanup_called = true; + } + if (!cleanup_called) _this->cleanup(exit_reason::normal); + _this->on_exit(); + std::atomic_thread_fence(std::memory_order_seq_cst); + detail::yield(detail::yield_state::done); +} + +detail::recursive_queue_node* context_switching_actor::receive_node() { + detail::recursive_queue_node* e = m_mailbox.try_pop(); + while (e == nullptr) { + if (m_mailbox.can_fetch_more() == false) { + m_state.store(abstract_scheduled_actor::about_to_block); + // make sure mailbox is empty + if (m_mailbox.can_fetch_more()) { + // someone preempt us => continue + m_state.store(abstract_scheduled_actor::ready); + } + else { + // wait until actor becomes rescheduled + detail::yield(detail::yield_state::blocked); + } + } + e = m_mailbox.try_pop(); + } + return e; +} + +scheduled_actor_type context_switching_actor::impl_type() { + return context_switching_impl; +} + +resume_result context_switching_actor::resume(util::fiber* from) { + using namespace detail; + scoped_self_setter sss{this}; + for (;;) { + switch (call(&m_fiber, from)) { + case yield_state::done: { + return resume_result::actor_done; + } + case yield_state::ready: { + break; + } + case yield_state::blocked: { + switch (compare_exchange_state(abstract_scheduled_actor::about_to_block, + abstract_scheduled_actor::blocked)) { + case abstract_scheduled_actor::ready: { + break; + } + case abstract_scheduled_actor::blocked: { + // wait until someone re-schedules that actor + return resume_result::actor_blocked; + } + default: { + CPPA_CRITICAL("illegal yield result"); + } + } + break; + } + default: { + CPPA_CRITICAL("illegal state"); + } + } + } +} + +} // namespace cppa + +#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING + +namespace { int keep_compiler_happy() { return 42; } } + +#endif // ifdef CPPA_DISABLE_CONTEXT_SWITCHING diff --git a/src/converted_thread_context.cpp b/src/converted_thread_context.cpp deleted file mode 100644 index adb6c55b1b..0000000000 --- a/src/converted_thread_context.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/******************************************************************************\ - * ___ __ * - * /\_ \ __/\ \ * - * \//\ \ /\_\ \ \____ ___ _____ _____ __ * - * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * - * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * - * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * - * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * - * \ \_\ \ \_\ * - * \/_/ \/_/ * - * * - * Copyright (C) 2011, 2012 * - * Dominik Charousset * - * * - * This file is part of libcppa. * - * libcppa is free software: you can redistribute it and/or modify it under * - * the terms of the GNU Lesser General Public License as published by the * - * Free Software Foundation, either version 3 of the License * - * or (at your option) any later version. * - * * - * libcppa is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with libcppa. If not, see . * -\******************************************************************************/ - - -#include -#include - -#include "cppa/self.hpp" -#include "cppa/exception.hpp" -#include "cppa/detail/matches.hpp" -#include "cppa/detail/invokable.hpp" -#include "cppa/detail/converted_thread_context.hpp" - -namespace cppa { namespace detail { - -converted_thread_context::converted_thread_context() - : m_exit_msg_pattern(atom(":Exit")) -{ -} - -void converted_thread_context::quit(std::uint32_t reason) -{ - super::cleanup(reason); - // actor_exited should not be catched, but if anyone does, - // self must point to a newly created instance - //self.set(nullptr); - throw actor_exited(reason); -} - -void converted_thread_context::cleanup(std::uint32_t reason) -{ - super::cleanup(reason); -} - -void converted_thread_context::enqueue(actor* sender, any_tuple&& msg) -{ - m_mailbox.push_back(fetch_node(sender, std::move(msg))); -} - -void converted_thread_context::enqueue(actor* sender, const any_tuple& msg) -{ - m_mailbox.push_back(fetch_node(sender, msg)); -} - -void converted_thread_context::dequeue(partial_function& rules) /*override*/ -{ - auto rm_fun = [&](queue_node_ptr& node) { return dq(*node, rules); }; - auto& mbox_cache = m_mailbox.cache(); - auto mbox_end = mbox_cache.end(); - auto iter = std::find_if(mbox_cache.begin(), mbox_end, rm_fun); - while (iter == mbox_end) - { - iter = std::find_if(m_mailbox.fetch_more(), mbox_end, rm_fun); - } - mbox_cache.erase(iter); -} - -void converted_thread_context::dequeue(behavior& rules) /*override*/ -{ - if (rules.timeout().valid()) - { - auto timeout = now(); - timeout += rules.timeout(); - auto rm_fun = [&](queue_node_ptr& node) - { - return dq(*node, rules.get_partial_function()); - }; - auto& mbox_cache = m_mailbox.cache(); - auto mbox_end = mbox_cache.end(); - auto iter = std::find_if(mbox_cache.begin(), mbox_end, rm_fun); - while (iter == mbox_end) - { - auto next = m_mailbox.try_fetch_more(timeout); - if (next == mbox_end) - { - rules.handle_timeout(); - return; - } - iter = std::find_if(next, mbox_end, rm_fun); - } - mbox_cache.erase(iter); - } - else - { - converted_thread_context::dequeue(rules.get_partial_function()); - } -} - -converted_thread_context::throw_on_exit_result -converted_thread_context::throw_on_exit(const any_tuple& msg) -{ - if (matches(msg, m_exit_msg_pattern)) - { - auto reason = msg.get_as(1); - if (reason != exit_reason::normal) - { - // throws - quit(reason); - } - else - { - return normal_exit_signal; - } - } - return not_an_exit_signal; -} - -bool converted_thread_context::dq(queue_node& node, partial_function& rules) -{ - if ( m_trap_exit == false - && throw_on_exit(node.msg) == normal_exit_signal) - { - return false; - } - std::swap(m_last_dequeued, node.msg); - std::swap(m_last_sender, node.sender); - { - queue_node_guard qguard{&node}; - if (rules(m_last_dequeued)) - { - // client calls erase(iter) - qguard.release(); - m_last_dequeued.reset(); - m_last_sender.reset(); - return true; - } - } - // no match (restore members) - std::swap(m_last_dequeued, node.msg); - std::swap(m_last_sender, node.sender); - return false; -} - -} } // namespace cppa::detail diff --git a/src/cppa.cpp b/src/cppa.cpp deleted file mode 100644 index 4e08e5b911..0000000000 --- a/src/cppa.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/******************************************************************************\ - * ___ __ * - * /\_ \ __/\ \ * - * \//\ \ /\_\ \ \____ ___ _____ _____ __ * - * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * - * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * - * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * - * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * - * \ \_\ \ \_\ * - * \/_/ \/_/ * - * * - * Copyright (C) 2011, 2012 * - * Dominik Charousset * - * * - * This file is part of libcppa. * - * libcppa is free software: you can redistribute it and/or modify it under * - * the terms of the GNU Lesser General Public License as published by the * - * Free Software Foundation, either version 3 of the License * - * or (at your option) any later version. * - * * - * libcppa is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with libcppa. If not, see . * -\******************************************************************************/ - - -#include "cppa/cppa.hpp" -#include "cppa/local_actor.hpp" - -namespace { - -class observer : public cppa::attachable -{ - - cppa::actor_ptr m_client; - - public: - - observer(cppa::actor_ptr&& client) : m_client(std::move(client)) { } - - void actor_exited(std::uint32_t reason) - { - using namespace cppa; - send(m_client, atom(":Down"), actor_ptr(self), reason); - } - - bool matches(const cppa::attachable::token& match_token) - { - if (match_token.subtype == typeid(observer)) - { - auto ptr = reinterpret_cast(match_token.ptr); - return m_client == ptr; - } - return false; - } - -}; - -} // namespace - -namespace cppa { - -const self_type& operator<<(const self_type& s, const any_tuple& what) -{ - local_actor* sptr = s; - sptr->enqueue(sptr, what); - return s; -} - -const self_type& operator<<(const self_type& s, any_tuple&& what) -{ - local_actor* sptr = s; - sptr->enqueue(sptr, std::move(what)); - return s; -} - -void link(actor_ptr& other) -{ - if (other) self->link_to(other); -} - -void link(actor_ptr&& other) -{ - actor_ptr tmp(std::move(other)); - link(tmp); -} - -void link(actor_ptr& lhs, actor_ptr& rhs) -{ - if (lhs && rhs) lhs->link_to(rhs); -} - -void link(actor_ptr&& lhs, actor_ptr& rhs) -{ - actor_ptr tmp(std::move(lhs)); - link(tmp, rhs); -} - -void link(actor_ptr&& lhs, actor_ptr&& rhs) -{ - actor_ptr tmp1(std::move(lhs)); - actor_ptr tmp2(std::move(rhs)); - link(tmp1, tmp2); -} - -void link(actor_ptr& lhs, actor_ptr&& rhs) -{ - actor_ptr tmp(std::move(rhs)); - link(lhs, tmp); -} - -void unlink(actor_ptr& lhs, actor_ptr& rhs) -{ - if (lhs && rhs) lhs->unlink_from(rhs); -} - -void monitor(actor_ptr& whom) -{ - if (whom) whom->attach(new observer(actor_ptr(self))); -} - -void monitor(actor_ptr&& whom) -{ - actor_ptr tmp(std::move(whom)); - monitor(tmp); -} - -void demonitor(actor_ptr& whom) -{ - attachable::token mtoken(typeid(observer), self); - if (whom) whom->detach(mtoken); -} - -} // namespace cppa diff --git a/src/demangle.cpp b/src/demangle.cpp index 35b07cad8b..ff9d3838b6 100644 --- a/src/demangle.cpp +++ b/src/demangle.cpp @@ -41,52 +41,52 @@ namespace cppa { namespace detail { -std::string demangle(char const* decorated) -{ +std::string demangle(const char* decorated) { size_t size; int status; char* undecorated = abi::__cxa_demangle(decorated, nullptr, &size, &status); - if (status != 0) - { + if (status != 0) { std::string error_msg = "Could not demangle type name "; error_msg += decorated; throw std::logic_error(error_msg); } std::string result; // the undecorated typeid name result.reserve(size); - char const* cstr = undecorated; + const char* cstr = undecorated; // filter unnecessary characters from undecorated char c = *cstr; - while (c != '\0') - { - if (c == ' ') - { + while (c != '\0') { + if (c == ' ') { char previous_c = result.empty() ? ' ' : *(result.rbegin()); // get next non-space character for (c = *++cstr; c == ' '; c = *++cstr) { } - if (c != '\0') - { + if (c != '\0') { // skip whitespace unless it separates two alphanumeric // characters (such as in "unsigned int") - if (isalnum(c) && isalnum(previous_c)) - { + if (isalnum(c) && isalnum(previous_c)) { result += ' '; result += c; } - else - { + else { result += c; } c = *++cstr; } } - else - { + else { result += c; c = *++cstr; } } free(undecorated); +# ifdef __clang__ + // replace "std::__1::" with "std::" (fixes strange clang names) + std::string needle = "std::__1::"; + std::string fixed_string = "std::"; + for (auto pos = result.find(needle); pos != std::string::npos; pos = result.find(needle)) { + result.replace(pos, needle.size(), fixed_string); + } +# endif return result; } diff --git a/src/deserializer.cpp b/src/deserializer.cpp index feb628bcda..e7252d78d7 100644 --- a/src/deserializer.cpp +++ b/src/deserializer.cpp @@ -37,16 +37,13 @@ namespace cppa { -deserializer::~deserializer() -{ +deserializer::~deserializer() { } -deserializer& operator>>(deserializer& d, object& what) -{ +deserializer& operator>>(deserializer& d, object& what) { std::string tname = d.peek_object(); auto mtype = uniform_type_info::from(tname); - if (mtype == nullptr) - { + if (mtype == nullptr) { throw std::logic_error("no uniform type info found for " + tname); } what = std::move(mtype->deserialize(&d)); diff --git a/src/duration.cpp b/src/duration.cpp index 8b1f872ac7..3f3b5902b6 100644 --- a/src/duration.cpp +++ b/src/duration.cpp @@ -32,8 +32,7 @@ namespace { -inline std::uint64_t ui64_val(const cppa::util::duration& d) -{ +inline std::uint64_t ui64_val(const cppa::util::duration& d) { return static_cast(d.unit) * d.count; } @@ -41,8 +40,7 @@ inline std::uint64_t ui64_val(const cppa::util::duration& d) namespace cppa { namespace util { -bool operator==(const duration& lhs, const duration& rhs) -{ +bool operator==(const duration& lhs, const duration& rhs) { return (lhs.unit == rhs.unit ? lhs.count == rhs.count : ui64_val(lhs) == ui64_val(rhs)); } diff --git a/src/empty_tuple.cpp b/src/empty_tuple.cpp index 4abc29b0ea..8fa2ad4495 100644 --- a/src/empty_tuple.cpp +++ b/src/empty_tuple.cpp @@ -33,42 +33,34 @@ namespace cppa { namespace detail { -empty_tuple::empty_tuple() : abstract_tuple(tuple_impl_info::statically_typed) -{ +empty_tuple::empty_tuple() : abstract_tuple(tuple_impl_info::statically_typed) { } -size_t empty_tuple::size() const -{ +size_t empty_tuple::size() const { return 0; } -void* empty_tuple::mutable_at(size_t) -{ +void* empty_tuple::mutable_at(size_t) { throw std::range_error("empty_tuple::mutable_at()"); } -abstract_tuple* empty_tuple::copy() const -{ +abstract_tuple* empty_tuple::copy() const { return new empty_tuple; } -const void* empty_tuple::at(size_t) const -{ +const void* empty_tuple::at(size_t) const { throw std::range_error("empty_tuple::at()"); } -const uniform_type_info* empty_tuple::type_at(size_t) const -{ +const uniform_type_info* empty_tuple::type_at(size_t) const { throw std::range_error("empty_tuple::type_at()"); } -bool empty_tuple::equals(const abstract_tuple& other) const -{ +bool empty_tuple::equals(const abstract_tuple& other) const { return other.size() == 0; } -std::type_info const* empty_tuple::type_token() const -{ +const std::type_info* empty_tuple::type_token() const { return &typeid(util::type_list<>); } diff --git a/src/event_based_actor.cpp b/src/event_based_actor.cpp index 513a85a280..351ac965ec 100644 --- a/src/event_based_actor.cpp +++ b/src/event_based_actor.cpp @@ -28,51 +28,101 @@ \******************************************************************************/ +#include +#include "cppa/to_string.hpp" + +#include "cppa/self.hpp" #include "cppa/event_based_actor.hpp" +#include "cppa/detail/filter_result.hpp" + namespace cppa { -event_based_actor::event_based_actor() -{ - m_loop_stack.reserve(2); +event_based_actor::event_based_actor() : super(super::blocked) { } + +void event_based_actor::dequeue(behavior&) { + quit(exit_reason::unallowed_function_call); } -void event_based_actor::become_void() -{ - cleanup(exit_reason::normal); - m_loop_stack.clear(); +void event_based_actor::dequeue(partial_function&) { + quit(exit_reason::unallowed_function_call); } -void event_based_actor::quit(std::uint32_t reason) -{ - if (reason == exit_reason::normal) - { - become_void(); - } - else - { - abstract_scheduled_actor::quit(reason); +resume_result event_based_actor::resume(util::fiber*) { + scoped_self_setter sss{this}; + auto done_cb = [&]() { + m_state.store(abstract_scheduled_actor::done); + m_bhvr_stack.clear(); + on_exit(); + }; + try { + detail::recursive_queue_node* e; + for (;;) { + e = m_mailbox.try_pop(); + if (!e) { + m_state.store(abstract_scheduled_actor::about_to_block); + if (m_mailbox.can_fetch_more() == false) { + switch (compare_exchange_state( + abstract_scheduled_actor::about_to_block, + abstract_scheduled_actor::blocked)) { + case abstract_scheduled_actor::ready: { + break; + } + case abstract_scheduled_actor::blocked: { + return resume_result::actor_blocked; + } + default: CPPA_CRITICAL("illegal actor state"); + }; + } + } + else { + if (m_policy.invoke(this, e, get_behavior())) { + // try to match cached message before receiving new ones + do { + m_bhvr_stack.cleanup(); + if (m_bhvr_stack.empty()) { + done_cb(); + return resume_result::actor_done; + } + } while (m_policy.invoke_from_cache(this, get_behavior())); + } + } + } } + catch (actor_exited& what) { cleanup(what.reason()); } + catch (...) { cleanup(exit_reason::unhandled_exception); } + done_cb(); + return resume_result::actor_done; +} + +bool event_based_actor::has_behavior() { + return m_bhvr_stack.empty() == false; } -void event_based_actor::do_become(behavior* bhvr, bool has_ownership) -{ +void event_based_actor::do_become(behavior* ptr, bool owner, bool discard_old) { reset_timeout(); - request_timeout(bhvr->timeout()); - stack_element new_element{bhvr}; - if (!has_ownership) new_element.get_deleter().disable(); - // keep always the latest element in the stack to prevent subtle errors, - // e.g., the addresses of all variables in a lambda expression calling - // become() suddenly are invalid if we would pop the behavior! - if (m_loop_stack.size() < 2) - { - m_loop_stack.push_back(std::move(new_element)); + request_timeout(ptr->timeout()); + if (discard_old) m_bhvr_stack.pop_back(); + m_bhvr_stack.push_back(ptr, owner); +} + +void event_based_actor::quit(std::uint32_t reason) { + if (reason == exit_reason::normal) { + cleanup(exit_reason::normal); + m_bhvr_stack.clear(); + m_bhvr_stack.cleanup(); } - else - { - m_loop_stack[0] = std::move(m_loop_stack[1]); - m_loop_stack[1] = std::move(new_element); + else { + abstract_scheduled_actor::quit(reason); } } +void event_based_actor::unbecome() { + m_bhvr_stack.pop_back(); +} + +scheduled_actor_type event_based_actor::impl_type() { + return event_based_impl; +} + } // namespace cppa diff --git a/src/exception.cpp b/src/exception.cpp index 329a04efc3..f05cf51ad0 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -38,17 +38,14 @@ namespace { -std::string ae_what(std::uint32_t reason) -{ +std::string ae_what(std::uint32_t reason) { std::ostringstream oss; oss << "actor exited with reason " << reason; return oss.str(); } -std::string be_what(int err_code) -{ - switch (err_code) - { +std::string be_what(int err_code) { + switch (err_code) { case EACCES: return "EACCES: address is protected; root access needed"; case EADDRINUSE: return "EADDRINUSE: address is already in use"; case EBADF: return "EBADF: no valid socket descriptor"; @@ -66,39 +63,31 @@ std::string be_what(int err_code) namespace cppa { -exception::exception(const std::string &what_str) : m_what(what_str) -{ +exception::exception(const std::string &what_str) : m_what(what_str) { } -exception::exception(std::string&& what_str) : m_what(std::move(what_str)) -{ +exception::exception(std::string&& what_str) : m_what(std::move(what_str)) { } -exception::~exception() throw() -{ +exception::~exception() throw() { } -const char* exception::what() const throw() -{ +const char* exception::what() const throw() { return m_what.c_str(); } -actor_exited::actor_exited(std::uint32_t reason) : exception(ae_what(reason)) -{ +actor_exited::actor_exited(std::uint32_t reason) : exception(ae_what(reason)) { m_reason = reason; } -network_error::network_error(const std::string& str) : exception(str) -{ +network_error::network_error(const std::string& str) : exception(str) { } network_error::network_error(std::string&& str) - : exception(std::move(str)) -{ + : exception(std::move(str)) { } -bind_failure::bind_failure(int err_code) : network_error(be_what(err_code)) -{ +bind_failure::bind_failure(int err_code) : network_error(be_what(err_code)) { m_errno = err_code; } diff --git a/cppa/util/projection.hpp b/src/factory.cpp similarity index 94% rename from cppa/util/projection.hpp rename to src/factory.cpp index 139410b59d..e8ae5b41dc 100644 --- a/cppa/util/projection.hpp +++ b/src/factory.cpp @@ -28,13 +28,10 @@ \******************************************************************************/ -#ifndef PROJECTION_HPP -#define PROJECTION_HPP +#include "cppa/factory.hpp" -namespace cppa { namespace util { +namespace cppa { namespace factory { +void default_cleanup() { } - -} } // namespace cppa::util - -#endif // PROJECTION_HPP +} } // namespace cppa::factory diff --git a/src/fiber.cpp b/src/fiber.cpp index 981f5d0915..72dbad9b5b 100644 --- a/src/fiber.cpp +++ b/src/fiber.cpp @@ -28,218 +28,74 @@ \******************************************************************************/ -#ifndef _XOPEN_SOURCE -#define _XOPEN_SOURCE -#endif +#ifdef CPPA_DISABLE_CONTEXT_SWITCHING -#include "cppa/config.hpp" -#ifndef CPPA_DISABLE_CONTEXT_SWITCHING +namespace { int keep_compiler_happy() { return 42; } } + +#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING -#include -#include -#include #include -#include +#include #include "cppa/util/fiber.hpp" -#include "cppa/detail/thread.hpp" - -#ifdef CPPA_USE_UCONTEXT_IMPL - -#include -#include - -#include - -namespace { - -constexpr size_t s_stack_size = SIGSTKSZ; - -inline void* get_stack() -{ - return mmap(0, - s_stack_size, - PROT_EXEC | PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, - -1, - 0); -} - -inline void release_stack(void* mem) -{ - munmap(mem, s_stack_size); -} - -typedef void (*void_function)(); -typedef void (*void_ptr_function)(void*); - -template -struct trampoline; - -template -struct trampoline<4, FunType, IntType> -{ - static_assert(sizeof(int) == 4, "sizeof(int) != 4"); - static void bounce(int func_ptr, int ptr) - { - auto func = reinterpret_cast(func_ptr); - func(reinterpret_cast(ptr)); - } - static void prepare(ucontext_t* ctx, void_ptr_function func, void* arg) - { - makecontext(ctx, (FunType) &trampoline<4>::bounce, - 2, (IntType) func, (IntType) arg); - } -}; - -template -struct trampoline<8, FunType, IntType> -{ - static_assert(sizeof(int) == 4, "sizeof(int) != 4"); - static void bounce(int func_first_4_byte, int func_second_4_byte, - int arg_first_4_byte, int arg_second_4_byte) - { - std::uint64_t arg_ptr; - { - int* _addr = reinterpret_cast(&arg_ptr); - _addr[0] = arg_first_4_byte; - _addr[1] = arg_second_4_byte; - } - std::uint64_t func_ptr; - { - int* _addr = reinterpret_cast(&func_ptr); - _addr[0] = func_first_4_byte; - _addr[1] = func_second_4_byte; - } - auto func = reinterpret_cast(func_ptr); - func((void*) arg_ptr); - } - static void prepare(ucontext_t* ctx, void_ptr_function func, void* arg) - { - std::uint64_t arg_ptr = reinterpret_cast(arg); - std::uint64_t func_ptr = reinterpret_cast(func); - int* func_addr = reinterpret_cast(&func_ptr); - int* arg_addr = reinterpret_cast(&arg_ptr); - makecontext(ctx, (FunType) &trampoline<8>::bounce, - 4, func_addr[0], func_addr[1], arg_addr[0], arg_addr[1]); - } -}; - -} // namespace namespace cppa { namespace util { -struct fiber_impl -{ - - bool m_initialized; - void* m_stack; - void (*m_func)(void*); - void* m_arg; - ucontext_t m_ctx; - - fiber_impl() throw() : m_initialized(true), m_stack(0), m_func(0), m_arg(0) - { - memset(&m_ctx, 0, sizeof(ucontext_t)); - getcontext(&m_ctx); - } +void fiber_trampoline(intptr_t iptr); - fiber_impl(void (*func)(void*), void* arg) - : m_initialized(false) - , m_stack(nullptr) - , m_func(func) - , m_arg(arg) - { - } +struct fiber_impl { - inline void swap(fiber_impl* to) - { - swapcontext(&(m_ctx), &(to->m_ctx)); + void* m_arg; + bool m_converted; + void (*m_fun)(void*); + boost::ctx::fcontext_t m_ctx; + boost::ctx::stack_allocator m_alloc; + + fiber_impl() : m_arg(nullptr), m_converted(true), m_fun(nullptr) { } + + fiber_impl(void (*fun)(void*), void* arg) : m_arg(arg), m_converted(false), m_fun(fun) { + auto st = m_alloc.allocate(boost::ctx::minimum_stacksize()); + m_ctx.fc_stack.base = st; + m_ctx.fc_stack.limit = static_cast(st) - boost::ctx::minimum_stacksize(); + boost::ctx::make_fcontext(&m_ctx, fiber_trampoline); } - void initialize() - { - m_initialized = true; - memset(&m_ctx, 0, sizeof(ucontext_t)); - getcontext(&m_ctx); - m_stack = get_stack(); - m_ctx.uc_stack.ss_sp = m_stack; - m_ctx.uc_stack.ss_size = s_stack_size; - m_ctx.uc_link = nullptr; - trampoline::prepare(&m_ctx, m_func, m_arg); + inline void run() { + m_fun(m_arg); } - inline void lazy_init() - { - if (!m_initialized) initialize(); + void swap(fiber_impl* to) { + boost::ctx::jump_fcontext(&m_ctx, &(to->m_ctx), (intptr_t) to); } - ~fiber_impl() - { - if (m_stack) release_stack(m_stack); + ~fiber_impl() { + if (m_converted == false) { + m_alloc.deallocate(m_ctx.fc_stack.base, boost::ctx::minimum_stacksize()); + } } }; -fiber::fiber() throw() : m_impl(new fiber_impl) -{ +void fiber_trampoline(intptr_t iptr) { + auto ptr = (fiber_impl*) iptr; + ptr->run(); } -fiber::fiber(void (*func)(void*), void* arg) : m_impl(new fiber_impl(func, arg)) -{ +fiber::fiber() throw() : m_impl(new fiber_impl) { } -fiber::~fiber() -{ - delete m_impl; +fiber::fiber(void (*func)(void*), void* arg) +: m_impl(new fiber_impl(func, arg)) { } -void fiber::swap(fiber& from, fiber& to) -{ - to.m_impl->lazy_init(); +void fiber::swap(fiber& from, fiber& to) { from.m_impl->swap(to.m_impl); } -} } // namespace cppa::util - -#elif defined(CPPA_USE_FIBER_IMPL) - -#include - -fiber::fiber() : handle(nullptr), is_converted_thread(true) -{ - handle = ConvertThreadToFiber(nullptr); - if (handle == nullptr) - { - throw std::logic_error("handle == nullptr"); - } -} - -fiber::fiber(LPFIBER_START_ROUTINE func, LPVOID arg1) - : handle(nullptr) - , is_converted_thread(false) -{ - handle = CreateFiber(0, func, arg1); - if (handle == nullptr) - { - throw std::logic_error("handle == nullptr"); - } -} - -fiber::~fiber() -{ - if (handle != nullptr && !is_converted_thread) - { - DeleteFiber(handle); - } +fiber::~fiber() { + delete m_impl; } -#endif // CPPA_USE_FIBER_IMPL - -#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING - -namespace { int keep_compiler_happy() { return 42; } } +} } // namespace cppa::util #endif // CPPA_DISABLE_CONTEXT_SWITCHING diff --git a/src/group.cpp b/src/group.cpp index eef9d25f29..a5c8b1ce4e 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -39,76 +39,57 @@ namespace cppa { intrusive_ptr group::get(const std::string& arg0, - const std::string& arg1) -{ + const std::string& arg1) { return detail::singleton_manager::get_group_manager()->get(arg0, arg1); } -intrusive_ptr group::anonymous() -{ +intrusive_ptr group::anonymous() { return detail::singleton_manager::get_group_manager()->anonymous(); } -void group::add_module(group::module* ptr) -{ +void group::add_module(group::module* ptr) { detail::singleton_manager::get_group_manager()->add_module(ptr); } group::unsubscriber::unsubscriber(const channel_ptr& s, const intrusive_ptr& g) - : m_self(s), m_group(g) -{ + : m_self(s), m_group(g) { } -group::unsubscriber::~unsubscriber() -{ +group::unsubscriber::~unsubscriber() { if (m_group && m_self) m_group->unsubscribe(m_self); } -void group::unsubscriber::actor_exited(std::uint32_t) -{ +void group::unsubscriber::actor_exited(std::uint32_t) { // unsubscription is done in destructor } -bool group::unsubscriber::matches(const attachable::token& what) -{ - if (what.subtype == typeid(group::unsubscriber)) - { +bool group::unsubscriber::matches(const attachable::token& what) { + if (what.subtype == typeid(group::unsubscriber)) { return m_group == reinterpret_cast(what.ptr); } return false; } -group::module::module(const std::string& name) : m_name(name) -{ -} - -group::module::module(std::string&& name) : m_name(std::move(name)) -{ -} +group::module::module(std::string name) : m_name(std::move(name)) { } -const std::string& group::module::name() -{ +const std::string& group::module::name() { return m_name; } group::group(std::string&& id, std::string&& mod_name) - : m_identifier(std::move(id)), m_module_name(std::move(mod_name)) -{ + : m_identifier(std::move(id)), m_module_name(std::move(mod_name)) { } group::group(const std::string& id, const std::string& mod_name) - : m_identifier(id), m_module_name(mod_name) -{ + : m_identifier(id), m_module_name(mod_name) { } -const std::string& group::identifier() const -{ +const std::string& group::identifier() const { return m_identifier; } -const std::string& group::module_name() const -{ +const std::string& group::module_name() const { return m_module_name; } diff --git a/src/group_manager.cpp b/src/group_manager.cpp index 6212fc1cce..2871ea04c5 100644 --- a/src/group_manager.cpp +++ b/src/group_manager.cpp @@ -41,14 +41,13 @@ namespace { using namespace cppa; -typedef detail::lock_guard exclusive_guard; +typedef std::lock_guard exclusive_guard; typedef util::shared_lock_guard shared_guard; typedef util::upgrade_lock_guard upgrade_guard; class local_group_module; -class group_impl : public group -{ +class group_impl : public group { util::shared_spinlock m_shared_mtx; std::set m_subscribers; @@ -60,48 +59,35 @@ class group_impl : public group public: - void enqueue(actor* sender, const any_tuple& msg) /*override*/ - { + void enqueue(actor* sender, any_tuple msg) /*override*/ { shared_guard guard(m_shared_mtx); - for (auto i = m_subscribers.begin(); i != m_subscribers.end(); ++i) - { + for (auto i = m_subscribers.begin(); i != m_subscribers.end(); ++i) { // this cast is safe because we don't affect the "value" // of *i, thus, the set remains in a consistent state const_cast(*i)->enqueue(sender, msg); } } - void enqueue(actor* sender, any_tuple&& msg) /*override*/ - { - any_tuple tmp(std::move(msg)); - enqueue(sender, tmp); - } - - group::subscription subscribe(const channel_ptr& who) /*override*/ - { + group::subscription subscribe(const channel_ptr& who) /*override*/ { group::subscription result; exclusive_guard guard(m_shared_mtx); - if (m_subscribers.insert(who).second) - { + if (m_subscribers.insert(who).second) { result.reset(new group::unsubscriber(who, this)); } return result; } - void unsubscribe(const channel_ptr& who) /*override*/ - { + void unsubscribe(const channel_ptr& who) /*override*/ { exclusive_guard guard(m_shared_mtx); m_subscribers.erase(who); } }; -struct anonymous_group : group_impl -{ +struct anonymous_group : group_impl { anonymous_group() : group_impl("anonymous", "anonymous") { } }; -class local_group : public group_impl -{ +class local_group : public group_impl { friend class local_group_module; @@ -109,8 +95,7 @@ class local_group : public group_impl }; -class local_group_module : public group::module -{ +class local_group_module : public group::module { typedef group::module super; @@ -121,19 +106,15 @@ class local_group_module : public group::module local_group_module() : super("local") { } - group_ptr get(const std::string& group_name) - { + group_ptr get(const std::string& group_name) { shared_guard guard(m_mtx); auto i = m_instances.find(group_name); - if (i != m_instances.end()) - { + if (i != m_instances.end()) { return i->second; } - else - { + else { group_ptr tmp(new local_group(group_name)); - // lifetime scope of uguard - { + { // lifetime scope of uguard upgrade_guard uguard(guard); auto p = m_instances.insert(std::make_pair(group_name, tmp)); // someone might preempt us @@ -148,26 +129,21 @@ class local_group_module : public group::module namespace cppa { namespace detail { -group_manager::group_manager() -{ +group_manager::group_manager() { std::unique_ptr ptr(new local_group_module); m_mmap.insert(std::make_pair(std::string("local"), std::move(ptr))); } -intrusive_ptr group_manager::anonymous() -{ +intrusive_ptr group_manager::anonymous() { return new anonymous_group; } intrusive_ptr group_manager::get(const std::string& module_name, - const std::string& group_identifier) -{ - // lifetime scope of guard - { - detail::lock_guard guard(m_mmap_mtx); + const std::string& group_identifier) { + { // lifetime scope of guard + std::lock_guard guard(m_mmap_mtx); auto i = m_mmap.find(module_name); - if (i != m_mmap.end()) - { + if (i != m_mmap.end()) { return (i->second)->get(group_identifier); } } @@ -177,15 +153,12 @@ intrusive_ptr group_manager::get(const std::string& module_name, throw std::logic_error(error_msg); } -void group_manager::add_module(group::module* mod) -{ +void group_manager::add_module(group::module* mod) { const std::string& mname = mod->name(); std::unique_ptr mptr(mod); - // lifetime scope of guard - { - detail::lock_guard guard(m_mmap_mtx); - if (m_mmap.insert(std::make_pair(mname, std::move(mptr))).second) - { + { // lifetime scope of guard + std::lock_guard guard(m_mmap_mtx); + if (m_mmap.insert(std::make_pair(mname, std::move(mptr))).second) { return; // success; don't throw } } diff --git a/src/local_actor.cpp b/src/local_actor.cpp index 01756bdb7c..36aed85356 100644 --- a/src/local_actor.cpp +++ b/src/local_actor.cpp @@ -28,12 +28,70 @@ \******************************************************************************/ +#include "cppa/cppa.hpp" +#include "cppa/atom.hpp" #include "cppa/local_actor.hpp" namespace cppa { -local_actor::local_actor() : m_trap_exit(false) -{ +namespace { + +class down_observer : public attachable { + + actor_ptr m_observer; + actor_ptr m_observed; + + public: + + down_observer(actor_ptr observer, actor_ptr observed) + : m_observer(std::move(observer)) + , m_observed(std::move(observed)) { + } + + void actor_exited(std::uint32_t reason) { + if (m_observer) { + m_observer->enqueue(m_observed.get(), + make_any_tuple(atom("DOWN"), reason)); + } + } + + bool matches(const attachable::token& match_token) { + if (match_token.subtype == typeid(down_observer)) { + auto ptr = reinterpret_cast(match_token.ptr); + return m_observer == ptr; + } + return false; + } + +}; + +} // namespace + +local_actor::local_actor(bool sflag) +: m_chaining(sflag), m_trap_exit(false), m_is_scheduled(sflag) { } + +void local_actor::monitor(actor_ptr whom) { + if (whom) whom->attach(new down_observer(this, whom)); +} + +void local_actor::demonitor(actor_ptr whom) { + attachable::token mtoken{typeid(down_observer), this}; + if (whom) whom->detach(mtoken); +} + +void local_actor::on_exit() { } + +void local_actor::init() { } + +void local_actor::join(const group_ptr& what) { + if (what) attach(what->subscribe(this)); +} + +void local_actor::leave(const group_ptr& what) { + if (what) { + attachable::token group_token(typeid(group::unsubscriber), what.get()); + detach(group_token); + } } } // namespace cppa diff --git a/src/mailman.cpp b/src/mailman.cpp index 3d62418520..a96ece283b 100644 --- a/src/mailman.cpp +++ b/src/mailman.cpp @@ -31,149 +31,87 @@ #include #include +#include "cppa/cppa.hpp" #include "cppa/to_string.hpp" #include "cppa/detail/mailman.hpp" #include "cppa/binary_serializer.hpp" #include "cppa/detail/post_office.hpp" -/* #define DEBUG(arg) \ std::cout << "[process id: " \ << cppa::process_information::get()->process_id() \ << "] " << arg << std::endl -//*/ +#undef DEBUG #define DEBUG(unused) ((void) 0) +using std::cout; +using std::cerr; +using std::endl; + // implementation of mailman.hpp namespace cppa { namespace detail { -mailman_job::mailman_job(process_information_ptr piptr, - const actor_ptr& from, - const channel_ptr& to, - const any_tuple& content) - : next(nullptr), m_type(send_job_type) -{ - new (&m_send_job) mailman_send_job (piptr, from, to, content); -} - -mailman_job::mailman_job(native_socket_type sockfd, const process_information_ptr& pinfo) - : next(0), m_type(add_peer_type) -{ - new (&m_add_socket) mailman_add_peer (sockfd, pinfo); -} - -mailman_job* mailman_job::kill_job() -{ - return new mailman_job(kill_type); -} - -mailman_job::~mailman_job() -{ - switch (m_type) - { - case send_job_type: - { - m_send_job.~mailman_send_job(); - break; - } - case add_peer_type: - { - m_add_socket.~mailman_add_peer(); - break; - } - default: - { - // union doesn't contain a valid object - break; - } - } -} - -// known issues: send() should be asynchronous and select() should be used -void mailman_loop() -{ +void mailman_loop() { + bool done = false; // serializes outgoing messages binary_serializer bs; - // current active job - std::unique_ptr job; - // caches mailman_queue() - auto& mqueue = mailman_queue(); // connected tcp peers std::map peers; - for (;;) - { - job.reset(mqueue.pop()); - if (job->is_send_job()) - { - mailman_send_job& sjob = job->send_job(); - // forward message to receiver peer - auto peer_element = peers.find(*(sjob.target_peer)); - if (peer_element != peers.end()) - { + do_receive ( + on_arg_match >> [&](process_information_ptr target_peer, addressed_message msg) { + auto i = peers.find(*target_peer); + if (i != peers.end()) { bool disconnect_peer = false; - auto peer = peer_element->second; - try - { - bs << sjob.msg; - auto size32 = static_cast(bs.size()); - DEBUG("--> " << to_string(sjob.msg)); - // write size of serialized message - auto sent = ::send(peer, &size32, sizeof(std::uint32_t), 0); - if (sent > 0) - { - // write message - sent = ::send(peer, bs.data(), bs.size(), 0); - } - // disconnect peer if send() failed - disconnect_peer = (sent <= 0); - // make sure all bytes are written - if (static_cast(sent) != size32) - { - throw std::logic_error("send() not a synchronous socket"); + auto peer_fd = i->second; + try { + bs << msg; + DEBUG("--> " << to_string(msg)); + auto sent = ::send(peer_fd, bs.sendable_data(), bs.sendable_size(), 0); + if (sent < 0 || static_cast(sent) != bs.sendable_size()) { + disconnect_peer = true; + DEBUG("too few bytes written"); } } // something went wrong; close connection to this peer - catch (std::exception& e) - { + catch (std::exception& e) { DEBUG(to_uniform_name(typeid(e)) << ": " << e.what()); disconnect_peer = true; } - if (disconnect_peer) - { + if (disconnect_peer) { DEBUG("peer disconnected (error during send)"); //closesocket(peer); - post_office_close_socket(peer); - peers.erase(peer_element); + post_office_close_socket(peer_fd); + peers.erase(i); } bs.reset(); } - else - { - DEBUG("message to an unknown peer"); + else { + DEBUG("message to an unknown peer: " << to_string(msg)); } - // else: unknown peer - } - else if (job->is_add_peer_job()) - { - mailman_add_peer& pjob = job->add_peer_job(); - auto i = peers.find(*(pjob.pinfo)); - if (i == peers.end()) - { + }, + on_arg_match >> [&](native_socket_type sockfd, process_information_ptr pinfo) { + DEBUG("mailman: add_peer"); + auto i = peers.find(*pinfo); + if (i == peers.end()) { //cout << "mailman added " << pjob.pinfo->process_id() << "@" // << to_string(pjob.pinfo->node_id()) << endl; - peers.insert(std::make_pair(*(pjob.pinfo), pjob.sockfd)); + peers.insert(std::make_pair(*pinfo, sockfd)); } - else - { - // TODO: some kind of error handling? + else { + DEBUG("add_peer_job failed: peer already known"); } + }, + on(atom("DONE")) >> [&]() { + done = true; + }, + others() >> [&]() { + std::string str = "unexpected message in post_office: "; + str += to_string(self->last_dequeued()); + CPPA_CRITICAL(str.c_str()); } - else if (job->is_kill_job()) - { - return; - } - } + ) + .until(gref(done)); } } } // namespace cppa::detail diff --git a/src/mock_scheduler.cpp b/src/mock_scheduler.cpp deleted file mode 100644 index af30a23294..0000000000 --- a/src/mock_scheduler.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/******************************************************************************\ - * ___ __ * - * /\_ \ __/\ \ * - * \//\ \ /\_\ \ \____ ___ _____ _____ __ * - * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * - * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * - * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * - * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * - * \ \_\ \ \_\ * - * \/_/ \/_/ * - * * - * Copyright (C) 2011, 2012 * - * Dominik Charousset * - * * - * This file is part of libcppa. * - * libcppa is free software: you can redistribute it and/or modify it under * - * the terms of the GNU Lesser General Public License as published by the * - * Free Software Foundation, either version 3 of the License * - * or (at your option) any later version. * - * * - * libcppa is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with libcppa. If not, see . * -\******************************************************************************/ - - -#include "cppa/config.hpp" - -#include -#include - -#include "cppa/self.hpp" -#include "cppa/any_tuple.hpp" -#include "cppa/scheduler.hpp" -#include "cppa/attachable.hpp" -#include "cppa/local_actor.hpp" -#include "cppa/scheduled_actor.hpp" -#include "cppa/abstract_event_based_actor.hpp" - -#include "cppa/detail/thread.hpp" -#include "cppa/detail/actor_count.hpp" -#include "cppa/detail/mock_scheduler.hpp" -#include "cppa/detail/to_uniform_name.hpp" -#include "cppa/detail/converted_thread_context.hpp" - -using std::cout; -using std::cerr; -using std::endl; - -namespace { - -void run_actor(cppa::intrusive_ptr m_self, - cppa::scheduled_actor* behavior) -{ - cppa::self.set(m_self.get()); - if (behavior) - { - try { behavior->act(); } - catch (...) { } - try { behavior->on_exit(); } - catch (...) { } - delete behavior; - cppa::self.set(nullptr); - } - cppa::detail::dec_actor_count(); -} - -} // namespace - -namespace cppa { namespace detail { - -actor_ptr mock_scheduler::spawn(scheduled_actor* behavior) -{ - inc_actor_count(); - CPPA_MEMORY_BARRIER(); - intrusive_ptr ctx(new detail::converted_thread_context); - thread(run_actor, ctx, behavior).detach(); - return ctx; -} - -actor_ptr mock_scheduler::spawn(abstract_event_based_actor* what) -{ - // TODO: don't delete what :) - delete what; - return nullptr; -} - -actor_ptr mock_scheduler::spawn(scheduled_actor* behavior, scheduling_hint) -{ - return spawn(behavior); -} - -void mock_scheduler::enqueue(detail::abstract_scheduled_actor*) -{ - cerr << "mock_scheduler::enqueue" << endl; - abort(); -} - -} } // namespace detail diff --git a/src/native_socket.cpp b/src/native_socket.cpp index 097c037c60..51384c2135 100644 --- a/src/native_socket.cpp +++ b/src/native_socket.cpp @@ -39,26 +39,19 @@ namespace cppa { namespace detail { #ifndef CPPA_WINDOWS -void closesocket(native_socket_type s) -{ - if(::close(s) != 0) - { - switch(errno) - { - case EBADF: - { +void closesocket(native_socket_type s) { + if(::close(s) != 0) { + switch(errno) { + case EBADF: { throw std::ios_base::failure("EBADF: invalid socket"); } - case EINTR: - { + case EINTR: { throw std::ios_base::failure("EINTR: interrupted"); } - case EIO: - { + case EIO: { throw std::ios_base::failure("EIO: an I/O error occured"); } - default: - { + default: { std::ostringstream oss; throw std::ios_base::failure(""); } diff --git a/src/network_manager.cpp b/src/network_manager.cpp index 25c3fc9c8a..6a4a4c75ec 100644 --- a/src/network_manager.cpp +++ b/src/network_manager.cpp @@ -29,6 +29,7 @@ #include +#include #include #include #include // strerror @@ -37,10 +38,12 @@ #include #include -#include "cppa/detail/thread.hpp" +#include "cppa/self.hpp" +#include "cppa/scheduler.hpp" +#include "cppa/thread_mapped_actor.hpp" + #include "cppa/detail/mailman.hpp" #include "cppa/detail/post_office.hpp" -#include "cppa/detail/post_office_msg.hpp" #include "cppa/detail/network_manager.hpp" namespace { @@ -48,64 +51,61 @@ namespace { using namespace cppa; using namespace cppa::detail; -struct network_manager_impl : network_manager -{ - - typedef intrusive::single_reader_queue post_office_queue_t; - typedef intrusive::single_reader_queue mailman_queue_t; - - int m_pipe[2]; // m_pipe[0]: read; m_pipe[1]: write +struct network_manager_impl : network_manager { - mailman_queue_t m_mailman_queue; - post_office_queue_t m_post_office_queue; + local_actor_ptr m_mailman; + std::thread m_mailman_thread; - thread m_loop; // post office thread + local_actor_ptr m_post_office; + std::thread m_post_office_thread; - void start() /*override*/ - { - if (pipe(m_pipe) != 0) - { - char* error_cstr = strerror(errno); - std::string error_str = "pipe(): "; - error_str += error_cstr; - free(error_cstr); - throw std::logic_error(error_str); - } - m_loop = thread(post_office_loop, m_pipe[0], m_pipe[1]); - } + int pipe_fd[2]; - void write_to_pipe(const pipe_msg& what) - { - if (write(m_pipe[1], what, pipe_msg_size) != (int) pipe_msg_size) - { - std::cerr << "FATAL: cannot write to pipe" << std::endl; - abort(); + void start() { // override + if (pipe(pipe_fd) != 0) { + CPPA_CRITICAL("cannot create pipe"); } + // create actors + m_post_office.reset(new thread_mapped_actor); + m_mailman.reset(new thread_mapped_actor); + // store some data in local variables for lambdas + int pipe_fd0 = pipe_fd[0]; + auto po_ptr = m_post_office; + auto mm_ptr = m_mailman; + // start threads + m_post_office_thread = std::thread([pipe_fd0, po_ptr]() { + scoped_self_setter sss{po_ptr.get()}; + post_office_loop(pipe_fd0); + }); + m_mailman_thread = std::thread([mm_ptr]() { + scoped_self_setter sss{mm_ptr.get()}; + mailman_loop(); + }); } - inline int write_handle() const - { - return m_pipe[1]; + void stop() { // override + m_mailman->enqueue(nullptr, make_any_tuple(atom("DONE"))); + m_mailman_thread.join(); + // wait until mailman is done; post_office closes all sockets + std::atomic_thread_fence(std::memory_order_seq_cst); + send_to_post_office(po_message{atom("DONE"), -1, 0}); + m_post_office_thread.join(); + close(pipe_fd[0]); + close(pipe_fd[0]); } - mailman_queue_t& mailman_queue() - { - return m_mailman_queue; + void send_to_post_office(const po_message& msg) { + if (write(pipe_fd[1], &msg, sizeof(po_message)) != sizeof(po_message)) { + CPPA_CRITICAL("cannot write to pipe"); + } } - post_office_queue_t& post_office_queue() - { - return m_post_office_queue; + void send_to_post_office(any_tuple msg) { + m_post_office->enqueue(nullptr, std::move(msg)); } - void stop() /*override*/ - { - pipe_msg msg = { shutdown_event, 0 }; - write_to_pipe(msg); - // m_loop calls close(m_pipe[0]) - m_loop.join(); - close(m_pipe[0]); - close(m_pipe[1]); + void send_to_mailman(any_tuple msg) { + m_mailman->enqueue(nullptr, std::move(msg)); } }; @@ -114,12 +114,10 @@ struct network_manager_impl : network_manager namespace cppa { namespace detail { -network_manager::~network_manager() -{ +network_manager::~network_manager() { } -network_manager* network_manager::create_singleton() -{ +network_manager* network_manager::create_singleton() { return new network_manager_impl; } diff --git a/src/object.cpp b/src/object.cpp index 4e8a2e4cd0..3da279e502 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -41,8 +41,7 @@ namespace { cppa::util::void_type s_void; -inline cppa::uniform_type_info const* tvoid() -{ +inline const cppa::uniform_type_info* tvoid() { return cppa::detail::static_types_array::arr[0]; } @@ -50,58 +49,48 @@ inline cppa::uniform_type_info const* tvoid() namespace cppa { -void object::swap(object& other) -{ +void object::swap(object& other) { std::swap(m_value, other.m_value); std::swap(m_type, other.m_type); } -object::object(void* val, uniform_type_info const* utype) - : m_value(val), m_type(utype) -{ +object::object(void* val, const uniform_type_info* utype) + : m_value(val), m_type(utype) { CPPA_REQUIRE(val != nullptr); CPPA_REQUIRE(utype != nullptr); } -object::object() : m_value(&s_void), m_type(tvoid()) -{ +object::object() : m_value(&s_void), m_type(tvoid()) { } -object::~object() -{ +object::~object() { if (m_value != &s_void) m_type->delete_instance(m_value); } -object::object(const object& other) -{ +object::object(const object& other) { m_type = other.m_type; m_value = (other.m_value == &s_void) ? other.m_value : m_type->new_instance(other.m_value); } -object::object(object&& other) : m_value(&s_void), m_type(tvoid()) -{ +object::object(object&& other) : m_value(&s_void), m_type(tvoid()) { swap(other); } -object& object::operator=(object&& other) -{ +object& object::operator=(object&& other) { object tmp(std::move(other)); swap(tmp); return *this; } -object& object::operator=(const object& other) -{ +object& object::operator=(const object& other) { object tmp(other); swap(tmp); return *this; } -bool operator==(const object& lhs, const object& rhs) -{ - if (lhs.type() == rhs.type()) - { +bool operator==(const object& lhs, const object& rhs) { + if (lhs.type() == rhs.type()) { // values might both point to s_void if lhs and rhs are "empty" return lhs.value() == rhs.value() || lhs.type()->equals(lhs.value(), rhs.value()); @@ -109,18 +98,15 @@ bool operator==(const object& lhs, const object& rhs) return false; } -uniform_type_info const* object::type() const -{ +const uniform_type_info* object::type() const { return m_type; } -void const* object::value() const -{ +const void* object::value() const { return m_value; } -void* object::mutable_value() -{ +void* object::mutable_value() { return m_value; } diff --git a/src/object_array.cpp b/src/object_array.cpp index 76345f8010..e191932ad3 100644 --- a/src/object_array.cpp +++ b/src/object_array.cpp @@ -32,42 +32,34 @@ namespace cppa { namespace detail { -object_array::object_array() : super(tuple_impl_info::dynamically_typed) -{ +object_array::object_array() : super(tuple_impl_info::dynamically_typed) { } -void object_array::push_back(const object& what) -{ +void object_array::push_back(const object& what) { m_elements.push_back(what); } -void object_array::push_back(object&& what) -{ +void object_array::push_back(object&& what) { m_elements.push_back(std::move(what)); } -void* object_array::mutable_at(size_t pos) -{ +void* object_array::mutable_at(size_t pos) { return m_elements[pos].mutable_value(); } -size_t object_array::size() const -{ +size_t object_array::size() const { return m_elements.size(); } -abstract_tuple* object_array::copy() const -{ +abstract_tuple* object_array::copy() const { return new object_array(*this); } -void const* object_array::at(size_t pos) const -{ +const void* object_array::at(size_t pos) const { return m_elements[pos].value(); } -uniform_type_info const* object_array::type_at(size_t pos) const -{ +const uniform_type_info* object_array::type_at(size_t pos) const { return m_elements[pos].type(); } diff --git a/src/partial_function.cpp b/src/partial_function.cpp index 2baffdc97d..84d8b66458 100644 --- a/src/partial_function.cpp +++ b/src/partial_function.cpp @@ -33,16 +33,9 @@ #include "cppa/config.hpp" #include "cppa/behavior.hpp" #include "cppa/partial_function.hpp" -#include "cppa/detail/invokable.hpp" namespace cppa { -partial_function::partial_function(impl_ptr&& ptr) : m_impl(std::move(ptr)) -{ -} - -partial_function::impl::~impl() -{ -} +partial_function::partial_function(impl_ptr&& ptr) : m_impl(std::move(ptr)) { } } // namespace cppa diff --git a/src/pattern.cpp b/src/pattern.cpp index 95c8932959..9fa3a414f8 100644 --- a/src/pattern.cpp +++ b/src/pattern.cpp @@ -34,8 +34,7 @@ namespace cppa { value_matcher::~value_matcher() { } -bool dummy_matcher::operator()(const any_tuple&) const -{ +bool dummy_matcher::operator()(const any_tuple&) const { return true; } diff --git a/src/post_office.cpp b/src/post_office.cpp index 011e1427f5..b0889cf253 100644 --- a/src/post_office.cpp +++ b/src/post_office.cpp @@ -31,32 +31,31 @@ #include // placement new #include // ios_base::failure #include // std::list +#include #include // std::vector +#include #include // strerror #include // std::uint32_t, std::uint64_t #include // std::cout, std::cerr, std::endl #include // std::logic_error #include // std::find_if #include // std::underflow_error -#include #include #include #include #include #include +#include -// used cppa classes +#include "cppa/cppa.hpp" #include "cppa/atom.hpp" +#include "cppa/match.hpp" +#include "cppa/config.hpp" #include "cppa/to_string.hpp" #include "cppa/deserializer.hpp" #include "cppa/binary_deserializer.hpp" -// used cppa intrusive containers -#include "cppa/intrusive/single_reader_queue.hpp" - -// used cppa details -#include "cppa/detail/thread.hpp" #include "cppa/detail/buffer.hpp" #include "cppa/detail/mailman.hpp" #include "cppa/detail/types_array.hpp" @@ -64,20 +63,19 @@ #include "cppa/detail/native_socket.hpp" #include "cppa/detail/actor_registry.hpp" #include "cppa/detail/network_manager.hpp" -#include "cppa/detail/post_office_msg.hpp" #include "cppa/detail/singleton_manager.hpp" #include "cppa/detail/actor_proxy_cache.hpp" #include "cppa/detail/addressed_message.hpp" -/* #define DEBUG(arg) \ std::cout << "[process id: " \ << cppa::process_information::get()->process_id() \ << "] " << arg << std::endl -//*/ +#undef DEBUG #define DEBUG(unused) ((void) 0) +using std::cout; using std::cerr; using std::endl; @@ -97,25 +95,66 @@ static_assert((s_max_buffer_size % s_chunk_size) == 0, static_assert(sizeof(cppa::detail::native_socket_type) == sizeof(std::uint32_t), "sizeof(native_socket_t) != sizeof(std::uint32_t)"); -constexpr int s_rdflag = MSG_DONTWAIT; - } // namespace namespace cppa { namespace detail { -intrusive::single_reader_queue& mailman_queue() -{ - return singleton_manager::get_network_manager()->mailman_queue(); +inline void send2po_(network_manager*) { } + +template +inline void send2po_(network_manager* nm, Arg0&& arg0, Args&&... args) { + nm->send_to_post_office(make_any_tuple(std::forward(arg0), + std::forward(args)...)); +} + + +template +inline void send2po(const po_message& msg, Args&&... args) { + auto nm = singleton_manager::get_network_manager(); + nm->send_to_post_office(msg); + send2po_(nm, std::forward(args)...); } -class po_doorman; +template +struct scope_guard { + Fun m_fun; + scope_guard(Fun&& fun) : m_fun(fun) { } + ~scope_guard() { m_fun(); } +}; + +template +scope_guard make_scope_guard(Fun fun) { return {std::move(fun)}; } + +class po_socket_handler { + + public: + + po_socket_handler(native_socket_type fd) : m_socket(fd) { } + + virtual ~po_socket_handler() { } + + // returns bool if either done or an error occured + virtual bool read_and_continue() = 0; + + native_socket_type get_socket() const { + return m_socket; + } + + virtual bool is_doorman_of(actor_id) const { return false; } + + protected: + + native_socket_type m_socket; + +}; + +typedef std::unique_ptr po_socket_handler_ptr; +typedef std::vector po_socket_handler_vector; // represents a TCP connection to another peer -class po_peer -{ +class po_peer : public po_socket_handler { - enum state - { + enum state { // connection just established; waiting for process information wait_for_process_info, // wait for the size of the next message @@ -125,636 +164,325 @@ class po_peer }; state m_state; - // TCP socket to remote peer - native_socket_type m_socket; - // TCP socket identifying our parent (that accepted m_socket) - native_socket_type m_parent_socket; // caches process_information::get() process_information_ptr m_pself; - // the process information or our remote peer + // the process information of our remote peer process_information_ptr m_peer; - std::unique_ptr m_observer; - buffer m_rdbuf; - std::list m_children; - + // caches uniform_typeid() const uniform_type_info* m_meta_msg; + // manages socket input + buffer<512, (16 * 1024 * 1024)> m_buf; public: - explicit po_peer(post_office_msg::add_peer& from) - : m_state(wait_for_msg_size) - , m_socket(from.sockfd) - , m_parent_socket(-1) - , m_pself(process_information::get()) - , m_peer(std::move(from.peer)) - , m_observer(std::move(from.attachable_ptr)) - , m_meta_msg(uniform_typeid()) - { - } - - explicit po_peer(native_socket_type sockfd, native_socket_type parent_socket) - : m_state(wait_for_process_info) - , m_socket(sockfd) - , m_parent_socket(parent_socket) - , m_pself(process_information::get()) - , m_meta_msg(uniform_typeid()) - { - m_rdbuf.reset( sizeof(std::uint32_t) - + process_information::node_id_size); - } - - po_peer(po_peer&& other) - : m_state(other.m_state) - , m_socket(other.m_socket) - , m_parent_socket(other.m_parent_socket) + po_peer(native_socket_type fd, process_information_ptr peer = nullptr) + : po_socket_handler(fd) + , m_state((peer) ? wait_for_msg_size : wait_for_process_info) , m_pself(process_information::get()) - , m_peer(std::move(other.m_peer)) - , m_observer(std::move(other.m_observer)) - , m_rdbuf(std::move(other.m_rdbuf)) - , m_children(std::move(other.m_children)) - , m_meta_msg(other.m_meta_msg) - { - other.m_socket = -1; - other.m_parent_socket = -1; - // other.m_children.clear(); - } - - native_socket_type get_socket() const - { - return m_socket; - } - - // returns true if @p pod is the parent of this - inline bool parent_exited(const po_doorman& pod); - - void add_child(const actor_proxy_ptr& pptr) - { - CPPA_REQUIRE(pptr.get() != nullptr); - if (pptr) m_children.push_back(pptr); - } - - inline size_t children_count() const - { - return m_children.size(); + , m_peer(std::move(peer)) + , m_meta_msg(uniform_typeid()) { + m_buf.reset(m_state == wait_for_process_info + ? sizeof(std::uint32_t) + process_information::node_id_size + : sizeof(std::uint32_t)); } - inline bool has_parent() const - { - return m_parent_socket != -1; - } - - // removes pptr from the list of children and returns - // a pair, whereas: first = true if pptr is a child of this - // second = number of remaining children - std::pair remove_child(const actor_proxy_ptr& pptr) - { - auto end = m_children.end(); - auto i = std::find(m_children.begin(), end, pptr); - if (i != end) - { - m_children.erase(i); - return { true, m_children.size() }; - } - return { false, m_children.size() }; - } - - - ~po_peer() - { - if (!m_children.empty()) - { - auto msg = make_cow_tuple(atom(":KillProxy"), - exit_reason::remote_link_unreachable); - for (actor_proxy_ptr& pptr : m_children) - { - pptr->enqueue(nullptr, msg); + ~po_peer() { + closesocket(m_socket); + if (m_peer) { + // collect all children (proxies to actors of m_peer) + std::vector children; + children.reserve(20); + get_actor_proxy_cache().erase_all(m_peer->node_id(), + m_peer->process_id(), + [&](actor_proxy_ptr& pptr) { + children.push_back(std::move(pptr)); + }); + // kill all proxies + for (actor_proxy_ptr& pptr: children) { + pptr->enqueue(nullptr, + make_any_tuple(atom("KILL_PROXY"), + exit_reason::remote_link_unreachable)); } } - if (m_socket != -1) closesocket(m_socket); } + inline native_socket_type get_socket() const { return m_socket; } + // @returns false if an error occured; otherwise true - bool read_and_continue() - { - static constexpr size_t wfp_size = sizeof(std::uint32_t) - + process_information::node_id_size; - switch (m_state) - { - case wait_for_process_info: - { - if (m_rdbuf.final_size() != wfp_size) - { - m_rdbuf.reset(wfp_size); - } - if (m_rdbuf.append_from(m_socket, s_rdflag) == false) - { - return false; - } - if (m_rdbuf.ready() == false) - { - break; - } - else - { + bool read_and_continue() { + for (;;) { + if (m_buf.append_from(m_socket) == false) { + DEBUG("cannot read from socket"); + return false; + } + if (m_buf.ready() == false) { + return true; // try again later + } + switch (m_state) { + case wait_for_process_info: { std::uint32_t process_id; - memcpy(&process_id, m_rdbuf.data(), sizeof(std::uint32_t)); process_information::node_id_type node_id; - memcpy(node_id.data(), - m_rdbuf.data() + sizeof(std::uint32_t), + memcpy(&process_id, m_buf.data(), sizeof(std::uint32_t)); + memcpy(node_id.data(), m_buf.data() + sizeof(std::uint32_t), process_information::node_id_size); m_peer.reset(new process_information(process_id, node_id)); // inform mailman about new peer - mailman_queue().push_back(new mailman_job(m_socket, - m_peer)); - m_rdbuf.reset(); + singleton_manager::get_network_manager() + ->send_to_mailman(make_any_tuple(m_socket, m_peer)); m_state = wait_for_msg_size; + m_buf.reset(sizeof(std::uint32_t)); DEBUG("pinfo read: " << m_peer->process_id() << "@" << to_string(m_peer->node_id())); - // fall through and try to read more from socket - } - } - case wait_for_msg_size: - { - if (m_rdbuf.final_size() != sizeof(std::uint32_t)) - { - m_rdbuf.reset(sizeof(std::uint32_t)); - } - if (!m_rdbuf.append_from(m_socket, s_rdflag)) return false; - if (m_rdbuf.ready() == false) - { break; } - else - { - // read and set message size + case wait_for_msg_size: { std::uint32_t msg_size; - memcpy(&msg_size, m_rdbuf.data(), sizeof(std::uint32_t)); - m_rdbuf.reset(msg_size); + memcpy(&msg_size, m_buf.data(), sizeof(std::uint32_t)); + m_buf.reset(msg_size); m_state = read_message; - // fall through and try to read more from socket - } - } - case read_message: - { - if (!m_rdbuf.append_from(m_socket, s_rdflag)) - { - // could not read from socket - return false; - } - if (m_rdbuf.ready() == false) - { - // wait for new data break; } - addressed_message msg; - binary_deserializer bd(m_rdbuf.data(), m_rdbuf.size()); - try - { - m_meta_msg->deserialize(&msg, &bd); - } - catch (std::exception& e) - { - // unable to deserialize message (format error) - DEBUG(to_uniform_name(typeid(e)) << ": " << e.what()); - return false; - } - auto& content = msg.content(); - DEBUG("<-- " << to_string(content)); - // intercept ":Monitor" messages - if ( content.size() == 1 - && t_atom_actor_ptr_types[0] == content.type_at(0) - && content.get_as(0) == atom(":Monitor")) - { - auto receiver = msg.receiver().downcast(); - CPPA_REQUIRE(receiver.get() != nullptr); - if (!receiver) - { - DEBUG("empty receiver"); - } - else if (receiver->parent_process() == *process_information::get()) - { - //cout << pinfo << " ':Monitor'; actor id = " - // << sender->id() << endl; - // local actor? - // this message was send from a proxy - receiver->attach_functor([=](std::uint32_t reason) - { - any_tuple kmsg = make_cow_tuple(atom(":KillProxy"), - reason); - auto mjob = new detail::mailman_job(m_peer, - receiver, - receiver, - kmsg); - detail::mailman_queue().push_back(mjob); - }); + case read_message: { + addressed_message msg; + binary_deserializer bd(m_buf.data(), m_buf.size()); + try { + m_meta_msg->deserialize(&msg, &bd); } - else - { - DEBUG(":Monitor received for an remote actor"); + catch (std::exception& e) { + // unable to deserialize message (format error) + DEBUG(to_uniform_name(typeid(e)) << ": " << e.what()); + return false; } + auto& content = msg.content(); + DEBUG("<-- " << to_string(msg)); + match(content) ( + on(atom("MONITOR")) >> [&]() { + auto receiver = msg.receiver().downcast(); + CPPA_REQUIRE(receiver.get() != nullptr); + if (!receiver) { + DEBUG("empty receiver"); + } + else if (receiver->parent_process() == *process_information::get()) { + // this message was send from a proxy + receiver->attach_functor([=](std::uint32_t reason) { + addressed_message kmsg{receiver, receiver, make_any_tuple(atom("KILL_PROXY"), reason)}; + singleton_manager::get_network_manager() + ->send_to_mailman(make_any_tuple(m_peer, kmsg)); + }); + } + else { + DEBUG("MONITOR received for a remote actor"); + } + }, + on(atom("LINK"), arg_match) >> [&](actor_ptr ptr) { + if (msg.sender()->is_proxy() == false) { + DEBUG("msg.sender() is not a proxy"); + return; + } + auto whom = msg.sender().downcast(); + if ((whom) && (ptr)) whom->local_link_to(ptr); + }, + on(atom("UNLINK"), arg_match) >> [](actor_ptr ptr) { + if (ptr->is_proxy() == false) { + DEBUG("msg.sender() is not a proxy"); + return; + } + auto whom = ptr.downcast(); + if ((whom) && (ptr)) whom->local_unlink_from(ptr); + }, + others() >> [&]() { + if (msg.receiver()) { + msg.receiver()->enqueue(msg.sender().get(), + std::move(msg.content())); + } + else { + DEBUG("empty receiver"); + } + } + ); + m_buf.reset(sizeof(std::uint32_t)); + m_state = wait_for_msg_size; + break; } - // intercept ":Link" messages - else if ( content.size() == 2 - && t_atom_actor_ptr_types[0] == content.type_at(0) - && t_atom_actor_ptr_types[1] == content.type_at(1) - && content.get_as(0) == atom(":Link")) - { - CPPA_REQUIRE(msg.sender()->is_proxy()); - auto whom = msg.sender().downcast(); - auto to = content.get_as(1); - if ((whom) && (to)) - whom->local_link_to(to); - } - // intercept ":Unlink" messages - else if ( content.size() == 2 - && t_atom_actor_ptr_types[0] == content.type_at(0) - && t_atom_actor_ptr_types[1] == content.type_at(1) - && content.get_as(0) == atom(":Link")) - { - CPPA_REQUIRE(msg.sender()->is_proxy()); - auto whom = msg.sender().downcast(); - auto from = content.get_as(1); - if ((whom) && (from)) - whom->local_unlink_from(from); + default: { + CPPA_CRITICAL("illegal state"); } - else - { - if (msg.receiver()) - { - msg.receiver()->enqueue(msg.sender().get(), - std::move(msg.content())); - } - else - { - DEBUG("empty receiver"); - } - } - m_rdbuf.reset(); - m_state = wait_for_msg_size; - break; - } - default: - { - throw std::logic_error("illegal state"); } + // try to read more (next iteration) } - return true; } }; // accepts new connections to a published actor -class po_doorman -{ +class po_doorman : public po_socket_handler { - // server socket - native_socket_type m_socket; - actor_ptr published_actor; - std::list* m_peers; + actor_id m_actor_id; // caches process_information::get() process_information_ptr m_pself; + po_socket_handler_vector* new_handler; public: - explicit po_doorman(post_office_msg::add_server_socket& assm, - std::list* peers) - : m_socket(assm.server_sockfd) - , published_actor(assm.published_actor) - , m_peers(peers) - , m_pself(process_information::get()) - { + po_doorman(actor_id aid, native_socket_type fd, po_socket_handler_vector* v) + : po_socket_handler(fd) + , m_actor_id(aid), m_pself(process_information::get()) + , new_handler(v) { } - ~po_doorman() - { - if (m_socket != -1) closesocket(m_socket); + bool is_doorman_of(actor_id aid) const { + return m_actor_id == aid; } - po_doorman(po_doorman&& other) - : m_socket(other.m_socket) - , published_actor(std::move(other.published_actor)) - , m_peers(other.m_peers) - , m_pself(process_information::get()) - { - other.m_socket = -1; + ~po_doorman() { + closesocket(m_socket); } - inline native_socket_type get_socket() const - { - return m_socket; - } - - // @returns false if an error occured; otherwise true - bool read_and_continue() - { - sockaddr addr; - socklen_t addrlen; - memset(&addr, 0, sizeof(addr)); - memset(&addrlen, 0, sizeof(addrlen)); - auto sfd = ::accept(m_socket, &addr, &addrlen); - if (sfd < 0) - { - switch (errno) - { - case EAGAIN: -# if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -# endif - { - // just try again - return true; + bool read_and_continue() { + for (;;) { + sockaddr addr; + socklen_t addrlen; + memset(&addr, 0, sizeof(addr)); + memset(&addrlen, 0, sizeof(addrlen)); + auto sfd = ::accept(m_socket, &addr, &addrlen); + if (sfd < 0) { + switch (errno) { + case EAGAIN: +# if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +# endif + // just try again + return true; + default: + perror("accept()"); + DEBUG("accept failed (actor unpublished?)"); + return false; } - default: return false; } + int flags = 1; + setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(int)); + flags = fcntl(sfd, F_GETFL, 0); + if (flags == -1) { + throw network_error("unable to get socket flags"); + } + if (fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) { + throw network_error("unable to set socket to nonblock"); + } + auto id = m_actor_id; + std::uint32_t process_id = m_pself->process_id(); + ::send(sfd, &id, sizeof(std::uint32_t), 0); + ::send(sfd, &process_id, sizeof(std::uint32_t), 0); + ::send(sfd, m_pself->node_id().data(), m_pself->node_id().size(), 0); + new_handler->emplace_back(new po_peer(sfd)); + DEBUG("socket accepted; published actor: " << id); } - auto id = published_actor->id(); - std::uint32_t process_id = m_pself->process_id(); - ::send(sfd, &id, sizeof(std::uint32_t), 0); - ::send(sfd, &process_id, sizeof(std::uint32_t), 0); - ::send(sfd, m_pself->node_id().data(), m_pself->node_id().size(), 0); - m_peers->push_back(po_peer(sfd, m_socket)); - DEBUG("socket accepted; published actor: " << id); - return true; } }; -inline bool po_peer::parent_exited(const po_doorman& pod) -{ - if (m_parent_socket == pod.get_socket()) - { - m_parent_socket = -1; - return true; - } - return false; +inline constexpr std::uint64_t valof(atom_value val) { + return static_cast(val); } -// starts and stops mailman_loop -struct mailman_worker -{ - thread m_thread; - mailman_worker() : m_thread(mailman_loop) - { - } - ~mailman_worker() - { - mailman_queue().push_back(mailman_job::kill_job()); - m_thread.join(); - } -}; - -void post_office_loop(int pipe_read_handle, int pipe_write_handle) -{ - mailman_worker mworker; - // map of all published actors (actor_id => list) - std::map > doormen; - // list of all connected peers - std::list peers; - // readset for select() - fd_set readset; - // maximum number of all socket descriptors for select() +void post_office_loop(int input_fd) { int maxfd = 0; - // initialize variables for select() - FD_ZERO(&readset); - maxfd = pipe_read_handle; - FD_SET(pipe_read_handle, &readset); - // keeps track about what peer we are iterating at the moment - po_peer* selected_peer = nullptr; - // our event queue - auto& msg_queue = singleton_manager::get_network_manager()->post_office_queue(); - auto pself = process_information::get(); - // needed for lookups in our proxy cache - actor_proxy_cache::key_tuple proxy_cache_key ( 0, // set on lookup - pself->process_id(), - pself->node_id() ); - // initialize proxy cache - get_actor_proxy_cache().set_new_proxy_callback([&](actor_proxy_ptr& pptr) - { - DEBUG("new_proxy_callback, actor id = " << pptr->id()); - // it's ok to access objects on the stack, since this callback - // is guaranteed to be executed in the same thread - if (selected_peer == nullptr) - { - if (!pptr) DEBUG("pptr == nullptr"); - throw std::logic_error("selected_peer == nullptr"); + fd_set readset; + bool done = false; + po_socket_handler_vector handler; + po_socket_handler_vector new_handler; + do { + FD_ZERO(&readset); + FD_SET(input_fd, &readset); + maxfd = input_fd; + for (auto& hptr : handler) { + auto fd = hptr->get_socket(); + maxfd = std::max(maxfd, fd); + FD_SET(fd, &readset); } - pptr->enqueue(nullptr, make_cow_tuple(atom(":Monitor"))); - selected_peer->add_child(pptr); - auto aid = pptr->id(); - auto pptr_copy = pptr; - pptr->attach_functor([&msg_queue,aid,pipe_write_handle,pptr_copy] (std::uint32_t) - { - // this callback is not guaranteed to be executed in the same thread - msg_queue.push_back(new post_office_msg(pptr_copy)); - pipe_msg msg = { rd_queue_event, 0 }; - if (write(pipe_write_handle, msg, pipe_msg_size) != (int) pipe_msg_size) - { - cerr << "FATAL: cannot write to pipe" << endl; - abort(); - } - }); - }); - for (;;) - { - if (select(maxfd + 1, &readset, nullptr, nullptr, nullptr) < 0) - { + if (select(maxfd + 1, &readset, nullptr, nullptr, nullptr) < 0) { // must not happen + DEBUG("select failed!"); perror("select()"); exit(3); } - // iterate over all peers and remove peers on errors - peers.remove_if([&](po_peer& peer) -> bool - { - if (FD_ISSET(peer.get_socket(), &readset)) - { - selected_peer = &peer; - return peer.read_and_continue() == false; + { // iterate over all handler and remove if needed + auto i = handler.begin(); + while (i != handler.end()) { + if ( FD_ISSET((*i)->get_socket(), &readset) + && (*i)->read_and_continue() == false) { + DEBUG("handler erased"); + i = handler.erase(i); + } + else { + ++i; + } } - return false; - }); - selected_peer = nullptr; - // iterate over all doormen (accept new connections) - // and remove doormen on errors - for (auto& kvp : doormen) - { - // iterate over all doormen and remove doormen on error - kvp.second.remove_if([&](po_doorman& doorman) -> bool - { - return FD_ISSET(doorman.get_socket(), &readset) - && doorman.read_and_continue() == false; - }); } - // read events from pipe - if (FD_ISSET(pipe_read_handle, &readset)) - { - pipe_msg pmsg; - //memcpy(pmsg, pipe_msg_buf.data(), pipe_msg_buf.size()); - //pipe_msg_buf.clear(); - if (::read(pipe_read_handle, &pmsg, pipe_msg_size) != (int) pipe_msg_size) - { - cerr << "FATAL: cannot read from pipe" << endl; - abort(); + if (FD_ISSET(input_fd, &readset)) { + DEBUG("post_office: read from pipe"); + po_message msg; + if (read(input_fd, &msg, sizeof(po_message)) != sizeof(po_message)) { + CPPA_CRITICAL("cannot read from pipe"); } - switch (pmsg[0]) - { - case rd_queue_event: - { - DEBUG("rd_queue_event"); - std::unique_ptr pom{msg_queue.pop()}; - if (pom->is_add_peer_msg()) - { - DEBUG("add_peer_msg"); - auto& apm = pom->as_add_peer_msg(); - actor_proxy_ptr pptr = apm.first_peer_actor; - peers.push_back(po_peer(apm)); - selected_peer = &(peers.back()); - if (pptr) - { - DEBUG("proxy added via post_office_msg"); - get_actor_proxy_cache().add(pptr); - } - selected_peer = nullptr; - } - else if (pom->is_add_server_socket_msg()) - { - DEBUG("add_server_socket_msg"); - auto& assm = pom->as_add_server_socket_msg(); - auto& pactor = assm.published_actor; - if (pactor) - { - auto aid = pactor->id(); - auto callback = [aid](std::uint32_t) - { - DEBUG("call post_office_unpublish() ..."); - post_office_unpublish(aid); - }; - if (pactor->attach_functor(std::move(callback))) - { - auto& dm = doormen[aid]; - dm.push_back(po_doorman(assm, &peers)); - DEBUG("new doorman"); - } - } - else - { - DEBUG("nullptr published"); + switch (valof(msg.flag)) { + case valof(atom("ADD_PEER")): { + receive ( + on_arg_match >> [&](native_socket_type fd, + process_information_ptr piptr) { + DEBUG("post_office: add_peer"); + handler.emplace_back(new po_peer(fd, piptr)); } - } - else if (pom->is_proxy_exited_msg()) - { - DEBUG("proxy_exited_msg"); - auto pptr = std::move(pom->as_proxy_exited_msg().proxy_ptr); - if (pptr) - { - // get parent of pptr - auto i = peers.begin(); - auto end = peers.end(); - DEBUG("search parent of exited proxy"); - while (i != end) - { - auto result = i->remove_child(pptr); - if (result.first) // true if pptr is a child - { - DEBUG("found parent of proxy"); - if (result.second == 0) // no more children? - { - // disconnect peer if we don't know any - // actor of it and if the published - // actor already exited - // (this is the case if the peer doesn't - // have a parent) - if (i->has_parent() == false) - { - DEBUG("removed peer"); - peers.erase(i); - } - } - i = end; // done - } - else - { - DEBUG("... next iteration"); - ++i; // next iteration - } - } - } - else DEBUG("pptr == nullptr"); - } + ); + break; + } + case valof(atom("RM_PEER")): { + DEBUG("post_office: rm_peer"); + auto i = std::find_if(handler.begin(), handler.end(), + [&](const po_socket_handler_ptr& hp) { + return hp->get_socket() == msg.fd; + }); + if (i != handler.end()) handler.erase(i); break; } - case unpublish_actor_event: - { - DEBUG("unpublish_actor_event"); - auto kvp = doormen.find(pmsg[1]); - if (kvp != doormen.end()) - { - DEBUG("erase doorman from map"); - for (po_doorman& dm : kvp->second) - { - // remove peers with no children and no parent - // (that are peers that connected to an already - // exited actor and where we don't know any - // actor from) - peers.remove_if([&](po_peer& ppeer) - { - return ppeer.parent_exited(dm) - && ppeer.children_count() == 0; - }); + case valof(atom("PUBLISH")): { + receive ( + on_arg_match >> [&](native_socket_type sockfd, + actor_ptr whom) { + DEBUG("post_office: publish_actor"); + CPPA_REQUIRE(sockfd > 0); + CPPA_REQUIRE(whom.get() != nullptr); + handler.emplace_back(new po_doorman(whom->id(), sockfd, &new_handler)); } - doormen.erase(kvp); - } + ); break; } - case close_socket_event: - { - DEBUG("close_socket_event"); - auto sockfd = static_cast(pmsg[1]); - auto end = peers.end(); - auto i = std::find_if(peers.begin(), end, - [sockfd](po_peer& peer) -> bool - { - return peer.get_socket() == sockfd; + case valof(atom("UNPUBLISH")): { + DEBUG("post_office: unpublish_actor"); + auto i = std::find_if(handler.begin(), handler.end(), + [&](const po_socket_handler_ptr& hp) { + return hp->is_doorman_of(msg.aid); }); - if (i != end) peers.erase(i); + if (i != handler.end()) handler.erase(i); break; } - case shutdown_event: - { - // goodbye - return; + case valof(atom("DONE")): { + done = true; + break; } - default: - { - std::ostringstream oss; - oss << "unexpected event type: " << pmsg[0]; - throw std::logic_error(oss.str()); + default: { + CPPA_CRITICAL("illegal pipe message"); } } } - // recalculate readset - FD_ZERO(&readset); - FD_SET(pipe_read_handle, &readset); - maxfd = pipe_read_handle; - for (po_peer& pd : peers) - { - auto fd = pd.get_socket(); - if (fd > maxfd) maxfd = fd; - FD_SET(fd, &readset); - } - // iterate over key-value (actor id / doormen) pairs - for (auto& kvp : doormen) - { - // iterate over values (doormen) - for (auto& dm : kvp.second) - { - auto fd = dm.get_socket(); - if (fd > maxfd) maxfd = fd; - FD_SET(fd, &readset); - } + if (new_handler.empty() == false) { + std::move(new_handler.begin(), new_handler.end(), + std::back_inserter(handler)); + new_handler.clear(); } } + while (done == false); } /****************************************************************************** @@ -763,41 +491,25 @@ void post_office_loop(int pipe_read_handle, int pipe_write_handle) ******************************************************************************/ void post_office_add_peer(native_socket_type a0, - const process_information_ptr& a1, - const actor_proxy_ptr& a2, - std::unique_ptr&& a3) -{ - auto nm = singleton_manager::get_network_manager(); - nm->post_office_queue().push_back(new post_office_msg(a0, a1, a2, - std::move(a3))); - pipe_msg msg = { rd_queue_event, 0 }; - nm->write_to_pipe(msg); + const process_information_ptr& a1) { + po_message msg{atom("ADD_PEER"), -1, 0}; + send2po(msg, a0, a1); } void post_office_publish(native_socket_type server_socket, - const actor_ptr& published_actor) -{ - DEBUG("post_office_publish(" << published_actor->id() << ")"); - auto nm = singleton_manager::get_network_manager(); - nm->post_office_queue().push_back(new post_office_msg(server_socket, - published_actor)); - pipe_msg msg = { rd_queue_event, 0 }; - nm->write_to_pipe(msg); + const actor_ptr& published_actor) { + po_message msg{atom("PUBLISH"), -1, 0}; + send2po(msg, server_socket, published_actor); } -void post_office_unpublish(actor_id whom) -{ - DEBUG("post_office_unpublish(" << whom << ")"); - auto nm = singleton_manager::get_network_manager(); - pipe_msg msg = { unpublish_actor_event, whom }; - nm->write_to_pipe(msg); +void post_office_unpublish(actor_id whom) { + po_message msg{atom("UNPUBLISH"), -1, whom}; + send2po(msg); } -void post_office_close_socket(native_socket_type sfd) -{ - auto nm = singleton_manager::get_network_manager(); - pipe_msg msg = { close_socket_event, static_cast(sfd) }; - nm->write_to_pipe(msg); +void post_office_close_socket(native_socket_type sfd) { + po_message msg{atom("RM_PEER"), sfd, 0}; + send2po(msg); } } } // namespace cppa::detail diff --git a/src/primitive_variant.cpp b/src/primitive_variant.cpp index 89f08e28e6..52ac329c49 100644 --- a/src/primitive_variant.cpp +++ b/src/primitive_variant.cpp @@ -39,95 +39,79 @@ namespace { template void ptv_del(T&, - typename std::enable_if::value>::type* = 0) -{ + typename std::enable_if::value>::type* = 0) { // arithmetic types don't need destruction } template void ptv_del(T& what, - typename std::enable_if::value>::type* = 0) -{ + typename std::enable_if::value>::type* = 0) { what.~T(); } -struct destroyer -{ +struct destroyer { template - inline void operator()(T& what) const - { + inline void operator()(T& what) const { ptv_del(what); } }; -struct type_reader -{ +struct type_reader { const std::type_info* tinfo; type_reader() : tinfo(nullptr) { } template - void operator()(const T&) - { + void operator()(const T&) { tinfo = &typeid(T); } }; -struct comparator -{ +struct comparator { bool result; const primitive_variant& lhs; const primitive_variant& rhs; comparator(const primitive_variant& pv1, const primitive_variant& pv2) - : result(false), lhs(pv1), rhs(pv2) - { + : result(false), lhs(pv1), rhs(pv2) { } template - void operator()(util::pt_token) - { - if (rhs.ptype() == PT) - { + void operator()(util::pt_token) { + if (rhs.ptype() == PT) { result = (get(lhs) == get(rhs)); } } }; -struct initializer -{ +struct initializer { primitive_variant& lhs; inline initializer(primitive_variant& pv) : lhs(pv) { } template - inline void operator()(util::pt_token) - { + inline void operator()(util::pt_token) { typedef typename detail::ptype_to_type::type T; lhs = T(); } }; -struct setter -{ +struct setter { primitive_variant& lhs; setter(primitive_variant& pv) : lhs(pv) { } template - inline void operator()(const T& rhs) - { + inline void operator()(const T& rhs) { lhs = rhs; } }; -struct mover -{ +struct mover { primitive_variant& lhs; mover(primitive_variant& pv) : lhs(pv) { } template - inline void operator()(T& rhs) - { + inline void operator()(T& rhs) { lhs = std::move(rhs); } }; @@ -136,56 +120,47 @@ struct mover primitive_variant::primitive_variant() : m_ptype(pt_null) { } -primitive_variant::primitive_variant(primitive_type ptype) : m_ptype(pt_null) -{ +primitive_variant::primitive_variant(primitive_type ptype) : m_ptype(pt_null) { util::pt_dispatch(ptype, initializer(*this)); } primitive_variant::primitive_variant(const primitive_variant& other) - : m_ptype(pt_null) -{ + : m_ptype(pt_null) { other.apply(setter(*this)); } primitive_variant::primitive_variant(primitive_variant&& other) - : m_ptype(pt_null) -{ + : m_ptype(pt_null) { other.apply(mover(*this)); } -primitive_variant& primitive_variant::operator=(const primitive_variant& other) -{ +primitive_variant& primitive_variant::operator=(const primitive_variant& other) { other.apply(setter(*this)); return *this; } -primitive_variant& primitive_variant::operator=(primitive_variant&& other) -{ +primitive_variant& primitive_variant::operator=(primitive_variant&& other) { other.apply(mover(*this)); return *this; } -bool operator==(const primitive_variant& lhs, const primitive_variant& rhs) -{ +bool equal(const primitive_variant& lhs, const primitive_variant& rhs) { comparator cmp(lhs, rhs); util::pt_dispatch(lhs.m_ptype, cmp); return cmp.result; } -const std::type_info& primitive_variant::type() const -{ +const std::type_info& primitive_variant::type() const { type_reader tr; apply(tr); return (tr.tinfo == nullptr) ? typeid(void) : *tr.tinfo; } -primitive_variant::~primitive_variant() -{ +primitive_variant::~primitive_variant() { destroy(); } -void primitive_variant::destroy() -{ +void primitive_variant::destroy() { apply(destroyer()); m_ptype = pt_null; } diff --git a/src/process_information.cpp b/src/process_information.cpp index 0a2b993570..e55a75a6b8 100644 --- a/src/process_information.cpp +++ b/src/process_information.cpp @@ -43,10 +43,8 @@ namespace { -inline void erase_trailing_newline(std::string& str) -{ - while (!str.empty() && (*str.rbegin()) == '\n') - { +inline void erase_trailing_newline(std::string& str) { + while (!str.empty() && (*str.rbegin()) == '\n') { str.resize(str.size() - 1); } } @@ -71,22 +69,19 @@ const char* s_get_mac = "head -n1"; #endif -cppa::process_information* compute_proc_info() -{ +cppa::process_information* compute_proc_info() { char cbuf[100]; // fetch hd serial std::string hd_serial_and_mac_addr; FILE* get_uuid_cmd = popen(s_get_uuid, "r"); - while (fgets(cbuf, 100, get_uuid_cmd) != 0) - { + while (fgets(cbuf, 100, get_uuid_cmd) != 0) { hd_serial_and_mac_addr += cbuf; } pclose(get_uuid_cmd); erase_trailing_newline(hd_serial_and_mac_addr); // fetch mac address of first network device FILE* get_mac_cmd = popen(s_get_mac, "r"); - while (fgets(cbuf, 100, get_mac_cmd) != 0) - { + while (fgets(cbuf, 100, get_mac_cmd) != 0) { hd_serial_and_mac_addr += cbuf; } pclose(get_mac_cmd); @@ -98,32 +93,24 @@ cppa::process_information* compute_proc_info() cppa::process_information_ptr s_pinfo; -struct pinfo_manager -{ - pinfo_manager() - { - if (!s_pinfo) - { +struct pinfo_manager { + pinfo_manager() { + if (!s_pinfo) { s_pinfo.reset(compute_proc_info()); } } } s_pinfo_manager; -std::uint8_t hex_char_value(char c) -{ - if (isdigit(c)) - { +std::uint8_t hex_char_value(char c) { + if (isdigit(c)) { return static_cast(c - '0'); } - else if (isalpha(c)) - { - if (c >= 'a' && c <= 'f') - { + else if (isalpha(c)) { + if (c >= 'a' && c <= 'f') { return static_cast((c - 'a') + 10); } - else if (c >= 'A' && c <= 'F') - { + else if (c >= 'A' && c <= 'F') { return static_cast((c - 'A') + 10); } } @@ -135,15 +122,12 @@ std::uint8_t hex_char_value(char c) namespace cppa { void node_id_from_string(const std::string& hash, - process_information::node_id_type& node_id) -{ - if (hash.size() != (node_id.size() * 2)) - { + process_information::node_id_type& node_id) { + if (hash.size() != (node_id.size() * 2)) { throw std::invalid_argument("string argument is not a node id hash"); } auto j = hash.c_str(); - for (size_t i = 0; i < node_id.size(); ++i) - { + for (size_t i = 0; i < node_id.size(); ++i) { // read two characters, each representing 4 bytes auto& val = node_id[i]; val = hex_char_value(*j++) << 4; @@ -152,75 +136,61 @@ void node_id_from_string(const std::string& hash, } bool equal(const std::string& hash, - const process_information::node_id_type& node_id) -{ - if (hash.size() != (node_id.size() * 2)) - { + const process_information::node_id_type& node_id) { + if (hash.size() != (node_id.size() * 2)) { return false; } auto j = hash.c_str(); - try - { - for (size_t i = 0; i < node_id.size(); ++i) - { + try { + for (size_t i = 0; i < node_id.size(); ++i) { // read two characters, each representing 4 bytes std::uint8_t val; val = hex_char_value(*j++) << 4; val |= hex_char_value(*j++); - if (val != node_id[i]) - { + if (val != node_id[i]) { return false; } } } - catch (std::invalid_argument&) - { + catch (std::invalid_argument&) { return false; } return true; } process_information::process_information(const process_information& other) - : super(), m_process_id(other.process_id()), m_node_id(other.node_id()) -{ + : super(), m_process_id(other.process_id()), m_node_id(other.node_id()) { } process_information::process_information(std::uint32_t a, const std::string& b) - : m_process_id(a) -{ + : m_process_id(a) { node_id_from_string(b, m_node_id); } process_information::process_information(std::uint32_t a, const node_id_type& b) - : m_process_id(a), m_node_id(b) -{ + : m_process_id(a), m_node_id(b) { } -std::string to_string(const process_information::node_id_type& node_id) -{ +std::string to_string(const process_information::node_id_type& node_id) { std::ostringstream oss; oss << std::hex; oss.fill('0'); - for (size_t i = 0; i < process_information::node_id_size; ++i) - { + for (size_t i = 0; i < process_information::node_id_size; ++i) { oss.width(2); oss << static_cast(node_id[i]); } return oss.str(); } -const intrusive_ptr& process_information::get() -{ +const intrusive_ptr& process_information::get() { return s_pinfo; } -int process_information::compare(const process_information& other) const -{ - int tmp = strncmp(reinterpret_cast(node_id().data()), - reinterpret_cast(other.node_id().data()), +int process_information::compare(const process_information& other) const { + int tmp = strncmp(reinterpret_cast(node_id().data()), + reinterpret_cast(other.node_id().data()), node_id_size); - if (tmp == 0) - { + if (tmp == 0) { if (m_process_id < other.process_id()) return -1; else if (m_process_id == other.process_id()) return 0; return 1; @@ -228,8 +198,7 @@ int process_information::compare(const process_information& other) const return tmp; } -std::string to_string(const process_information& what) -{ +std::string to_string(const process_information& what) { std::ostringstream oss; oss << what.process_id() << "@" << to_string(what.node_id()); return oss.str(); diff --git a/src/receive.cpp b/src/receive.cpp index 69a725fede..3ac89f4d2a 100644 --- a/src/receive.cpp +++ b/src/receive.cpp @@ -32,20 +32,16 @@ namespace cppa { -void receive_loop(behavior& rules) -{ +void receive_loop(behavior& rules) { local_actor* sptr = self; - for (;;) - { + for (;;) { sptr->dequeue(rules); } } -void receive_loop(partial_function& rules) -{ +void receive_loop(partial_function& rules) { local_actor* sptr = self; - for (;;) - { + for (;;) { sptr->dequeue(rules); } } diff --git a/src/ripemd_160.cpp b/src/ripemd_160.cpp index 496b4f9b33..fd33201c8a 100644 --- a/src/ripemd_160.cpp +++ b/src/ripemd_160.cpp @@ -100,78 +100,67 @@ typedef std::uint32_t dword; #define J(x, y, z) ((x) ^ ((y) | ~(z))) // the ten basic operations FF() through III() -#define FF(a, b, c, d, e, x, s) \ - { \ - (a) += F((b), (c), (d)) + (x); \ - (a) = ROL((a), (s)) + (e); \ - (c) = ROL((c), 10); \ - } +#define FF(a, b, c, d, e, x, s) { \ + (a) += F((b), (c), (d)) + (x); \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} -#define GG(a, b, c, d, e, x, s) \ - { \ - (a) += G((b), (c), (d)) + (x) + 0x5a827999UL; \ - (a) = ROL((a), (s)) + (e); \ - (c) = ROL((c), 10); \ - } +#define GG(a, b, c, d, e, x, s) { \ + (a) += G((b), (c), (d)) + (x) + 0x5a827999UL; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} -#define HH(a, b, c, d, e, x, s) \ - { \ - (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL; \ - (a) = ROL((a), (s)) + (e); \ - (c) = ROL((c), 10); \ - } +#define HH(a, b, c, d, e, x, s) { \ + (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} -#define II(a, b, c, d, e, x, s) \ - { \ - (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL; \ - (a) = ROL((a), (s)) + (e); \ - (c) = ROL((c), 10); \ - } +#define II(a, b, c, d, e, x, s) { \ + (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} -#define JJ(a, b, c, d, e, x, s) \ - { \ - (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL; \ - (a) = ROL((a), (s)) + (e); \ - (c) = ROL((c), 10); \ - } +#define JJ(a, b, c, d, e, x, s) { \ + (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} -#define FFF(a, b, c, d, e, x, s) \ - { \ - (a) += F((b), (c), (d)) + (x); \ - (a) = ROL((a), (s)) + (e); \ - (c) = ROL((c), 10); \ - } +#define FFF(a, b, c, d, e, x, s) { \ + (a) += F((b), (c), (d)) + (x); \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} -#define GGG(a, b, c, d, e, x, s) \ - { \ - (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL; \ - (a) = ROL((a), (s)) + (e); \ - (c) = ROL((c), 10); \ - } +#define GGG(a, b, c, d, e, x, s) { \ + (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} -#define HHH(a, b, c, d, e, x, s) \ - { \ - (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL; \ - (a) = ROL((a), (s)) + (e); \ - (c) = ROL((c), 10); \ - } +#define HHH(a, b, c, d, e, x, s) { \ + (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} -#define III(a, b, c, d, e, x, s) \ - { \ - (a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL; \ - (a) = ROL((a), (s)) + (e); \ - (c) = ROL((c), 10); \ - } +#define III(a, b, c, d, e, x, s) { \ + (a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} -#define JJJ(a, b, c, d, e, x, s) \ - { \ - (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL; \ - (a) = ROL((a), (s)) + (e); \ - (c) = ROL((c), 10); \ - } +#define JJJ(a, b, c, d, e, x, s) { \ + (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL; \ + (a) = ROL((a), (s)) + (e); \ + (c) = ROL((c), 10); \ +} -void MDinit(dword* MDbuf) -{ +void MDinit(dword* MDbuf) { MDbuf[0] = 0x67452301UL; MDbuf[1] = 0xefcdab89UL; MDbuf[2] = 0x98badcfeUL; @@ -179,8 +168,7 @@ void MDinit(dword* MDbuf) MDbuf[4] = 0xc3d2e1f0UL; } -void compress(dword* MDbuf, dword* X) -{ +void compress(dword* MDbuf, dword* X) { // round 1-5 variables dword aa = MDbuf[0]; dword bb = MDbuf[1]; @@ -372,20 +360,17 @@ void compress(dword* MDbuf, dword* X) MDbuf[0] = ddd; } -void MDfinish(dword *MDbuf, const byte *strptr, dword lswlen, dword mswlen) -{ +void MDfinish(dword *MDbuf, const byte *strptr, dword lswlen, dword mswlen) { dword X[16]; // message words memset(X, 0, 16 * sizeof(dword)); // put bytes from strptr into X - for (unsigned int i = 0; i < (lswlen & 63); ++i) - { + for (unsigned int i = 0; i < (lswlen & 63); ++i) { // byte i goes into word X[i div 4] at pos. 8*(i mod 4) X[i>>2] ^= (dword) *strptr++ << (8 * (i&3)); } // append the bit m_n == 1 X[(lswlen>>2)&15] ^= (dword)1 << (8*(lswlen&3) + 7); - if ((lswlen & 63) > 55) - { + if ((lswlen & 63) > 55) { // length goes to next block compress(MDbuf, X); memset(X, 0, 16*sizeof(dword)); @@ -400,8 +385,7 @@ void MDfinish(dword *MDbuf, const byte *strptr, dword lswlen, dword mswlen) namespace cppa { namespace util { -void ripemd_160(std::array& storage, const std::string& data) -{ +void ripemd_160(std::array& storage, const std::string& data) { dword MDbuf[5]; // contains (A, B, C, D(, E)) dword X[16]; // current 16-word chunk dword length; // length in bytes of message @@ -413,10 +397,8 @@ void ripemd_160(std::array& storage, const std::string& data) length = data.size(); // process message in 16-word chunks - for (dword nbytes = length; nbytes > 63; nbytes -= 64) - { - for (dword i = 0; i < 16; ++i) - { + for (dword nbytes = length; nbytes > 63; nbytes -= 64) { + for (dword i = 0; i < 16; ++i) { X[i] = BYTES_TO_DWORD(message); message += 4; } @@ -427,8 +409,7 @@ void ripemd_160(std::array& storage, const std::string& data) // finish: MDfinish(MDbuf, message, length, 0); - for (size_t i = 0; i < storage.size(); i += 4) - { + for (size_t i = 0; i < storage.size(); i += 4) { storage[i] = MDbuf[i>>2]; // implicit cast to byte storage[i+1] = (MDbuf[i>>2] >> 8); // extracts the 8 least storage[i+2] = (MDbuf[i>>2] >> 16); // significant bits. diff --git a/src/scheduled_actor.cpp b/src/scheduled_actor.cpp index 76a5429777..bf733a357e 100644 --- a/src/scheduled_actor.cpp +++ b/src/scheduled_actor.cpp @@ -28,16 +28,29 @@ \******************************************************************************/ +#include "cppa/scheduler.hpp" #include "cppa/scheduled_actor.hpp" namespace cppa { -scheduled_actor::~scheduled_actor() -{ +scheduled_actor::scheduled_actor(bool enable_chained_send) +: local_actor(enable_chained_send), next(nullptr), m_scheduler(nullptr) { } + +void scheduled_actor::attach_to_scheduler(scheduler* sched) { + CPPA_REQUIRE(sched != nullptr); + // init is called by the spawning actor, manipulate self to + // point to this actor + scoped_self_setter sss{this}; + // initialize this actor + try { init(); } + catch (...) { } + // make sure scheduler is not set until init() is done + std::atomic_thread_fence(std::memory_order_seq_cst); + m_scheduler = sched; } -void scheduled_actor::on_exit() -{ +bool scheduled_actor::initialized() { + return m_scheduler != nullptr; } } // namespace cppa diff --git a/src/scheduled_actor_dummy.cpp b/src/scheduled_actor_dummy.cpp new file mode 100644 index 0000000000..c622d01822 --- /dev/null +++ b/src/scheduled_actor_dummy.cpp @@ -0,0 +1,62 @@ +/******************************************************************************\ + * ___ __ * + * /\_ \ __/\ \ * + * \//\ \ /\_\ \ \____ ___ _____ _____ __ * + * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * + * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * + * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * + * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * + * \ \_\ \ \_\ * + * \/_/ \/_/ * + * * + * Copyright (C) 2011, 2012 * + * Dominik Charousset * + * * + * This file is part of libcppa. * + * libcppa is free software: you can redistribute it and/or modify it under * + * the terms of the GNU Lesser General Public License as published by the * + * Free Software Foundation, either version 3 of the License * + * or (at your option) any later version. * + * * + * libcppa is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with libcppa. If not, see . * +\******************************************************************************/ + + +#include "cppa/detail/scheduled_actor_dummy.hpp" + +namespace cppa { namespace detail { + +void scheduled_actor_dummy::quit(std::uint32_t) { } +void scheduled_actor_dummy::dequeue(behavior&) { } +void scheduled_actor_dummy::dequeue(partial_function&) { } +void scheduled_actor_dummy::link_to(intrusive_ptr&) { } +void scheduled_actor_dummy::unlink_from(intrusive_ptr&) { } +void scheduled_actor_dummy::detach(const attachable::token&) { } +bool scheduled_actor_dummy::attach(attachable*) { return false; } +void scheduled_actor_dummy::unbecome() { } +void scheduled_actor_dummy::do_become(behavior*, bool, bool) { } +bool scheduled_actor_dummy::has_behavior() { return false; } + +resume_result scheduled_actor_dummy::resume(util::fiber*) { + return resume_result::actor_blocked; +} + +bool scheduled_actor_dummy::establish_backlink(intrusive_ptr&) { + return false; +} + +bool scheduled_actor_dummy::remove_backlink(intrusive_ptr&) { + return false; +} + +scheduled_actor_type scheduled_actor_dummy::impl_type() { + return event_based_impl; +} + +} } // namespace cppa::detail diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 7418b1a956..b96cbd9438 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -28,7 +28,9 @@ \******************************************************************************/ +#include #include +#include #include #include "cppa/on.hpp" @@ -37,59 +39,55 @@ #include "cppa/to_string.hpp" #include "cppa/scheduler.hpp" #include "cppa/local_actor.hpp" +#include "cppa/thread_mapped_actor.hpp" -#include "cppa/detail/thread.hpp" #include "cppa/detail/actor_count.hpp" -#include "cppa/detail/mock_scheduler.hpp" #include "cppa/detail/singleton_manager.hpp" #include "cppa/detail/thread_pool_scheduler.hpp" -#include "cppa/detail/converted_thread_context.hpp" namespace { typedef std::uint32_t ui32; -struct exit_observer : cppa::attachable -{ - ~exit_observer() - { +struct exit_observer : cppa::attachable { + ~exit_observer() { cppa::detail::dec_actor_count(); } - void actor_exited(std::uint32_t) - { + void actor_exited(std::uint32_t) { } - bool matches(const token&) - { + bool matches(const token&) { return false; } }; +inline decltype(std::chrono::high_resolution_clock::now()) now() { + return std::chrono::high_resolution_clock::now(); +} + } // namespace namespace cppa { -struct scheduler_helper -{ +class scheduler_helper { + + public: - typedef intrusive_ptr ptr_type; + typedef intrusive_ptr ptr_type; - scheduler_helper() : m_worker(new detail::converted_thread_context) - { + scheduler_helper() : m_worker(new thread_mapped_actor) { } - void start() - { - m_thread = detail::thread(&scheduler_helper::time_emitter, m_worker); + void start() { + m_thread = std::thread(&scheduler_helper::time_emitter, m_worker); } - void stop() - { + void stop() { m_worker->enqueue(nullptr, make_cow_tuple(atom(":_DIE"))); m_thread.join(); } ptr_type m_worker; - detail::thread m_thread; + std::thread m_thread; private: @@ -97,35 +95,31 @@ struct scheduler_helper }; -void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self) -{ - typedef abstract_actor::queue_node_ptr queue_node_ptr; +void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self) { + typedef detail::abstract_actor impl_type; + typedef std::unique_ptr queue_node_ptr; // setup & local variables self.set(m_self.get()); auto& queue = m_self->mailbox(); - std::multimap messages; + std::multimap messages; queue_node_ptr msg_ptr; //decltype(queue.pop()) msg_ptr = nullptr; - decltype(detail::now()) now; + decltype(now()) tout; bool done = false; // message handling rules - auto handle_msg = - ( - on() >> [&](const util::duration& d, - const actor_ptr&) - { + auto mfun = ( + on() >> [&](const util::duration& d, + const channel_ptr&) { // calculate timeout - auto timeout = detail::now(); + auto timeout = now(); timeout += d; messages.insert(std::make_pair(std::move(timeout), std::move(msg_ptr))); }, - on() >> [&]() - { + on() >> [&]() { done = true; }, - others() >> [&]() - { + others() >> [&]() { # ifdef CPPA_DEBUG std::cerr << "scheduler_helper::time_emitter: UNKNOWN MESSAGE: " << to_string(msg_ptr->msg) @@ -135,107 +129,83 @@ void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self) } ); // loop - while (!done) - { - while (!msg_ptr) - { - if (messages.empty()) - { + while (!done) { + while (!msg_ptr) { + if (messages.empty()) { msg_ptr.reset(queue.pop()); } - else - { - now = detail::now(); + else { + tout = now(); // handle timeouts (send messages) auto it = messages.begin(); - while (it != messages.end() && (it->first) <= now) - { - abstract_actor::queue_node_ptr ptr(std::move(it->second)); - //auto ptr = it->second; + while (it != messages.end() && (it->first) <= tout) { + queue_node_ptr ptr{std::move(it->second)}; + CPPA_REQUIRE(ptr->marked == false); auto whom = const_cast( - reinterpret_cast( + reinterpret_cast( ptr->msg.at(1))); - if (*whom) - { - any_tuple msg = *(reinterpret_cast( - ptr->msg.at(2))); - (*whom)->enqueue(ptr->sender.get(), std::move(msg)); + if (*whom) { + any_tuple msg = *(reinterpret_cast( + ptr->msg.at(2))); (*whom)->enqueue(ptr->sender.get(), std::move(msg)); } messages.erase(it); it = messages.begin(); - //delete ptr; } // wait for next message or next timeout - if (it != messages.end()) - { + if (it != messages.end()) { msg_ptr.reset(queue.try_pop(it->first)); } } } - handle_msg(msg_ptr->msg); - //delete msg_ptr; + mfun(msg_ptr->msg); } } -scheduler::scheduler() : m_helper(new scheduler_helper) -{ +scheduler::scheduler() : m_helper(new scheduler_helper) { } -void scheduler::start() -{ +void scheduler::start() { m_helper->start(); } -void scheduler::stop() -{ +void scheduler::stop() { m_helper->stop(); } -scheduler::~scheduler() -{ +scheduler::~scheduler() { delete m_helper; } -channel* scheduler::future_send_helper() -{ +channel* scheduler::delayed_send_helper() { return m_helper->m_worker.get(); } -void scheduler::register_converted_context(local_actor* what) -{ - if (what) - { +void scheduler::register_converted_context(local_actor* what) { + if (what) { detail::inc_actor_count(); what->attach(new exit_observer); } } -attachable* scheduler::register_hidden_context() -{ +attachable* scheduler::register_hidden_context() { detail::inc_actor_count(); return new exit_observer; } -void set_scheduler(scheduler* sched) -{ - if (detail::singleton_manager::set_scheduler(sched) == false) - { +void set_scheduler(scheduler* sched) { + if (detail::singleton_manager::set_scheduler(sched) == false) { throw std::runtime_error("scheduler already set"); } } -scheduler* get_scheduler() -{ +scheduler* get_scheduler() { scheduler* result = detail::singleton_manager::get_scheduler(); - if (result == nullptr) - { + if (result == nullptr) { result = new detail::thread_pool_scheduler; - try - { + try { set_scheduler(result); } - catch (std::runtime_error&) - { + catch (std::runtime_error&) { delete result; return detail::singleton_manager::get_scheduler(); } diff --git a/src/self.cpp b/src/self.cpp index 0e62c027e6..3f32d5bc63 100644 --- a/src/self.cpp +++ b/src/self.cpp @@ -36,58 +36,57 @@ #include "cppa/any_tuple.hpp" #include "cppa/scheduler.hpp" #include "cppa/local_actor.hpp" -#include "cppa/detail/converted_thread_context.hpp" +#include "cppa/thread_mapped_actor.hpp" -using cppa::detail::converted_thread_context; +namespace cppa { namespace { -void cleanup_fun(cppa::local_actor* what) -{ - auto ptr = dynamic_cast(what); - if (ptr) - { - // make sure "unspawned" actors quit properly - ptr->cleanup(cppa::exit_reason::normal); - } - if (what && !what->deref()) delete what; -} - -boost::thread_specific_ptr t_this_context(cleanup_fun); +boost::thread_specific_ptr t_this_actor(&self_type::cleanup_fun); } // namespace -namespace cppa { - -//self_type self; +void self_type::cleanup_fun(cppa::local_actor* what) { + if (what) { + auto ptr = dynamic_cast(what); + if (ptr) { + // make sure "unspawned" actors quit properly + ptr->cleanup(cppa::exit_reason::normal); + } + if (what->deref() == false) delete what; + } +} -void self_type::set_impl(local_actor* ptr) -{ +void self_type::set_impl(self_type::pointer ptr) { if (ptr) ptr->ref(); - t_this_context.reset(ptr); + t_this_actor.reset(ptr); } -local_actor* self_type::get_impl() -{ - auto result = t_this_context.get(); - if (result == nullptr) - { - result = new converted_thread_context; +self_type::pointer self_type::get_impl() { + auto result = t_this_actor.get(); + if (result == nullptr) { + result = new thread_mapped_actor; result->ref(); get_scheduler()->register_converted_context(result); - t_this_context.reset(result); + t_this_actor.reset(result); } return result; } -actor* self_type::convert_impl() -{ +actor* self_type::convert_impl() { return get_impl(); } -local_actor* self_type::get_unchecked_impl() -{ - return t_this_context.get(); +self_type::pointer self_type::get_unchecked_impl() { + return t_this_actor.get(); +} + +void self_type::adopt_impl(self_type::pointer ptr) { + t_this_actor.reset(ptr); +} + +self_type::pointer self_type::release_impl() { + return t_this_actor.release(); } } // namespace cppa diff --git a/src/serializer.cpp b/src/serializer.cpp index cf89b35b2f..b42479ed01 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -32,8 +32,7 @@ namespace cppa { -serializer::~serializer() -{ +serializer::~serializer() { } } // namespace cppa diff --git a/src/shared_spinlock.cpp b/src/shared_spinlock.cpp index 0e296b66f7..c9de175205 100644 --- a/src/shared_spinlock.cpp +++ b/src/shared_spinlock.cpp @@ -42,87 +42,57 @@ constexpr long min_long = std::numeric_limits::min(); namespace cppa { namespace util { -shared_spinlock::shared_spinlock() : m_flag(0) -{ +shared_spinlock::shared_spinlock() : m_flag(0) { } -void shared_spinlock::lock() -{ +void shared_spinlock::lock() { long v = m_flag.load(); - for (;;) - { - if (v != 0) - { + for (;;) { + if (v != 0) { //std::this_thread::yield(); v = m_flag.load(); } - else if (m_flag.compare_exchange_weak(v, min_long)) - { + else if (m_flag.compare_exchange_weak(v, min_long)) { return; } // else: next iteration } } -void shared_spinlock::lock_upgrade() -{ +void shared_spinlock::lock_upgrade() { unlock_shared(); lock(); - /* - long v = m_flag.load(); - for (;;) - { - if (v != 1) - { - //std::this_thread::yield(); - v = m_flag.load(); - } - else if (m_flag.compare_exchange_weak(v, min_long)) - { - return; - } - // else: next iteration - } - */ } -void shared_spinlock::unlock() -{ +void shared_spinlock::unlock() { m_flag.store(0); } -bool shared_spinlock::try_lock() -{ +bool shared_spinlock::try_lock() { long v = m_flag.load(); return (v == 0) ? m_flag.compare_exchange_weak(v, min_long) : false; } -void shared_spinlock::lock_shared() -{ +void shared_spinlock::lock_shared() { long v = m_flag.load(); - for (;;) - { - if (v < 0) - { + for (;;) { + if (v < 0) { //std::this_thread::yield(); v = m_flag.load(); } - else if (m_flag.compare_exchange_weak(v, v + 1)) - { + else if (m_flag.compare_exchange_weak(v, v + 1)) { return; } // else: next iteration } } -void shared_spinlock::unlock_shared() -{ +void shared_spinlock::unlock_shared() { m_flag.fetch_sub(1); } -bool shared_spinlock::try_lock_shared() -{ +bool shared_spinlock::try_lock_shared() { long v = m_flag.load(); return (v >= 0) ? m_flag.compare_exchange_weak(v, v + 1) : false; } diff --git a/src/singleton_manager.cpp b/src/singleton_manager.cpp index b147470643..bceb3b5e81 100644 --- a/src/singleton_manager.cpp +++ b/src/singleton_manager.cpp @@ -31,10 +31,11 @@ #include #include -#include "cppa/any_tuple.hpp" -#include "cppa/local_actor.hpp" #include "cppa/scheduler.hpp" #include "cppa/exception.hpp" +#include "cppa/any_tuple.hpp" +#include "cppa/local_actor.hpp" +#include "cppa/thread_mapped_actor.hpp" #include "cppa/detail/actor_count.hpp" #include "cppa/detail/empty_tuple.hpp" @@ -44,83 +45,81 @@ #include "cppa/detail/singleton_manager.hpp" #include "cppa/detail/thread_pool_scheduler.hpp" #include "cppa/detail/uniform_type_info_map.hpp" -#include "cppa/detail/converted_thread_context.hpp" namespace { using namespace cppa; using namespace cppa::detail; -std::atomic s_uniform_type_info_map(nullptr); -std::atomic s_network_manager(nullptr); -std::atomic s_actor_registry(nullptr); -std::atomic s_group_manager(nullptr); -std::atomic s_empty_tuple(nullptr); -std::atomic s_scheduler(nullptr); +//volatile uniform_type_info_map* s_uniform_type_info_map = 0; + +std::atomic s_uniform_type_info_map; +std::atomic s_network_manager; +std::atomic s_actor_registry; +std::atomic s_group_manager; +std::atomic s_empty_tuple; +std::atomic s_scheduler; template -void stop_and_kill(std::atomic& ptr) -{ +void stop_and_kill(std::atomic& ptr) { auto p = ptr.load(); - if (p) - { - if (ptr.compare_exchange_weak(p, nullptr)) - { + if (p) { + if (ptr.compare_exchange_weak(p, nullptr)) { p->stop(); delete p; } - else - { + else { stop_and_kill(ptr); } } } -struct singleton_cleanup_helper -{ - ~singleton_cleanup_helper() - { - if (self.unchecked() != nullptr) - { - try { self.unchecked()->quit(exit_reason::normal); } - catch (actor_exited&) { } - } - auto rptr = s_actor_registry.load(); - if (rptr) - { - rptr->await_running_count_equal(0); - } - delete s_actor_registry.load(); - // TODO: figure out why the ... Mac OS dies with a segfault here -//# ifndef __APPLE__ - stop_and_kill(s_scheduler); -//# endif - stop_and_kill(s_network_manager); - // it's safe now to delete all other singletons now - delete s_group_manager.load(); - auto et = s_empty_tuple.load(); - if (et && !et->deref()) delete et; - delete s_actor_registry.load(); - delete s_uniform_type_info_map.load(); +/* +void delete_singletons() { + if (self.unchecked() != nullptr) { + try { self.unchecked()->quit(exit_reason::normal); } + catch (actor_exited&) { } + } + auto rptr = s_actor_registry.load(); + if (rptr) { + rptr->await_running_count_equal(0); } + stop_and_kill(s_scheduler); + stop_and_kill(s_network_manager); + std::atomic_thread_fence(std::memory_order_seq_cst); + // it's safe now to delete all other singletons now + delete s_actor_registry.load(); + delete s_group_manager.load(); + auto et = s_empty_tuple.load(); + if (et && !et->deref()) delete et; + delete s_uniform_type_info_map.load(); } -;//s_cleanup_helper; +*/ template -T* lazy_get(std::atomic& ptr) -{ - T* result = ptr.load(); - if (result == nullptr) - { - auto tmp = new T(); - if (ptr.compare_exchange_weak(result, tmp) == false) - { +T* lazy_get(std::atomic& ptr, bool register_atexit_fun = false) { + T* result = ptr.load(std::memory_order_seq_cst); + if (result == nullptr) { + auto tmp = new T; + if (ptr.compare_exchange_strong(result, tmp, std::memory_order_seq_cst)) { + return tmp; + } + else { delete tmp; + return lazy_get(ptr, register_atexit_fun); } - else - { + /* + else { + // ok, successfully created singleton, register exit fun? + if (register_atexit_fun) { +//# ifndef __APPLE__ +// atexit(delete_singletons); +//# endif + } return tmp; } + */ + static_cast(register_atexit_fun); // keep compiler happy } return result; } @@ -129,79 +128,61 @@ T* lazy_get(std::atomic& ptr) namespace cppa { namespace detail { -actor_registry* singleton_manager::get_actor_registry() -{ +actor_registry* singleton_manager::get_actor_registry() { return lazy_get(s_actor_registry); } -uniform_type_info_map* singleton_manager::get_uniform_type_info_map() -{ - return lazy_get(s_uniform_type_info_map); +uniform_type_info_map* singleton_manager::get_uniform_type_info_map() { + return lazy_get(s_uniform_type_info_map, true); } -group_manager* singleton_manager::get_group_manager() -{ +group_manager* singleton_manager::get_group_manager() { return lazy_get(s_group_manager); } -scheduler* singleton_manager::get_scheduler() -{ +scheduler* singleton_manager::get_scheduler() { return s_scheduler.load(); } -bool singleton_manager::set_scheduler(scheduler* ptr) -{ +bool singleton_manager::set_scheduler(scheduler* ptr) { scheduler* expected = nullptr; - if (s_scheduler.compare_exchange_weak(expected, ptr)) - { + if (s_scheduler.compare_exchange_weak(expected, ptr)) { ptr->start(); auto nm = network_manager::create_singleton(); network_manager* nm_expected = nullptr; - if (s_network_manager.compare_exchange_weak(nm_expected, nm)) - { + if (s_network_manager.compare_exchange_weak(nm_expected, nm)) { nm->start(); } - else - { + else { delete nm; } return true; } - else - { + else { delete ptr; return false; } } -network_manager* singleton_manager::get_network_manager() -{ +network_manager* singleton_manager::get_network_manager() { network_manager* result = s_network_manager.load(); - if (result == nullptr) - { + if (result == nullptr) { scheduler* s = new thread_pool_scheduler; // set_scheduler sets s_network_manager - if (set_scheduler(s) == false) - { - //delete s; - } + set_scheduler(s); return get_network_manager(); } return result; } -empty_tuple* singleton_manager::get_empty_tuple() -{ +empty_tuple* singleton_manager::get_empty_tuple() { empty_tuple* result = s_empty_tuple.load(); - if (result == nullptr) - { + if (result == nullptr) { auto tmp = new empty_tuple; - if (s_empty_tuple.compare_exchange_weak(result, tmp) == false) - { + if (s_empty_tuple.compare_exchange_weak(result, tmp) == false) { delete tmp; } - else - { + else { result = tmp; result->ref(); } diff --git a/src/string_serialization.cpp b/src/string_serialization.cpp index 250a111d81..014fb40af2 100644 --- a/src/string_serialization.cpp +++ b/src/string_serialization.cpp @@ -45,29 +45,24 @@ namespace cppa { namespace { -class string_serializer : public serializer -{ +class string_serializer : public serializer { std::ostream& out; - struct pt_writer - { + struct pt_writer { std::ostream& out; pt_writer(std::ostream& mout) : out(mout) { } template - void operator()(const T& value) - { + void operator()(const T& value) { out << value; } - void operator()(const std::string& str) - { + void operator()(const std::string& str) { out << "\"";// << str << "\""; - for (char c : str) - { + for (char c : str) { if (c == '"') out << "\\\""; else out << c; } @@ -84,15 +79,12 @@ class string_serializer : public serializer bool m_obj_just_opened; std::stack m_open_objects; - inline void clear() - { - if (m_after_value) - { + inline void clear() { + if (m_after_value) { out << ", "; m_after_value = false; } - else if (m_obj_just_opened) - { + else if (m_obj_just_opened) { out << " ( "; m_obj_just_opened = false; } @@ -101,78 +93,63 @@ class string_serializer : public serializer public: string_serializer(std::ostream& mout) - : out(mout), m_after_value(false), m_obj_just_opened(false) - { + : out(mout), m_after_value(false), m_obj_just_opened(false) { } - void begin_object(const std::string& type_name) - { + void begin_object(const std::string& type_name) { clear(); m_open_objects.push(type_name); out << type_name;// << " ( "; m_obj_just_opened = true; } - void end_object() - { - if (m_obj_just_opened) - { + void end_object() { + if (m_obj_just_opened) { // no open brackets to close m_obj_just_opened = false; } - else - { + else { out << (m_after_value ? " )" : ")"); } m_after_value = true; - if (!m_open_objects.empty()) - { + if (!m_open_objects.empty()) { m_open_objects.pop(); } } - void begin_sequence(size_t) - { + void begin_sequence(size_t) { clear(); out << "{ "; } - void end_sequence() - { + void end_sequence() { out << (m_after_value ? " }" : "}"); m_after_value = true; } - void write_value(const primitive_variant& value) - { + void write_value(const primitive_variant& value) { clear(); - if (m_open_objects.empty()) - { + if (m_open_objects.empty()) { throw std::runtime_error("write_value(): m_open_objects.empty()"); } - if (m_open_objects.top() == "@atom") - { - if (value.ptype() != pt_uint64) - { + if (m_open_objects.top() == "@atom") { + if (value.ptype() != pt_uint64) { throw std::runtime_error("expected uint64 value after @atom"); } // write atoms as strings instead of integer values auto av = static_cast(get(value)); (pt_writer(out))(to_string(av)); } - else - { + else { value.apply(pt_writer(out)); } m_after_value = true; } - void write_tuple(size_t size, const primitive_variant* values) - { + void write_tuple(size_t size, const primitive_variant* values) { clear(); out << "{"; const primitive_variant* end = values + size; - for ( ; values != end; ++values) - { + for ( ; values != end; ++values) { write_value(*values); } out << (m_after_value ? " }" : "}"); @@ -180,8 +157,7 @@ class string_serializer : public serializer }; -class string_deserializer : public deserializer -{ +class string_deserializer : public deserializer { std::string m_str; std::string::iterator m_pos; @@ -189,29 +165,24 @@ class string_deserializer : public deserializer std::stack m_obj_had_left_parenthesis; std::stack m_open_objects; - void skip_space_and_comma() - { + void skip_space_and_comma() { while (*m_pos == ' ' || *m_pos == ',') ++m_pos; } - void throw_malformed(const std::string& error_msg) - { + void throw_malformed(const std::string& error_msg) { throw std::logic_error("malformed string: " + error_msg); } - void consume(char c) - { + void consume(char c) { skip_space_and_comma(); - if (*m_pos != c) - { + if (*m_pos != c) { std::string error; error += "expected '"; error += c; error += "' found '"; error += *m_pos; error += "'"; - if (m_open_objects.empty() == false) - { + if (m_open_objects.empty() == false) { error += "during deserialization an instance of "; error += m_open_objects.top(); } @@ -220,41 +191,38 @@ class string_deserializer : public deserializer ++m_pos; } - bool try_consume(char c) - { + bool try_consume(char c) { skip_space_and_comma(); - if (*m_pos == c) - { + if (*m_pos == c) { ++m_pos; return true; } return false; } - inline std::string::iterator next_delimiter() - { + inline std::string::iterator next_delimiter() { return std::find_if(m_pos, m_str.end(), [] (char c) -> bool { - switch (c) - { - case '(': - case ')': - case '{': - case '}': - case ' ': - case ',': return true; - default : return false; + switch (c) { + case '(': + case ')': + case '{': + case '}': + case ' ': + case ',': { + return true; + } + default: { + return false; + } } }); } - void integrity_check() - { - if (m_open_objects.empty() || m_obj_had_left_parenthesis.empty()) - { + void integrity_check() { + if (m_open_objects.empty() || m_obj_had_left_parenthesis.empty()) { throw_malformed("missing begin_object()"); } - if (m_obj_had_left_parenthesis.top() == false) - { + if (m_obj_had_left_parenthesis.top() == false) { throw_malformed("expected left parenthesis after " "begin_object call or void value"); } @@ -262,22 +230,18 @@ class string_deserializer : public deserializer public: - string_deserializer(const std::string& str) : m_str(str) - { + string_deserializer(const std::string& str) : m_str(str) { m_pos = m_str.begin(); } - string_deserializer(std::string&& str) : m_str(std::move(str)) - { + string_deserializer(std::string&& str) : m_str(std::move(str)) { m_pos = m_str.begin(); } - std::string seek_object() - { + std::string seek_object() { skip_space_and_comma(); auto substr_end = next_delimiter(); - if (m_pos == substr_end) - { + if (m_pos == substr_end) { throw_malformed("could not seek object type name"); } std::string result(m_pos, substr_end); @@ -285,16 +249,14 @@ class string_deserializer : public deserializer return result; } - std::string peek_object() - { + std::string peek_object() { std::string result = seek_object(); // restore position in stream m_pos -= result.size(); return result; } - void begin_object(const std::string& type_name) - { + void begin_object(const std::string& type_name) { m_open_objects.push(type_name); //++m_obj_count; skip_space_and_comma(); @@ -302,89 +264,70 @@ class string_deserializer : public deserializer //consume('('); } - void end_object() - { - if (m_obj_had_left_parenthesis.empty()) - { + void end_object() { + if (m_obj_had_left_parenthesis.empty()) { throw_malformed("missing begin_object()"); } - else - { - if (m_obj_had_left_parenthesis.top() == true) - { + else { + if (m_obj_had_left_parenthesis.top() == true) { consume(')'); } m_obj_had_left_parenthesis.pop(); } - if (m_open_objects.empty()) - { + if (m_open_objects.empty()) { throw std::runtime_error("no object to end"); } m_open_objects.pop(); - if (m_open_objects.empty()) - { + if (m_open_objects.empty()) { skip_space_and_comma(); - if (m_pos != m_str.end()) - { + if (m_pos != m_str.end()) { throw_malformed("expected end of of string"); } } } - size_t begin_sequence() - { + size_t begin_sequence() { integrity_check(); consume('{'); - auto list_end = std::find(m_pos, m_str.end(), '}'); - return std::count(m_pos, list_end, ',') + 1; + return std::count(m_pos, std::find(m_pos, m_str.end(), '}'), ',') + 1; } - void end_sequence() - { + void end_sequence() { integrity_check(); consume('}'); } - struct from_string - { + struct from_string { const std::string& str; from_string(const std::string& s) : str(s) { } template - void operator()(T& what) - { + void operator()(T& what) { std::istringstream s(str); s >> what; } - void operator()(std::string& what) - { + void operator()(std::string& what) { what = str; } void operator()(std::u16string&) { } void operator()(std::u32string&) { } }; - primitive_variant read_value(primitive_type ptype) - { + primitive_variant read_value(primitive_type ptype) { integrity_check(); - if (m_open_objects.top() == "@atom") - { - if (ptype != pt_uint64) - { + if (m_open_objects.top() == "@atom") { + if (ptype != pt_uint64) { throw_malformed("expected read of pt_uint64 after @atom"); } auto str_val = get(read_value(pt_u8string)); - if (str_val.size() > 10) - { + if (str_val.size() > 10) { throw_malformed("atom string size > 10"); } return detail::atom_val(str_val.c_str()); } skip_space_and_comma(); std::string::iterator substr_end; - auto find_if_cond = [] (char c) -> bool - { - switch (c) - { + auto find_if_cond = [] (char c) -> bool { + switch (c) { case ')': case '}': case ' ': @@ -392,17 +335,13 @@ class string_deserializer : public deserializer default : return false; } }; - if (ptype == pt_u8string) - { - if (*m_pos == '"') - { + if (ptype == pt_u8string) { + if (*m_pos == '"') { // skip leading " ++m_pos; char last_char = '"'; - auto find_if_str_cond = [&last_char] (char c) -> bool - { - if (c == '"' && last_char != '\\') - { + auto find_if_str_cond = [&last_char] (char c) -> bool { + if (c == '"' && last_char != '\\') { return true; } last_char = c; @@ -410,26 +349,21 @@ class string_deserializer : public deserializer }; substr_end = std::find_if(m_pos, m_str.end(), find_if_str_cond); } - else - { + else { substr_end = std::find_if(m_pos, m_str.end(), find_if_cond); } } - else - { + else { substr_end = std::find_if(m_pos, m_str.end(), find_if_cond); } - if (substr_end == m_str.end()) - { + if (substr_end == m_str.end()) { throw std::logic_error("malformed string (unterminated value)"); } std::string substr(m_pos, substr_end); m_pos += substr.size(); - if (ptype == pt_u8string) - { + if (ptype == pt_u8string) { // skip trailing " - if (*m_pos != '"') - { + if (*m_pos != '"') { std::string error_msg; error_msg = "malformed string, expected '\"' found '"; error_msg += *m_pos; @@ -439,10 +373,8 @@ class string_deserializer : public deserializer ++m_pos; // replace '\"' by '"' char last_char = ' '; - auto cond = [&last_char] (char c) -> bool - { - if (c == '"' && last_char == '\\') - { + auto cond = [&last_char] (char c) -> bool { + if (c == '"' && last_char == '\\') { return true; } last_char = c; @@ -453,20 +385,17 @@ class string_deserializer : public deserializer auto send = substr.end(); for (auto i = std::find_if(sbegin, send, cond); i != send; - i = std::find_if(i, send, cond)) - { + i = std::find_if(i, send, cond)) { --i; tmp.append(sbegin, i); tmp += '"'; i += 2; sbegin = i; } - if (sbegin != substr.begin()) - { + if (sbegin != substr.begin()) { tmp.append(sbegin, send); } - if (!tmp.empty()) - { + if (!tmp.empty()) { substr = std::move(tmp); } } @@ -477,13 +406,11 @@ class string_deserializer : public deserializer void read_tuple(size_t size, const primitive_type* begin, - primitive_variant* storage) - { + primitive_variant* storage) { integrity_check(); consume('{'); const primitive_type* end = begin + size; - for ( ; begin != end; ++begin) - { + for ( ; begin != end; ++begin) { *storage = std::move(read_value(*begin)); ++storage; } @@ -494,13 +421,11 @@ class string_deserializer : public deserializer } // namespace -object from_string(const std::string& what) -{ +object from_string(const std::string& what) { string_deserializer strd(what); std::string uname = strd.peek_object(); auto utype = uniform_type_info::from(uname); - if (utype == nullptr) - { + if (utype == nullptr) { throw std::logic_error(uname + " is not announced"); } return utype->deserialize(&strd); @@ -508,8 +433,7 @@ object from_string(const std::string& what) namespace detail { -std::string to_string_impl(const void *what, const uniform_type_info *utype) -{ +std::string to_string_impl(const void *what, const uniform_type_info *utype) { std::ostringstream osstr; string_serializer strs(osstr); utype->serialize(what, &strs); diff --git a/cppa/event_based_actor_base.hpp b/src/thread_mapped_actor.cpp similarity index 59% rename from cppa/event_based_actor_base.hpp rename to src/thread_mapped_actor.cpp index dad81eed85..0f99bfce75 100644 --- a/cppa/event_based_actor_base.hpp +++ b/src/thread_mapped_actor.cpp @@ -28,50 +28,62 @@ \******************************************************************************/ -#ifndef EVENT_BASED_ACTOR_MIXIN_HPP -#define EVENT_BASED_ACTOR_MIXIN_HPP +#include +#include +#include +#include -#include "cppa/behavior.hpp" -#include "cppa/abstract_event_based_actor.hpp" +#include "cppa/self.hpp" +#include "cppa/to_string.hpp" +#include "cppa/exception.hpp" +#include "cppa/thread_mapped_actor.hpp" + +#include "cppa/detail/matches.hpp" namespace cppa { -/** - * @brief Base class for event-based actor implementations. - */ -template -class event_based_actor_base : public abstract_event_based_actor -{ +thread_mapped_actor::thread_mapped_actor() : m_initialized(false) { } - typedef abstract_event_based_actor super; +thread_mapped_actor::thread_mapped_actor(std::function fun) +: super(std::move(fun)), m_initialized(false) { } - inline Derived* d_this() { return static_cast(this); } +void thread_mapped_actor::quit(std::uint32_t reason) { + cleanup(reason); + // actor_exited should not be catched, but if anyone does, + // self must point to a newly created instance + //self.set(nullptr); + throw actor_exited(reason); +} - protected: +void thread_mapped_actor::enqueue(actor* sender, any_tuple msg) { + auto node = fetch_node(sender, std::move(msg)); + CPPA_REQUIRE(node->marked == false); + m_mailbox.push_back(node); +} - /** - * @brief Sets the actor's behavior to @p bhvr. - * @note @p bhvr is owned by caller and must remain valid until - * the actor terminates. - * This member function should be used to use a member of - * a subclass as behavior. - */ - inline void become(behavior* bhvr) - { - d_this()->do_become(bhvr, false); - } +bool thread_mapped_actor::initialized() { + return m_initialized; +} + +detail::filter_result thread_mapped_actor::filter_msg(const any_tuple& msg) { + auto& arr = detail::static_types_array::arr; + if ( m_trap_exit == false + && msg.size() == 2 + && msg.type_at(0) == arr[0] + && msg.type_at(1) == arr[1]) { + auto v0 = msg.get_as(0); + auto v1 = msg.get_as(1); + if (v0 == atom("EXIT")) { + if (v1 != exit_reason::normal) { + quit(v1); + } + return detail::normal_exit_signal; + } - /** @brief Sets the actor's behavior. */ - template - void become(Arg0&& arg0, Args&&... args) - { - behavior tmp = match_expr_concat(std::forward(arg0), - std::forward(args)...); - d_this()->do_become(new behavior(std::move(tmp)), true); } + return detail::ordinary_message; +} -}; -} // namespace cppa -#endif // EVENT_BASED_ACTOR_MIXIN_HPP +} // namespace cppa::detail diff --git a/src/thread_pool_scheduler.cpp b/src/thread_pool_scheduler.cpp index 45414f551d..336f91797f 100644 --- a/src/thread_pool_scheduler.cpp +++ b/src/thread_pool_scheduler.cpp @@ -28,16 +28,17 @@ \******************************************************************************/ +#include +#include #include #include #include -#include "cppa/abstract_event_based_actor.hpp" +#include "cppa/event_based_actor.hpp" +#include "cppa/thread_mapped_actor.hpp" -#include "cppa/detail/invokable.hpp" #include "cppa/detail/actor_count.hpp" -#include "cppa/detail/mock_scheduler.hpp" -#include "cppa/detail/yielding_actor.hpp" +#include "cppa/context_switching_actor.hpp" #include "cppa/detail/thread_pool_scheduler.hpp" using std::cout; @@ -47,209 +48,236 @@ namespace cppa { namespace detail { namespace { -typedef unique_lock guard_type; -typedef std::unique_ptr worker_ptr; +typedef std::unique_lock guard_type; typedef intrusive::single_reader_queue worker_queue; } // namespace -struct thread_pool_scheduler::worker -{ +struct thread_pool_scheduler::worker { - typedef abstract_scheduled_actor* job_ptr; + typedef scheduled_actor* job_ptr; job_queue* m_job_queue; job_ptr m_dummy; - thread m_thread; + std::thread m_thread; - worker(job_queue* jq, job_ptr dummy) : m_job_queue(jq), m_dummy(dummy) - { - } + worker(job_queue* jq, job_ptr dummy) : m_job_queue(jq), m_dummy(dummy) { } - void start() - { - m_thread = thread(&thread_pool_scheduler::worker_loop, this); + void start() { + m_thread = std::thread(&thread_pool_scheduler::worker_loop, this); } worker(const worker&) = delete; worker& operator=(const worker&) = delete; - job_ptr aggressive_polling() - { + job_ptr aggressive_polling() { job_ptr result = nullptr; - for (int i = 0; i < 3; ++i) - { + for (int i = 0; i < 3; ++i) { result = m_job_queue->try_pop(); - if (result) - { + if (result) { return result; } - detail::this_thread::yield(); + std::this_thread::yield(); } return result; } - job_ptr less_aggressive_polling() - { + job_ptr less_aggressive_polling() { job_ptr result = nullptr; - for (int i = 0; i < 10; ++i) - { + for (int i = 0; i < 10; ++i) { result = m_job_queue->try_pop(); - if (result) - { + if (result) { return result; } -# ifdef __APPLE__ - auto timeout = boost::get_system_time(); - timeout += boost::posix_time::milliseconds(1); - boost::this_thread::sleep(timeout); -# else std::this_thread::sleep_for(std::chrono::milliseconds(1)); -# endif } return result; } - job_ptr relaxed_polling() - { + job_ptr relaxed_polling() { job_ptr result = nullptr; - for (;;) - { + for (;;) { result = m_job_queue->try_pop(); - if (result) - { + if (result) { return result; } -# ifdef __APPLE__ - auto timeout = boost::get_system_time(); - timeout += boost::posix_time::milliseconds(10); - boost::this_thread::sleep(timeout); -# else std::this_thread::sleep_for(std::chrono::milliseconds(10)); -# endif } } - void operator()() - { + void operator()() { util::fiber fself; - struct handler : abstract_scheduled_actor::resume_callback - { - abstract_scheduled_actor* job; - handler() : job(nullptr) { } - bool still_ready() { return true; } - void exec_done() - { - if (!job->deref()) delete job; - dec_actor_count(); - job = nullptr; - } + job_ptr job = nullptr; + auto fetch_pending = [&job]() -> job_ptr { + CPPA_REQUIRE(job != nullptr); + auto ptr = job->chained_actor().release(); + return ptr ? static_cast(ptr) : nullptr; }; - handler h; - for (;;) - { - h.job = aggressive_polling(); - if (!h.job) - { - h.job = less_aggressive_polling(); - if (!h.job) - { - h.job = relaxed_polling(); + for (;;) { + job = aggressive_polling(); + if (job == nullptr) { + job = less_aggressive_polling(); + if (job == nullptr) { + job = relaxed_polling(); } } - if (h.job == m_dummy) - { + if (job == m_dummy) { // dummy of doom received ... - m_job_queue->push_back(h.job); // kill the next guy - return; // and say goodbye + m_job_queue->push_back(job); // kill the next guy + return; // and say goodbye } - else - { - h.job->resume(&fself, &h); + else { + do { + switch (job->resume(&fself)) { + case resume_result::actor_done: { + auto pending = fetch_pending(); + if (!job->deref()) delete job; + std::atomic_thread_fence(std::memory_order_seq_cst); + dec_actor_count(); + job = pending; + break; + } + case resume_result::actor_blocked: { + job = fetch_pending(); + } + } + } + while (job); } } } }; -void thread_pool_scheduler::worker_loop(thread_pool_scheduler::worker* w) -{ +void thread_pool_scheduler::worker_loop(thread_pool_scheduler::worker* w) { (*w)(); } void thread_pool_scheduler::supervisor_loop(job_queue* jqueue, - abstract_scheduled_actor* dummy) -{ - std::vector workers; - size_t num_workers = std::max(thread::hardware_concurrency() * 2, 8); - for (size_t i = 0; i < num_workers; ++i) - { - worker_ptr wptr(new worker(jqueue, dummy)); - wptr->start(); - workers.push_back(std::move(wptr)); + scheduled_actor* dummy) { + std::vector > workers; + size_t num_workers = std::max(std::thread::hardware_concurrency() * 2, 4); + for (size_t i = 0; i < num_workers; ++i) { + workers.emplace_back(new worker(jqueue, dummy)); + workers.back()->start(); } // wait for workers - for (auto& w : workers) - { + for (auto& w : workers) { w->m_thread.join(); } } -void thread_pool_scheduler::start() -{ - m_supervisor = thread(&thread_pool_scheduler::supervisor_loop, - &m_queue, &m_dummy); +void thread_pool_scheduler::start() { + m_supervisor = std::thread(&thread_pool_scheduler::supervisor_loop, + &m_queue, &m_dummy); super::start(); } -void thread_pool_scheduler::stop() -{ +void thread_pool_scheduler::stop() { m_queue.push_back(&m_dummy); m_supervisor.join(); + // make sure job queue is empty, because destructor of m_queue would + // otherwise delete elements it shouldn't + auto ptr = m_queue.try_pop(); + while (ptr != nullptr) { + if (ptr != &m_dummy) { + if (!ptr->deref()) delete ptr; + std::atomic_thread_fence(std::memory_order_seq_cst); + dec_actor_count(); + ptr = m_queue.try_pop(); + } + } super::stop(); } -void thread_pool_scheduler::enqueue(abstract_scheduled_actor* what) -{ +void thread_pool_scheduler::enqueue(scheduled_actor* what) { m_queue.push_back(what); } -actor_ptr thread_pool_scheduler::spawn_impl(abstract_scheduled_actor* what, - bool push_to_queue) -{ - inc_actor_count(); - CPPA_MEMORY_BARRIER(); - intrusive_ptr ctx(what); - ctx->ref(); - if (push_to_queue) m_queue.push_back(ctx.get()); - return std::move(ctx); +actor_ptr thread_pool_scheduler::spawn_as_thread(void_function fun, + init_callback cb, + bool hidden) { + if (!hidden) inc_actor_count(); + thread_mapped_actor_ptr ptr{new thread_mapped_actor(std::move(fun))}; + ptr->init(); + ptr->initialized(true); + cb(ptr.get()); + std::thread([hidden, ptr]() { + scoped_self_setter sss{ptr.get()}; + try { + ptr->run(); + ptr->on_exit(); + } + catch (...) { } + std::atomic_thread_fence(std::memory_order_seq_cst); + if (!hidden) dec_actor_count(); + }).detach(); + return ptr; +} + +actor_ptr thread_pool_scheduler::spawn_impl(scheduled_actor_ptr what) { + if (what->has_behavior()) { + inc_actor_count(); + what->ref(); + // event-based actors are not pushed to the job queue on startup + if (what->impl_type() == context_switching_impl) { + m_queue.push_back(what.get()); + } + } + else { + what->on_exit(); + } + return std::move(what); } +actor_ptr thread_pool_scheduler::spawn(scheduled_actor* raw) { + scheduled_actor_ptr ptr{raw}; + ptr->attach_to_scheduler(this); + return spawn_impl(std::move(ptr)); +} -actor_ptr thread_pool_scheduler::spawn(abstract_event_based_actor* what) -{ - // do NOT push event-based actors to the queue on startup - return spawn_impl(what->attach_to_scheduler(this), false); +actor_ptr thread_pool_scheduler::spawn(scheduled_actor* raw, init_callback cb) { + scheduled_actor_ptr ptr{raw}; + ptr->attach_to_scheduler(this); + cb(ptr.get()); + return spawn_impl(std::move(ptr)); } #ifndef CPPA_DISABLE_CONTEXT_SWITCHING -actor_ptr thread_pool_scheduler::spawn(scheduled_actor* bhvr, - scheduling_hint hint) -{ - if (hint == detached) - { - return mock_scheduler::spawn(bhvr); +actor_ptr thread_pool_scheduler::spawn(void_function fun, scheduling_hint sh) { + if (sh == scheduled) { + scheduled_actor_ptr ptr{new context_switching_actor(std::move(fun))}; + ptr->attach_to_scheduler(this); + return spawn_impl(std::move(ptr)); } - else - { - return spawn_impl(new yielding_actor(bhvr, this)); + else { + return spawn_as_thread(std::move(fun), + [](local_actor*) { }, + sh == detached_and_hidden); + } +} +actor_ptr thread_pool_scheduler::spawn(void_function fun, + scheduling_hint sh, + init_callback init_cb) { + if (sh == scheduled) { + scheduled_actor_ptr ptr{new context_switching_actor(std::move(fun))}; + ptr->attach_to_scheduler(this); + init_cb(ptr.get()); + return spawn_impl(std::move(ptr)); + } + else { + return spawn_as_thread(std::move(fun), std::move(init_cb), sh == detached_and_hidden); } } #else -actor_ptr thread_pool_scheduler::spawn(scheduled_actor* bhvr, scheduling_hint) -{ - return mock_scheduler::spawn(bhvr); +actor_ptr thread_pool_scheduler::spawn(void_function what, scheduling_hint) { + return spawn_as_thread(std::move(what), [](local_actor*) { }); +} +actor_ptr thread_pool_scheduler::spawn(void_function what, + scheduling_hint, + init_callback init_cb) { + return spawn_as_thread(std::move(what), std::move(init_cb)); } #endif diff --git a/src/to_uniform_name.cpp b/src/to_uniform_name.cpp index 107d7d8990..29f18690d2 100644 --- a/src/to_uniform_name.cpp +++ b/src/to_uniform_name.cpp @@ -51,45 +51,39 @@ namespace { -constexpr const char* mapped_int_names[][2] = -{ - { nullptr, nullptr }, // sizeof 0 { invalid } +constexpr const char* mapped_int_names[][2] = { + { nullptr, nullptr }, // sizeof 0-> invalid { "@i8", "@u8" }, // sizeof 1 -> signed / unsigned int8 { "@i16", "@u16" }, // sizeof 2 -> signed / unsigned int16 - { nullptr, nullptr }, // sizeof 3 { invalid } + { nullptr, nullptr }, // sizeof 3-> invalid { "@i32", "@u32" }, // sizeof 4 -> signed / unsigned int32 - { nullptr, nullptr }, // sizeof 5 { invalid } - { nullptr, nullptr }, // sizeof 6 { invalid } - { nullptr, nullptr }, // sizeof 7 { invalid } + { nullptr, nullptr }, // sizeof 5-> invalid + { nullptr, nullptr }, // sizeof 6-> invalid + { nullptr, nullptr }, // sizeof 7-> invalid { "@i64", "@u64" } // sizeof 8 -> signed / unsigned int64 }; template -constexpr size_t sign_index() -{ +constexpr size_t sign_index() { static_assert(std::numeric_limits::is_integer, "T is not an integer"); return std::numeric_limits::is_signed ? 0 : 1; } template -inline std::string demangled() -{ +inline std::string demangled() { return cppa::detail::demangle(typeid(T).name()); } template -constexpr const char* mapped_int_name() -{ +constexpr const char* mapped_int_name() { return mapped_int_names[sizeof(T)][sign_index()]; } template std::string to_uniform_name_impl(Iterator begin, Iterator end, - bool first_run = false) -{ + bool first_run = false) { // all integer type names as uniform representation - static std::map mapped_demangled_names = - { + static std::map mapped_demangled_names = { // integer types { demangled(), mapped_int_name() }, { demangled(), mapped_int_name() }, @@ -125,16 +119,15 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end, { demangled(), "@actor" }, { demangled(), "@group" }, { demangled(), "@channel" }, - { demangled(), "@msg" } + { demangled(), "@msg" }, + { demangled< cppa::intrusive_ptr >(), "@process_info" } }; // check if we could find the whole string in our lookup map - if (first_run) - { + if (first_run) { std::string tmp(begin, end); auto i = mapped_demangled_names.find(tmp); - if (i != mapped_demangled_names.end()) - { + if (i != mapped_demangled_names.end()) { return i->second; } } @@ -150,10 +143,8 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end, int open_brackets = 0; // counts "open" '<' // denotes the begin of a possible subsequence Iterator anchor = begin; - for (Iterator i = begin; i != end; /* i is incemented in the loop */) - { - switch (*i) - { + for (Iterator i = begin; i != end; /* i is incemented in the loop */) { + switch (*i) { case '<': ++open_brackets; @@ -161,22 +152,19 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end, break; case '>': - if (--open_brackets < 0) - { + if (--open_brackets < 0) { throw std::runtime_error("malformed string"); } ++i; break; case ',': - if (open_brackets == 0) - { + if (open_brackets == 0) { substrings.push_back(std::make_pair(anchor, i)); ++i; anchor = i; } - else - { + else { ++i; } break; @@ -188,24 +176,20 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end, } } // call recursively for each list argument - if (!substrings.empty()) - { + if (!substrings.empty()) { std::string result; substrings.push_back(std::make_pair(anchor, end)); - for (const subseq& sstr : substrings) - { + for (const subseq& sstr : substrings) { if (!result.empty()) result += ","; result += to_uniform_name_impl(sstr.first, sstr.second); } return result; } // we didn't got a list, compute unify name - else - { + else { // is [begin, end) a template? Iterator substr_begin = std::find(begin, end, '<'); - if (substr_begin == end) - { + if (substr_begin == end) { // not a template, return mapping std::string arg(begin, end); auto mapped = mapped_demangled_names.find(arg); @@ -221,8 +205,7 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end, .base(); // skip trailing '>' --substr_end; - if (substr_end == substr_begin) - { + if (substr_end == substr_begin) { throw std::runtime_error("substr_end == substr_begin"); } std::string result; @@ -239,17 +222,14 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end, namespace cppa { namespace detail { -std::string to_uniform_name(const std::string& dname) -{ +std::string to_uniform_name(const std::string& dname) { static std::string an = "(anonymous namespace)"; static std::string an_replacement = "@_"; auto r = to_uniform_name_impl(dname.begin(), dname.end(), true); // replace all occurrences of an with "@_" - if (r.size() > an.size()) - { + if (r.size() > an.size()) { auto i = std::search(r.begin(), r.end(), an.begin(), an.end()); - while (i != r.end()) - { + while (i != r.end()) { auto substr_end = i + an.size(); r.replace(i, substr_end, an_replacement); // next iteration @@ -259,8 +239,7 @@ std::string to_uniform_name(const std::string& dname) return r; } -std::string to_uniform_name(const std::type_info& tinfo) -{ +std::string to_uniform_name(const std::type_info& tinfo) { return to_uniform_name(demangle(tinfo.name())); } diff --git a/src/unicast_network.cpp b/src/unicast_network.cpp index 495e5a186f..500332a59c 100644 --- a/src/unicast_network.cpp +++ b/src/unicast_network.cpp @@ -38,6 +38,7 @@ #include #include +#include #include "cppa/cppa.hpp" #include "cppa/atom.hpp" @@ -53,6 +54,7 @@ #include "cppa/detail/post_office.hpp" #include "cppa/detail/native_socket.hpp" #include "cppa/detail/actor_registry.hpp" +#include "cppa/detail/network_manager.hpp" #include "cppa/detail/actor_proxy_cache.hpp" #include "cppa/detail/singleton_manager.hpp" @@ -63,18 +65,15 @@ namespace cppa { namespace { -void read_from_socket(detail::native_socket_type sfd, void* buf, size_t buf_size) -{ +void read_from_socket(detail::native_socket_type sfd, void* buf, size_t buf_size) { char* cbuf = reinterpret_cast(buf); size_t read_bytes = 0; size_t left = buf_size; int rres = 0; size_t urres = 0; - do - { + do { rres = ::recv(sfd, cbuf + read_bytes, left, 0); - if (rres <= 0) - { + if (rres <= 0) { throw std::ios_base::failure("cannot read from closed socket"); } urres = static_cast(rres); @@ -86,39 +85,33 @@ void read_from_socket(detail::native_socket_type sfd, void* buf, size_t buf_size } // namespace -struct socket_guard -{ +struct socket_guard { bool m_released; detail::native_socket_type m_socket; public: - socket_guard(detail::native_socket_type sfd) : m_released(false), m_socket(sfd) - { + socket_guard(detail::native_socket_type sfd) : m_released(false), m_socket(sfd) { } - ~socket_guard() - { + ~socket_guard() { if (!m_released) detail::closesocket(m_socket); } - void release() - { + void release() { m_released = true; } }; -void publish(actor_ptr& whom, std::uint16_t port) -{ +void publish(actor_ptr whom, std::uint16_t port) { if (!whom) return; detail::singleton_manager::get_actor_registry()->put(whom->id(), whom); detail::native_socket_type sockfd; struct sockaddr_in serv_addr; sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd == detail::invalid_socket) - { + if (sockfd == detail::invalid_socket) { throw network_error("could not create server socket"); } // sguard closes the socket if an exception occurs @@ -127,46 +120,36 @@ void publish(actor_ptr& whom, std::uint16_t port) serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(port); - int flags = fcntl(sockfd, F_GETFL, 0); - if (flags == -1) - { - throw network_error("unable to get socket flags"); - } - if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) - { - throw network_error("unable to set socket to nonblocking"); - } - if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) - { + if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { throw bind_failure(errno); } - if (listen(sockfd, 10) != 0) - { + if (listen(sockfd, 10) != 0) { throw network_error("listen() failed"); } + int flags = fcntl(sockfd, F_GETFL, 0); + if (flags == -1) { + throw network_error("unable to get socket flags"); + } + if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) { + throw network_error("unable to set socket to nonblock"); + } + flags = 1; + setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(int)); // ok, no exceptions sguard.release(); detail::post_office_publish(sockfd, whom); } -void publish(actor_ptr&& whom, std::uint16_t port) -{ - publish(static_cast(whom), port); -} - -actor_ptr remote_actor(const char* host, std::uint16_t port) -{ +actor_ptr remote_actor(const char* host, std::uint16_t port) { detail::native_socket_type sockfd; struct sockaddr_in serv_addr; struct hostent* server; sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd == detail::invalid_socket) - { + if (sockfd == detail::invalid_socket) { throw network_error("socket creation failed"); } server = gethostbyname(host); - if (!server) - { + if (!server) { std::string errstr = "no such host: "; errstr += host; throw network_error(std::move(errstr)); @@ -175,12 +158,13 @@ actor_ptr remote_actor(const char* host, std::uint16_t port) serv_addr.sin_family = AF_INET; memmove(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length); serv_addr.sin_port = htons(port); - if (connect(sockfd, (const sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) - { + if (connect(sockfd, (const sockaddr*) &serv_addr, sizeof(serv_addr)) != 0) { throw network_error("could not connect to host"); } auto pinf = process_information::get(); std::uint32_t process_id = pinf->process_id(); + int flags = 1; + setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(int)); ::send(sockfd, &process_id, sizeof(std::uint32_t), 0); ::send(sockfd, pinf->node_id().data(), pinf->node_id().size(), 0); std::uint32_t remote_actor_id; @@ -189,14 +173,25 @@ actor_ptr remote_actor(const char* host, std::uint16_t port) read_from_socket(sockfd, &remote_actor_id, sizeof(remote_actor_id)); read_from_socket(sockfd, &peer_pid, sizeof(std::uint32_t)); read_from_socket(sockfd, peer_node_id.data(), peer_node_id.size()); + + flags = fcntl(sockfd, F_GETFL, 0); + if (flags == -1) { + throw network_error("unable to get socket flags"); + } + if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) { + throw network_error("unable to set socket to nonblock"); + } + auto peer_pinf = new process_information(peer_pid, peer_node_id); process_information_ptr pinfptr(peer_pinf); - actor_proxy_ptr result(new actor_proxy(remote_actor_id, pinfptr)); - detail::mailman_queue().push_back(new detail::mailman_job(sockfd, pinfptr)); - detail::post_office_add_peer(sockfd, pinfptr, result, - std::unique_ptr()); + //auto key = std::make_tuple(remote_actor_id, pinfptr->process_id(), pinfptr->node_id()); + detail::singleton_manager::get_network_manager() + ->send_to_mailman(make_any_tuple(sockfd, pinfptr)); + detail::post_office_add_peer(sockfd, pinfptr); + return detail::get_actor_proxy_cache().get(remote_actor_id, + pinfptr->process_id(), + pinfptr->node_id()); //auto ptr = get_scheduler()->register_hidden_context(); - return result; } } // namespace cppa diff --git a/src/uniform_type_info.cpp b/src/uniform_type_info.cpp index 76d868a079..f9492dec3c 100644 --- a/src/uniform_type_info.cpp +++ b/src/uniform_type_info.cpp @@ -38,8 +38,6 @@ #include #include #include -#include -#include #include #include "cppa/atom.hpp" @@ -64,29 +62,15 @@ #include "cppa/detail/uniform_type_info_map.hpp" #include "cppa/detail/default_uniform_type_info_impl.hpp" -using std::cout; -using std::endl; -using cppa::util::void_type; - -namespace std { - -ostream& operator<<(ostream& o, const cppa::actor_ptr&) { return o; } -istream& operator>>(istream& i, cppa::actor_ptr&) { return i; } - -ostream& operator<<(ostream& o, const cppa::util::void_type&) { return o; } -istream& operator>>(istream& i, cppa::util::void_type&) { return i; } - -} // namespace std +namespace cppa { namespace detail { namespace { -inline cppa::detail::uniform_type_info_map& uti_map() -{ - return *(cppa::detail::singleton_manager::get_uniform_type_info_map()); +inline uniform_type_info_map& uti_map() { + return *singleton_manager::get_uniform_type_info_map(); } -inline const char* raw_name(const std::type_info& tinfo) -{ +inline const char* raw_name(const std::type_info& tinfo) { #ifdef CPPA_WINDOWS return tinfo.raw_name(); #else @@ -95,103 +79,109 @@ inline const char* raw_name(const std::type_info& tinfo) } template -struct is_signed - : std::integral_constant::is_signed> -{ -}; +struct is_signed : + std::integral_constant::is_signed> { }; template -inline const char* raw_name() -{ +inline const char* raw_name() { return raw_name(typeid(T)); } typedef std::set string_set; +typedef std::map > int_name_mapping; template -void push(std::map>& ints, - std::integral_constant) // signed version -{ - ints[sizeof(Int)].first.insert(raw_name()); +inline void push_impl(int_name_mapping& ints, std::true_type) { + ints[sizeof(Int)].first.insert(raw_name()); // signed version } template -void push(std::map>& ints, - std::integral_constant) // unsigned version -{ - ints[sizeof(Int)].second.insert(raw_name()); +inline void push_impl(int_name_mapping& ints, std::false_type) { + ints[sizeof(Int)].second.insert(raw_name()); // unsigned version } template -void push(std::map>& ints) -{ - push(ints, is_signed()); +inline void push(int_name_mapping& ints) { + push_impl(ints, is_signed{}); } template -void push(std::map>& ints) -{ - push(ints, is_signed()); +inline void push(int_name_mapping& ints) { + push_impl(ints, is_signed{}); push(ints); } -} // namespace - -namespace cppa { namespace detail { //namespace { - -const std::string nullptr_type_name = "@0"; +const std::string s_nullptr_type_name{"@0"}; -void serialize_nullptr(serializer* sink) -{ - sink->begin_object(nullptr_type_name); +void serialize_nullptr(serializer* sink) { + sink->begin_object(s_nullptr_type_name); sink->end_object(); } -void deserialize_nullptr(deserializer* source) -{ - source->begin_object(nullptr_type_name); +void deserialize_nullptr(deserializer* source) { + source->begin_object(s_nullptr_type_name); source->end_object(); } -class void_type_tinfo : public util::abstract_uniform_type_info -{ +} // namespace + +class void_type_tinfo : public uniform_type_info { + + public: + + void_type_tinfo() : uniform_type_info(to_uniform_name()) {} + + bool equals(const std::type_info &tinfo) const { + return typeid(util::void_type) == tinfo; + } protected: - void serialize(const void*, serializer* sink) const - { + void serialize(const void*, serializer* sink) const { serialize_nullptr(sink); } - void deserialize(void*, deserializer* source) const - { + void deserialize(void*, deserializer* source) const { std::string cname = source->seek_object(); - if (cname != name()) - { + if (cname != name()) { throw std::logic_error("wrong type name found"); } deserialize_nullptr(source); } + bool equals(const void*, const void*) const { + return true; + } + + void* new_instance(const void*) const { + // const_cast cannot cause any harm, because void_type is immutable + return const_cast(static_cast(&m_value)); + } + + void delete_instance(void* instance) const { + CPPA_REQUIRE(instance == &m_value); + // keep compiler happy (suppress unused argument warning) + static_cast(instance); + } + + private: + + util::void_type m_value; + }; -class actor_ptr_tinfo : public util::abstract_uniform_type_info -{ +class actor_ptr_tinfo : public util::abstract_uniform_type_info { public: static void s_serialize(const actor_ptr& ptr, serializer* sink, - const std::string name) - { - if (ptr == nullptr) - { + const std::string& name) { + if (ptr == nullptr) { serialize_nullptr(sink); } - else - { - if (ptr->is_proxy() == false) - { + else { + if (ptr->is_proxy() == false) { singleton_manager::get_actor_registry()->put(ptr->id(), ptr); } primitive_variant ptup[3]; @@ -206,23 +196,18 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info static void s_deserialize(actor_ptr& ptrref, deserializer* source, - const std::string name) - { + const std::string& name) { std::string cname = source->seek_object(); - if (cname != name) - { - if (cname == nullptr_type_name) - { + if (cname != name) { + if (cname == s_nullptr_type_name) { deserialize_nullptr(source); ptrref.reset(); } - else - { + else { throw std::logic_error("wrong type name found"); } } - else - { + else { primitive_variant ptup[3]; primitive_type ptypes[] = { pt_uint32, pt_uint32, pt_u8string }; source->begin_object(cname); @@ -232,54 +217,51 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info // local actor? auto pinf = process_information::get(); if ( pinf->process_id() == get(ptup[1]) - && cppa::equal(nstr, pinf->node_id())) - { + && cppa::equal(nstr, pinf->node_id())) { auto id = get(ptup[0]); ptrref = singleton_manager::get_actor_registry()->get(id); //ptrref = actor::by_id(get(ptup[0])); } - else - { + else { + /* actor_proxy_cache::key_tuple key; std::get<0>(key) = get(ptup[0]); std::get<1>(key) = get(ptup[1]); node_id_from_string(nstr, std::get<2>(key)); ptrref = detail::get_actor_proxy_cache().get(key); + */ + process_information::node_id_type nid; + node_id_from_string(nstr, nid); + ptrref = detail::get_actor_proxy_cache().get(get(ptup[0]), + get(ptup[1]), + nid); } } } protected: - void serialize(const void* ptr, serializer* sink) const - { - s_serialize(*reinterpret_cast(ptr), - sink, - name()); + void serialize(const void* ptr, serializer* sink) const { + s_serialize(*reinterpret_cast(ptr), sink, name()); } - void deserialize(void* ptr, deserializer* source) const - { + void deserialize(void* ptr, deserializer* source) const { s_deserialize(*reinterpret_cast(ptr), source, name()); } }; -class group_ptr_tinfo : public util::abstract_uniform_type_info -{ +class group_ptr_tinfo : public util::abstract_uniform_type_info { public: static void s_serialize(const group_ptr& ptr, serializer* sink, - const std::string& name) - { - if (ptr == nullptr) - { + const std::string& name) { + if (ptr == nullptr) { serialize_nullptr(sink); } - else - { + else { sink->begin_object(name); sink->write_value(ptr->module_name()); sink->write_value(ptr->identifier()); @@ -289,23 +271,18 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info static void s_deserialize(group_ptr& ptrref, deserializer* source, - const std::string& name) - { + const std::string& name) { std::string cname = source->seek_object(); - if (cname != name) - { - if (cname == nullptr_type_name) - { + if (cname != name) { + if (cname == s_nullptr_type_name) { deserialize_nullptr(source); ptrref.reset(); } - else - { + else { throw std::logic_error("wrong type name found"); } } - else - { + else { source->begin_object(name); auto modname = source->read_value(pt_u8string); auto groupid = source->read_value(pt_u8string); @@ -317,22 +294,19 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info protected: - void serialize(const void* ptr, serializer* sink) const - { + void serialize(const void* ptr, serializer* sink) const { s_serialize(*reinterpret_cast(ptr), sink, name()); } - void deserialize(void* ptr, deserializer* source) const - { + void deserialize(void* ptr, deserializer* source) const { s_deserialize(*reinterpret_cast(ptr), source, name()); } }; -class channel_ptr_tinfo : public util::abstract_uniform_type_info -{ +class channel_ptr_tinfo : public util::abstract_uniform_type_info { std::string group_ptr_name; std::string actor_ptr_name; @@ -343,27 +317,21 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info serializer* sink, const std::string& channel_type_name, const std::string& actor_ptr_type_name, - const std::string& group_ptr_type_name) - { + const std::string& group_ptr_type_name) { sink->begin_object(channel_type_name); - if (ptr == nullptr) - { + if (ptr == nullptr) { serialize_nullptr(sink); } - else - { + else { group_ptr gptr; auto aptr = ptr.downcast(); - if (aptr) - { + if (aptr) { actor_ptr_tinfo::s_serialize(aptr, sink, actor_ptr_type_name); } - else if ((gptr = ptr.downcast())) - { + else if ((gptr = ptr.downcast())) { group_ptr_tinfo::s_serialize(gptr, sink, group_ptr_type_name); } - else - { + else { throw std::logic_error("channel is neither " "an actor nor a group"); } @@ -375,35 +343,28 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info deserializer* source, const std::string& name, const std::string& actor_ptr_type_name, - const std::string& group_ptr_type_name) - { + const std::string& group_ptr_type_name) { std::string cname = source->seek_object(); - if (cname != name) - { + if (cname != name) { throw std::logic_error("wrong type name found"); } source->begin_object(cname); std::string subobj = source->peek_object(); - if (subobj == actor_ptr_type_name) - { + if (subobj == actor_ptr_type_name) { actor_ptr tmp; actor_ptr_tinfo::s_deserialize(tmp, source, actor_ptr_type_name); ptrref = tmp; } - else if (subobj == group_ptr_type_name) - { + else if (subobj == group_ptr_type_name) { group_ptr tmp; group_ptr_tinfo::s_deserialize(tmp, source, group_ptr_type_name); ptrref = tmp; } - else if (subobj == nullptr_type_name) - { - (void) source->seek_object(); + else if (subobj == s_nullptr_type_name) { (void) source->seek_object(); deserialize_nullptr(source); ptrref.reset(); } - else - { + else { throw std::logic_error("unexpected type name: " + subobj); } source->end_object(); @@ -411,8 +372,7 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info protected: - void serialize(const void* instance, serializer* sink) const - { + void serialize(const void* instance, serializer* sink) const { s_serialize(*reinterpret_cast(instance), sink, name(), @@ -420,8 +380,7 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info group_ptr_name); } - void deserialize(void* instance, deserializer* source) const - { + void deserialize(void* instance, deserializer* source) const { s_deserialize(*reinterpret_cast(instance), source, name(), @@ -432,25 +391,20 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info public: channel_ptr_tinfo() : group_ptr_name(to_uniform_name(typeid(group_ptr))) - , actor_ptr_name(to_uniform_name(typeid(actor_ptr))) - { - } + , actor_ptr_name(to_uniform_name(typeid(actor_ptr))) { } }; -class any_tuple_tinfo : public util::abstract_uniform_type_info -{ +class any_tuple_tinfo : public util::abstract_uniform_type_info { public: static void s_serialize(const any_tuple& atup, serializer* sink, - const std::string& name) - { + const std::string& name) { sink->begin_object(name); sink->begin_sequence(atup.size()); - for (size_t i = 0; i < atup.size(); ++i) - { + for (size_t i = 0; i < atup.size(); ++i) { atup.type_at(i)->serialize(atup.at(i), sink); } sink->end_sequence(); @@ -459,40 +413,35 @@ class any_tuple_tinfo : public util::abstract_uniform_type_info static void s_deserialize(any_tuple& atref, deserializer* source, - const std::string& name) - { + const std::string& name) { auto result = new detail::object_array; auto str = source->seek_object(); if (str != name) throw std::logic_error("invalid type found: " + str); source->begin_object(str); size_t tuple_size = source->begin_sequence(); - for (size_t i = 0; i < tuple_size; ++i) - { + for (size_t i = 0; i < tuple_size; ++i) { auto tname = source->peek_object(); auto utype = uniform_type_info::from(tname); result->push_back(utype->deserialize(source)); } source->end_sequence(); source->end_object(); - atref = any_tuple(result); + atref = any_tuple{result}; } protected: - void serialize(const void* instance, serializer* sink) const - { + void serialize(const void* instance, serializer* sink) const { s_serialize(*reinterpret_cast(instance),sink,name()); } - void deserialize(void* instance, deserializer* source) const - { + void deserialize(void* instance, deserializer* source) const { s_deserialize(*reinterpret_cast(instance), source, name()); } }; -class addr_msg_tinfo : public util::abstract_uniform_type_info -{ +class addr_msg_tinfo : public util::abstract_uniform_type_info { std::string any_tuple_name; std::string actor_ptr_name; @@ -501,10 +450,9 @@ class addr_msg_tinfo : public util::abstract_uniform_type_info(instance); - const any_tuple& data = msg.content(); + virtual void serialize(const void* instance, serializer* sink) const { + auto& msg = *reinterpret_cast(instance); + auto& data = msg.content(); sink->begin_object(name()); actor_ptr_tinfo::s_serialize(msg.sender(), sink, actor_ptr_name); channel_ptr_tinfo::s_serialize(msg.receiver(), @@ -516,12 +464,11 @@ class addr_msg_tinfo : public util::abstract_uniform_type_infoend_object(); } - virtual void deserialize(void* instance, deserializer* source) const - { + virtual void deserialize(void* instance, deserializer* source) const { auto tname = source->seek_object(); if (tname != name()) throw 42; source->begin_object(tname); - addressed_message& msg = *reinterpret_cast(instance); + auto& msg = *reinterpret_cast(instance); //actor_ptr sender; //channel_ptr receiver; //any_tuple content; @@ -538,30 +485,72 @@ class addr_msg_tinfo : public util::abstract_uniform_type_info()) + , actor_ptr_name(to_uniform_name()) + , group_ptr_name(to_uniform_name()) + , channel_ptr_name(to_uniform_name()) { } + +}; + +class process_info_ptr_tinfo : public util::abstract_uniform_type_info { + + typedef process_information_ptr ptr_type; + + public: + + virtual void serialize(const void* instance, serializer* sink) const { + auto& ptr = *reinterpret_cast(instance); + if (ptr == nullptr) { + serialize_nullptr(sink); + } + else { + primitive_variant ptup[2]; + ptup[0] = ptr->process_id(); + ptup[1] = to_string(ptr->node_id()); + sink->begin_object(name()); + sink->write_tuple(2, ptup); + sink->end_object(); + } + } + + virtual void deserialize(void* instance, deserializer* source) const { + auto& ptrref = *reinterpret_cast(instance); + std::string cname = source->seek_object(); + if (cname != name()) { + if (cname == s_nullptr_type_name) { + deserialize_nullptr(source); + ptrref.reset(); + } + else { + throw std::logic_error("wrong type name found"); + } + } + else { + primitive_variant ptup[2]; + primitive_type ptypes[] = { pt_uint32, pt_u8string }; + source->begin_object(cname); + source->read_tuple(2, ptypes, ptup); + source->end_object(); + process_information::node_id_type nid; + node_id_from_string(get(ptup[1]), nid); + ptrref.reset(new process_information{get(ptup[0]), nid}); + } } }; -class atom_value_tinfo : public util::abstract_uniform_type_info -{ +class atom_value_tinfo : public util::abstract_uniform_type_info { public: - virtual void serialize(const void* instance, serializer* sink) const - { + virtual void serialize(const void* instance, serializer* sink) const { auto val = reinterpret_cast(instance); sink->begin_object(name()); sink->write_value(static_cast(*val)); sink->end_object(); } - virtual void deserialize(void* instance, deserializer* source) const - { + virtual void deserialize(void* instance, deserializer* source) const { auto val = reinterpret_cast(instance); auto tname = source->seek_object(); if (tname != name()) throw 42; @@ -573,11 +562,9 @@ class atom_value_tinfo : public util::abstract_uniform_type_info }; -class duration_tinfo : public util::abstract_uniform_type_info -{ +class duration_tinfo : public util::abstract_uniform_type_info { - virtual void serialize(const void* instance, serializer* sink) const - { + virtual void serialize(const void* instance, serializer* sink) const { auto val = reinterpret_cast(instance); sink->begin_object(name()); sink->write_value(static_cast(val->unit)); @@ -585,8 +572,7 @@ class duration_tinfo : public util::abstract_uniform_type_info sink->end_object(); } - virtual void deserialize(void* instance, deserializer* source) const - { + virtual void deserialize(void* instance, deserializer* source) const { auto val = reinterpret_cast(instance); auto tname = source->seek_object(); if (tname != name()) throw 42; @@ -594,8 +580,7 @@ class duration_tinfo : public util::abstract_uniform_type_info auto unit_val = source->read_value(pt_uint32); auto count_val = source->read_value(pt_uint32); source->end_object(); - switch (get(unit_val)) - { + switch (get(unit_val)) { case 1: val->unit = util::time_unit::seconds; break; @@ -618,184 +603,131 @@ class duration_tinfo : public util::abstract_uniform_type_info }; template -class int_tinfo : public detail::default_uniform_type_info_impl -{ +class int_tinfo : public detail::default_uniform_type_info_impl { public: - bool equals(const std::type_info& tinfo) const - { + bool equals(const std::type_info& tinfo) const { // TODO: string comparsion sucks & is slow; find a nicer solution auto map_iter = uti_map().int_names().find(sizeof(T)); const string_set& st = is_signed::value ? map_iter->second.first : map_iter->second.second; auto x = raw_name(tinfo); return std::any_of(st.begin(), st.end(), - [&](const std::string& y) { return x == y; }); + [&x](const std::string& y) { return x == y; }); } }; -using std::is_integral; -using std::enable_if; +class uniform_type_info_map_helper { -class uniform_type_info_map_helper -{ - - friend class uniform_type_info_map; - - typedef uniform_type_info_map* this_ptr; + public: - static void insert(this_ptr d, - uniform_type_info* uti, - const std::set& tnames) - { - CPPA_REQUIRE(tnames.empty() == false); - for (const std::string& tname : tnames) - { - d->m_by_rname.insert(std::make_pair(tname, uti)); - } - d->m_by_uname.insert(std::make_pair(uti->name(), uti)); - } + uniform_type_info_map_helper(uniform_type_info_map* umap) : d(umap) { } template - static inline void insert(this_ptr d, - const std::set& tnames, - typename enable_if::value>::type* = 0) - { - insert(d, new int_tinfo, tnames); + inline void insert_int() { + d->insert(d->m_ints[sizeof(T)].first, new int_tinfo); } template - static inline void insert(this_ptr d, - const std::set& tnames, - typename enable_if::value>::type* = 0) - { - insert(d, new default_uniform_type_info_impl(), tnames); + inline void insert_uint() { + d->insert(d->m_ints[sizeof(T)].second, new int_tinfo); } template - static inline void insert(this_ptr d) - { - insert(d, {std::string(raw_name())}); - } - - static void init(this_ptr d) - { - insert(d); - insert(d); - insert(d); - insert(d, new duration_tinfo, { raw_name() }); - insert(d, new any_tuple_tinfo, { raw_name() }); - insert(d, new actor_ptr_tinfo, { raw_name() }); - insert(d, new group_ptr_tinfo, { raw_name() }); - insert(d, new channel_ptr_tinfo, { raw_name() }); - //insert(d, new message_tinfo, { raw_name() }); - insert(d, new atom_value_tinfo, { raw_name() }); - insert(d, new addr_msg_tinfo, {raw_name() }); - insert(d, new void_type_tinfo, { raw_name() }); - insert(d); - insert(d); - /* - if (sizeof(double) == sizeof(long double)) - { - std::string dbl = raw_name(); - std::string ldbl = raw_name(); - insert(d, { dbl, ldbl }); - } - else - { - insert(d); - insert(d); - } - */ - // first: signed - // second: unsigned - push(d->m_ints); - insert(d, d->m_ints[sizeof(std::int8_t)].first); - insert(d, d->m_ints[sizeof(std::uint8_t)].second); - insert(d, d->m_ints[sizeof(std::int16_t)].first); - insert(d, d->m_ints[sizeof(std::uint16_t)].second); - insert(d, d->m_ints[sizeof(std::int32_t)].first); - insert(d, d->m_ints[sizeof(std::uint32_t)].second); - insert(d, d->m_ints[sizeof(std::int64_t)].first); - insert(d, d->m_ints[sizeof(std::uint64_t)].second); + inline void insert_builtin() { + d->insert({raw_name()}, new default_uniform_type_info_impl); } + private: + + uniform_type_info_map* d; + }; -uniform_type_info_map::uniform_type_info_map() -{ - uniform_type_info_map_helper::init(this); +uniform_type_info_map::uniform_type_info_map() { + // inserts all compiler generated raw-names to m_ings + push(m_ints); + uniform_type_info_map_helper helper{this}; + // inserts integer type infos + helper.insert_int(); + helper.insert_int(); + helper.insert_int(); + helper.insert_int(); + helper.insert_uint(); + helper.insert_uint(); + helper.insert_uint(); + helper.insert_uint(); + // insert type infos for "built-in" types + helper.insert_builtin(); + helper.insert_builtin(); + helper.insert_builtin(); + helper.insert_builtin(); + helper.insert_builtin(); + // insert cppa types + insert({raw_name()}, new duration_tinfo); + insert({raw_name()}, new any_tuple_tinfo); + insert({raw_name()}, new actor_ptr_tinfo); + insert({raw_name()}, new group_ptr_tinfo); + insert({raw_name()}, new channel_ptr_tinfo); + insert({raw_name()}, new atom_value_tinfo); + insert({raw_name()}, new addr_msg_tinfo); + insert({raw_name()}, new void_type_tinfo); + insert({raw_name()}, new process_info_ptr_tinfo); } -uniform_type_info_map::~uniform_type_info_map() -{ +uniform_type_info_map::~uniform_type_info_map() { m_by_rname.clear(); - for (auto& kvp : m_by_uname) - { + for (auto& kvp : m_by_uname) { delete kvp.second; kvp.second = nullptr; } m_by_uname.clear(); } -uniform_type_info* uniform_type_info_map::by_raw_name(const std::string& name) const -{ +const uniform_type_info* uniform_type_info_map::by_raw_name(const std::string& name) const { auto i = m_by_rname.find(name); - if (i != m_by_rname.end()) - { + if (i != m_by_rname.end()) { return i->second; } return nullptr; } -uniform_type_info* uniform_type_info_map::by_uniform_name(const std::string& name) const -{ +const uniform_type_info* uniform_type_info_map::by_uniform_name(const std::string& name) const { auto i = m_by_uname.find(name); - if (i != m_by_uname.end()) - { + if (i != m_by_uname.end()) { return i->second; } return nullptr; } bool uniform_type_info_map::insert(const std::set& raw_names, - uniform_type_info* what) -{ - if (m_by_uname.count(what->name()) > 0) - { + uniform_type_info* what) { + if (m_by_uname.count(what->name()) > 0) { delete what; return false; } m_by_uname.insert(std::make_pair(what->name(), what)); - for (const std::string& plain_name : raw_names) - { - if (!m_by_rname.insert(std::make_pair(plain_name, what)).second) - { + for (auto& plain_name : raw_names) { + if (!m_by_rname.insert(std::make_pair(plain_name, what)).second) { std::string error_str = plain_name; error_str += " already mapped to an uniform_type_info"; throw std::runtime_error(error_str); @@ -804,12 +736,10 @@ bool uniform_type_info_map::insert(const std::set& raw_names, return true; } -std::vector uniform_type_info_map::get_all() const -{ - std::vector result; +std::vector uniform_type_info_map::get_all() const { + std::vector result; result.reserve(m_by_uname.size()); - for (const uti_map::value_type& i : m_by_uname) - { + for (const uti_map_type::value_type& i : m_by_uname) { result.push_back(i.second); } return std::move(result); @@ -819,30 +749,22 @@ std::vector uniform_type_info_map::get_all() const namespace cppa { -bool announce(const std::type_info& tinfo, uniform_type_info* utype) -{ - return uti_map().insert({ raw_name(tinfo) }, utype); +bool announce(const std::type_info& tinfo, uniform_type_info* utype) { + return detail::uti_map().insert({detail::raw_name(tinfo)}, utype); } -uniform_type_info::uniform_type_info(const std::string& uname) : m_name(uname) -{ -} +uniform_type_info::uniform_type_info(const std::string& str) : m_name(str) { } -uniform_type_info::~uniform_type_info() -{ +uniform_type_info::~uniform_type_info() { } -object uniform_type_info::create() const -{ - return { new_instance(), this }; +object uniform_type_info::create() const { + return {new_instance(), this}; } -const uniform_type_info* -uniform_type_info::from(const std::type_info& tinf) -{ - auto result = uti_map().by_raw_name(raw_name(tinf)); - if (!result) - { +const uniform_type_info* uniform_type_info::from(const std::type_info& tinf) { + auto result = detail::uti_map().by_raw_name(detail::raw_name(tinf)); + if (result == nullptr) { std::string error = "uniform_type_info::by_type_info(): "; error += detail::to_uniform_name(tinf); error += " is an unknown typeid name"; @@ -851,30 +773,25 @@ uniform_type_info::from(const std::type_info& tinf) return result; } -uniform_type_info* uniform_type_info::from(const std::string& name) -{ - auto result = uti_map().by_uniform_name(name); - if (!result) - { +const uniform_type_info* uniform_type_info::from(const std::string& name) { + auto result = detail::uti_map().by_uniform_name(name); + if (result == nullptr) { throw std::runtime_error(name + " is an unknown typeid name"); } return result; } -object uniform_type_info::deserialize(deserializer* from) const -{ +object uniform_type_info::deserialize(deserializer* from) const { auto ptr = new_instance(); deserialize(ptr, from); - return { ptr, this }; + return {ptr, this}; } -std::vector uniform_type_info::instances() -{ - return uti_map().get_all(); +std::vector uniform_type_info::instances() { + return detail::uti_map().get_all(); } -const uniform_type_info* uniform_typeid(const std::type_info& tinfo) -{ +const uniform_type_info* uniform_typeid(const std::type_info& tinfo) { return uniform_type_info::from(tinfo); } diff --git a/src/yield_interface.cpp b/src/yield_interface.cpp index 871dcdc55f..674878e789 100644 --- a/src/yield_interface.cpp +++ b/src/yield_interface.cpp @@ -44,14 +44,12 @@ __thread util::fiber* t_callee = nullptr; namespace cppa { namespace detail { -void yield(yield_state ystate) -{ +void yield(yield_state ystate) { *t_ystate = ystate; util::fiber::swap(*t_callee, *t_caller); } -yield_state call(util::fiber* what, util::fiber* from) -{ +yield_state call(util::fiber* what, util::fiber* from) { yield_state result; t_ystate = &result; t_caller = from; diff --git a/src/yielding_actor.cpp b/src/yielding_actor.cpp deleted file mode 100644 index bf973bda72..0000000000 --- a/src/yielding_actor.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/******************************************************************************\ - * ___ __ * - * /\_ \ __/\ \ * - * \//\ \ /\_\ \ \____ ___ _____ _____ __ * - * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * - * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * - * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * - * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * - * \ \_\ \ \_\ * - * \/_/ \/_/ * - * * - * Copyright (C) 2011, 2012 * - * Dominik Charousset * - * * - * This file is part of libcppa. * - * libcppa is free software: you can redistribute it and/or modify it under * - * the terms of the GNU Lesser General Public License as published by the * - * Free Software Foundation, either version 3 of the License * - * or (at your option) any later version. * - * * - * libcppa is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with libcppa. If not, see . * -\******************************************************************************/ - - -#include "cppa/detail/yielding_actor.hpp" -#ifndef CPPA_DISABLE_CONTEXT_SWITCHING - -#include - -#include "cppa/cppa.hpp" -#include "cppa/self.hpp" -#include "cppa/detail/invokable.hpp" - -namespace cppa { namespace detail { - -yielding_actor::yielding_actor(scheduled_actor* behavior, scheduler* sched) - : super(sched) - , m_fiber(&yielding_actor::run, this) - , m_behavior(behavior) -{ -} - -yielding_actor::~yielding_actor() -{ - delete m_behavior; -} - -void yielding_actor::run(void* ptr_arg) -{ - auto this_ptr = reinterpret_cast(ptr_arg); - auto behavior_ptr = this_ptr->m_behavior; - if (behavior_ptr) - { - bool cleanup_called = false; - try { behavior_ptr->act(); } - catch (actor_exited&) - { - // cleanup already called by scheduled_actor::quit - cleanup_called = true; - } - catch (...) - { - this_ptr->cleanup(exit_reason::unhandled_exception); - cleanup_called = true; - } - if (!cleanup_called) this_ptr->cleanup(exit_reason::normal); - try { behavior_ptr->on_exit(); } - catch (...) { } - } - yield(yield_state::done); -} - - -void yielding_actor::yield_until_not_empty() -{ - if (m_mailbox.can_fetch_more() == false) - { - m_state.store(abstract_scheduled_actor::about_to_block); - CPPA_MEMORY_BARRIER(); - // make sure mailbox is 'empty' - if (m_mailbox.can_fetch_more() == false) - { - m_state.store(abstract_scheduled_actor::ready); - return; - } - else - { - yield(yield_state::blocked); - } - } -} - -void yielding_actor::dequeue(partial_function& fun) -{ - auto rm_fun = [&](queue_node_ptr& node) { return dq(*node, fun) == dq_done; }; - dequeue_impl(rm_fun); -} - -void yielding_actor::dequeue(behavior& bhvr) -{ - if (bhvr.timeout().valid()) - { - request_timeout(bhvr.timeout()); - auto rm_fun = [&](queue_node_ptr& node) -> bool - { - switch (dq(*node, bhvr.get_partial_function())) - { - case dq_timeout_occured: - bhvr.handle_timeout(); - return true; - case dq_done: - return true; - default: - return false; - } - }; - dequeue_impl(rm_fun); - } - else - { - // suppress virtual function call - yielding_actor::dequeue(bhvr.get_partial_function()); - } -} - -void yielding_actor::resume(util::fiber* from, resume_callback* callback) -{ - self.set(this); - for (;;) - { - switch (call(&m_fiber, from)) - { - case yield_state::done: - { - callback->exec_done(); - return; - } - case yield_state::ready: - { - break; - } - case yield_state::blocked: - { - switch (compare_exchange_state(abstract_scheduled_actor::about_to_block, - abstract_scheduled_actor::blocked)) - { - case abstract_scheduled_actor::ready: - { - break; - } - case abstract_scheduled_actor::blocked: - { - // wait until someone re-schedules that actor - return; - } - default: - { - // illegal state - exit(7); - } - } - break; - } - default: - { - // illegal state - exit(8); - } - } - } -} - -} } // namespace cppa::detail - -#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING - -namespace { int keep_compiler_happy() { return 42; } } - -#endif // ifdef CPPA_DISABLE_CONTEXT_SWITCHING diff --git a/third_party/boost_context/include/boost/context/all.hpp b/third_party/boost_context/include/boost/context/all.hpp new file mode 100644 index 0000000000..f9a4c71dbf --- /dev/null +++ b/third_party/boost_context/include/boost/context/all.hpp @@ -0,0 +1,14 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_ALL_H +#define BOOST_CTX_ALL_H + +#include +#include +#include + +#endif // BOOST_CTX_ALL_H diff --git a/third_party/boost_context/include/boost/context/detail/config.hpp b/third_party/boost_context/include/boost/context/detail/config.hpp new file mode 100644 index 0000000000..50ada3c507 --- /dev/null +++ b/third_party/boost_context/include/boost/context/detail/config.hpp @@ -0,0 +1,42 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_DETAIL_CONFIG_H +#define BOOST_CTX_DETAIL_CONFIG_H + +#include +#include + +#ifdef BOOST_CONTEXT_DECL +# undef BOOST_CONTEXT_DECL +#endif + +#if defined(BOOST_HAS_DECLSPEC) +# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTEXT_DYN_LINK) +# if ! defined(BOOST_DYN_LINK) +# define BOOST_DYN_LINK +# endif +# if defined(BOOST_CONTEXT_SOURCE) +# define BOOST_CONTEXT_DECL BOOST_SYMBOL_EXPORT +# else +# define BOOST_CONTEXT_DECL BOOST_SYMBOL_IMPORT +# endif +# endif +#endif + +#if ! defined(BOOST_CONTEXT_DECL) +# define BOOST_CONTEXT_DECL +#endif + +#if ! defined(BOOST_CONTEXT_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_CONTEXT_NO_LIB) +# define BOOST_LIB_NAME boost_context +# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTEXT_DYN_LINK) +# define BOOST_DYN_LINK +# endif +# include +#endif + +#endif // BOOST_CTX_DETAIL_CONFIG_H diff --git a/third_party/boost_context/include/boost/context/detail/fcontext_arm.hpp b/third_party/boost_context/include/boost/context/detail/fcontext_arm.hpp new file mode 100644 index 0000000000..1adceb7a92 --- /dev/null +++ b/third_party/boost_context/include/boost/context/detail/fcontext_arm.hpp @@ -0,0 +1,66 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_DETAIL_FCONTEXT_ARM_H +#define BOOST_CTX_DETAIL_FCONTEXT_ARM_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint32_t fc_freg[16]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ + boost::uint32_t fc_greg[11]; + stack_t fc_stack; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_ARM_H diff --git a/third_party/boost_context/include/boost/context/detail/fcontext_i386.hpp b/third_party/boost_context/include/boost/context/detail/fcontext_i386.hpp new file mode 100644 index 0000000000..77406e17c6 --- /dev/null +++ b/third_party/boost_context/include/boost/context/detail/fcontext_i386.hpp @@ -0,0 +1,68 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_DETAIL_FCONTEXT_I386H +#define BOOST_CTX_DETAIL_FCONTEXT_I386H + +#include + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL __attribute__((cdecl)) + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint32_t fc_freg[2]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ + boost::uint32_t fc_greg[6]; + stack_t fc_stack; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_I386_H diff --git a/third_party/boost_context/include/boost/context/detail/fcontext_i386_win.hpp b/third_party/boost_context/include/boost/context/detail/fcontext_i386_win.hpp new file mode 100644 index 0000000000..749981719e --- /dev/null +++ b/third_party/boost_context/include/boost/context/detail/fcontext_i386_win.hpp @@ -0,0 +1,79 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_DETAIL_FCONTEXT_I386H +#define BOOST_CTX_DETAIL_FCONTEXT_I386H + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include + +#include + +#pragma warning(push) +#pragma warning(disable:4351) + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL __cdecl + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint32_t fc_freg[2]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ + boost::uint32_t fc_greg[6]; + stack_t fc_stack; + void * fc_excpt_lst; + void * fc_local_storage; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_excpt_lst( 0), + fc_local_storage( 0), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#pragma warning(pop) + +#endif // BOOST_CTX_DETAIL_FCONTEXT_I386_H diff --git a/third_party/boost_context/include/boost/context/detail/fcontext_mips.hpp b/third_party/boost_context/include/boost/context/detail/fcontext_mips.hpp new file mode 100644 index 0000000000..068c482b32 --- /dev/null +++ b/third_party/boost_context/include/boost/context/detail/fcontext_mips.hpp @@ -0,0 +1,68 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_DETAIL_FCONTEXT_MIPS_H +#define BOOST_CTX_DETAIL_FCONTEXT_MIPS_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL + +// on MIPS we assume 64bit regsiters - even for 32bit ABIs + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint64_t fc_freg[6]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ + boost::uint64_t fc_greg[13]; + stack_t fc_stack; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_MIPS_H diff --git a/third_party/boost_context/include/boost/context/detail/fcontext_ppc.hpp b/third_party/boost_context/include/boost/context/detail/fcontext_ppc.hpp new file mode 100644 index 0000000000..a0b6ab1789 --- /dev/null +++ b/third_party/boost_context/include/boost/context/detail/fcontext_ppc.hpp @@ -0,0 +1,70 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_DETAIL_FCONTEXT_PPC_H +#define BOOST_CTX_DETAIL_FCONTEXT_PPC_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint64_t fc_freg[19]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ +# if defined(__powerpc64__) + boost::uint64_t fc_greg[23]; +# else + boost::uint32_t fc_greg[23]; +# endif + stack_t fc_stack; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_PPC_H diff --git a/third_party/boost_context/include/boost/context/detail/fcontext_x86_64.hpp b/third_party/boost_context/include/boost/context/detail/fcontext_x86_64.hpp new file mode 100644 index 0000000000..6e95337eb4 --- /dev/null +++ b/third_party/boost_context/include/boost/context/detail/fcontext_x86_64.hpp @@ -0,0 +1,66 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_DETAIL_FCONTEXT_X86_64_H +#define BOOST_CTX_DETAIL_FCONTEXT_X86_64_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint32_t fc_freg[2]; + + fp_t() : + fc_freg() + {} +}; + +struct fcontext_t +{ + boost::uint64_t fc_greg[8]; + stack_t fc_stack; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_DETAIL_FCONTEXT_X86_64_H diff --git a/third_party/boost_context/include/boost/context/detail/fcontext_x86_64_win.hpp b/third_party/boost_context/include/boost/context/detail/fcontext_x86_64_win.hpp new file mode 100644 index 0000000000..32d065b96a --- /dev/null +++ b/third_party/boost_context/include/boost/context/detail/fcontext_x86_64_win.hpp @@ -0,0 +1,86 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_DETAIL_FCONTEXT_X86_64_H +#define BOOST_CTX_DETAIL_FCONTEXT_X86_64_H + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include +#include + +#include + +#pragma warning(push) +#pragma warning(disable:4351) + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +extern "C" { + +#define BOOST_CONTEXT_CALLDECL + +struct stack_t +{ + void * base; + void * limit; + + stack_t() : + base( 0), limit( 0) + {} +}; + +struct fp_t +{ + boost::uint32_t fc_freg[2]; + void * fc_xmm; + char fc_buffer[175]; + + fp_t() : + fc_freg(), + fc_xmm( 0), + fc_buffer() + { + fc_xmm = fc_buffer; + if ( 0 != ( ( ( uintptr_t) fc_xmm) & 15) ) + fc_xmm = ( char *) ( ( ( ( uintptr_t) fc_xmm) + 15) & ~0x0F); + } +}; + +struct fcontext_t +{ + boost::uint64_t fc_greg[10]; + stack_t fc_stack; + void * fc_local_storage; + fp_t fc_fp; + + fcontext_t() : + fc_greg(), + fc_stack(), + fc_local_storage( 0), + fc_fp() + {} +}; + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#pragma warning(pop) + +#endif // BOOST_CTX_DETAIL_FCONTEXT_X86_64_H diff --git a/third_party/boost_context/include/boost/context/fcontext.hpp b/third_party/boost_context/include/boost/context/fcontext.hpp new file mode 100644 index 0000000000..d2cc030a1e --- /dev/null +++ b/third_party/boost_context/include/boost/context/fcontext.hpp @@ -0,0 +1,82 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_FCONTEXT_H +#define BOOST_CTX_FCONTEXT_H + +#if defined(__PGI) +#include +#endif + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +// x86_64 +// test x86_64 before i386 because icc might +// define __i686__ for x86_64 too +#if defined(__x86_64__) || defined(__x86_64) \ + || defined(__amd64__) || defined(__amd64) \ + || defined(_M_X64) || defined(_M_AMD64) +# if defined(BOOST_WINDOWS) +# include +# else +# include +# endif +// i386 +#elif defined(i386) || defined(__i386__) || defined(__i386) \ + || defined(__i486__) || defined(__i586__) || defined(__i686__) \ + || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \ + || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \ + || defined(_M_IX86) || defined(_I86_) +# if defined(BOOST_WINDOWS) +# include +# else +# include +# endif +// arm +#elif defined(__arm__) || defined(__thumb__) || defined(__TARGET_ARCH_ARM) \ + || defined(__TARGET_ARCH_THUMB) || defined(_ARM) +# include +// mips +#elif (defined(__mips) && __mips == 1) || defined(_MIPS_ISA_MIPS1) \ + || defined(_R3000) +# include +// powerpc +#elif defined(__powerpc) || defined(__powerpc__) || defined(__ppc) \ + || defined(__ppc__) || defined(_ARCH_PPC) || defined(__POWERPC__) \ + || defined(__PPCGECKO__) || defined(__PPCBROADWAY) || defined(_XENON) +# include +#else +# error "platform not supported" +#endif + +namespace boost { +namespace ctx { +namespace detail { + +extern "C" BOOST_CONTEXT_DECL void * BOOST_CONTEXT_CALLDECL align_stack( void * vp); + +} + +extern "C" BOOST_CONTEXT_DECL +intptr_t BOOST_CONTEXT_CALLDECL jump_fcontext( fcontext_t * ofc, fcontext_t const* nfc, intptr_t vp, bool preserve_fpu = true); +extern "C" BOOST_CONTEXT_DECL +void BOOST_CONTEXT_CALLDECL make_fcontext( fcontext_t * fc, void (* fn)( intptr_t) ); + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_FCONTEXT_H + diff --git a/third_party/boost_context/include/boost/context/stack_allocator.hpp b/third_party/boost_context/include/boost/context/stack_allocator.hpp new file mode 100644 index 0000000000..0db50157d1 --- /dev/null +++ b/third_party/boost_context/include/boost/context/stack_allocator.hpp @@ -0,0 +1,37 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_STACK_ALLOCATOR_H +#define BOOST_CTX_STACK_ALLOCATOR_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +class BOOST_CONTEXT_DECL stack_allocator +{ +public: + void * allocate( std::size_t) const; + + void deallocate( void *, std::size_t) const; +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_STACK_ALLOCATOR_H diff --git a/third_party/boost_context/include/boost/context/stack_utils.hpp b/third_party/boost_context/include/boost/context/stack_utils.hpp new file mode 100644 index 0000000000..ca3ed2135f --- /dev/null +++ b/third_party/boost_context/include/boost/context/stack_utils.hpp @@ -0,0 +1,41 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CTX_STACK_UTILS_H +#define BOOST_CTX_STACK_UTILS_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +BOOST_CONTEXT_DECL std::size_t default_stacksize(); + +BOOST_CONTEXT_DECL std::size_t minimum_stacksize(); + +BOOST_CONTEXT_DECL std::size_t maximum_stacksize(); + +BOOST_CONTEXT_DECL std::size_t pagesize(); + +BOOST_CONTEXT_DECL std::size_t page_count( std::size_t stacksize); + +BOOST_CONTEXT_DECL bool is_stack_unbound(); + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CTX_STACK_UTILS_H diff --git a/third_party/boost_context/src/asm/fcontext_arm_aapcs_elf_gas.S b/third_party/boost_context/src/asm/fcontext_arm_aapcs_elf_gas.S new file mode 100644 index 0000000000..0f1f8fb646 --- /dev/null +++ b/third_party/boost_context/src/asm/fcontext_arm_aapcs_elf_gas.S @@ -0,0 +1,98 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************* + * * + * ------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | * + * ------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| 0x20| 0x24| * + * ------------------------------------------------------------- * + * | v1 | v2 | v3 | v4 | v5 | v6 | v7 | v8 | sp | lr | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 10 | | * + * ------------------------------------------------------------- * + * | 0x28| | * + * ------------------------------------------------------------- * + * | pc | | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 11 | 12 | | * + * ------------------------------------------------------------- * + * | 0x2c| 0x30| | * + * ------------------------------------------------------------- * + * |sbase|slimit| | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | * + * ------------------------------------------------------------- * + * | 0x34| 0x38|0x3c| 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58 | * + * ------------------------------------------------------------- * + * | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | s24 | s25 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 23 | 24 | 25 | 26 | 27 | 28 | | * + * ------------------------------------------------------------- * + * | 0x5c| 0x60| 0x64| 0x68| 0x6c| 0x70| | * + * ------------------------------------------------------------- * + * | s26 | s27 | s28 | s29 | s30 | s31 | | * + * ------------------------------------------------------------- * + * * + * *****************************************************************/ + +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,%function +jump_fcontext: + stmia a1, {v1-v8,sp-lr} @ save V1-V8,SP-LR + str lr, [a1,#40] @ save LR as PC +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + cmp a4, #0 @ test if fpu env should be preserved + be 1f + + ldr a4, [a1,#52] + stmia a4, {s16-s31} @ save S16-S31 + + ldr a4, [a2,#52] + ldmia a4, {s16-s31} @ restore S16-S31 +1: +#endif + + mov a1, a3 @ use third arg as return value after jump + @ and as first arg in context function + ldmia a2, {v1-v8,sp-pc} @ restore v1-V8,SP-PC +.size jump_fcontext,.-jump_fcontext + +.text +.globl make_fcontext +.align 2 +.type make_fcontext,%function +make_fcontext: + str a1, [a1,#0] @ save the address of passed context + str a2, [a1,#40] @ save address of the context function + ldr a2, [a1,#44] @ load the stack base + + push {a1,lr} @ save pointer to fcontext_t + mov a1, a2 @ stack pointer as arg for align_stack + bl align_stack@PLT @ align stack + mov a2, a1 @ begin of aligned stack + pop {a1,lr} @ restore pointer to fcontext_t + + str a2, [a1,#32] @ save the aligned stack base + + adr a2, finish @ address of finish; called after context function returns + str a2, [a1,#36] + + mov a1, #0 + bx lr + +finish: + mov a1, #0 @ exit code is zero + bl _exit@PLT @ exit application +.size make_fcontext,.-make_fcontext diff --git a/third_party/boost_context/src/asm/fcontext_i386_ms_pe_masm.asm b/third_party/boost_context/src/asm/fcontext_i386_ms_pe_masm.asm new file mode 100644 index 0000000000..0f4dd671b1 --- /dev/null +++ b/third_party/boost_context/src/asm/fcontext_i386_ms_pe_masm.asm @@ -0,0 +1,151 @@ + +; Copyright Oliver Kowalke 2009. +; Distributed under the Boost Software License, Version 1.0. +; (See accompanying file LICENSE_1_0.txt or copy at +; http://www.boost.org/LICENSE_1_0.txt) + +; -------------------------------------------------------------- +; | 0 | 1 | 2 | 3 | 4 | 5 | +; -------------------------------------------------------------- +; | 0h | 04h | 08h | 0ch | 010h | 014h | +; -------------------------------------------------------------- +; | EDI | ESI | EBX | EBP | ESP | EIP | +; -------------------------------------------------------------- +; -------------------------------------------------------------- +; | 6 | 7 | | +; -------------------------------------------------------------- +; | 018h | 01ch | | +; -------------------------------------------------------------- +; | ss_base | ss_limit| | +; -------------------------------------------------------------- +; -------------------------------------------------------------- +; | 8 | | +; -------------------------------------------------------------- +; | 020h | | +; -------------------------------------------------------------- +; |fc_execpt| | +; -------------------------------------------------------------- +; -------------------------------------------------------------- +; | 9 | | +; -------------------------------------------------------------- +; | 024h | | +; -------------------------------------------------------------- +; |fc_strage| | +; -------------------------------------------------------------- +; -------------------------------------------------------------- +; | 10 | 11 | | +; -------------------------------------------------------------- +; | 028h | 02ch | | +; -------------------------------------------------------------- +; | fc_mxcsr|fc_x87_cw| | +; -------------------------------------------------------------- + +.386 +.XMM +.model flat, c +_exit PROTO, value:SDWORD +align_stack PROTO, vp:DWORD +seh_fcontext PROTO, except:DWORD, frame:DWORD, context:DWORD, dispatch:DWORD +.code + +jump_fcontext PROC EXPORT + mov ecx, [esp+04h] ; load address of the first fcontext_t arg + mov [ecx], edi ; save EDI + mov [ecx+04h], esi ; save ESI + mov [ecx+08h], ebx ; save EBX + mov [ecx+0ch], ebp ; save EBP + + assume fs:nothing + mov edx, fs:[018h] ; load NT_TIB + assume fs:error + mov eax, [edx] ; load current SEH exception list + mov [ecx+020h], eax ; save current exception list + mov eax, [edx+04h] ; load current stack base + mov [ecx+018h], eax ; save current stack base + mov eax, [edx+08h] ; load current stack limit + mov [ecx+01ch], eax ; save current stack limit + mov eax, [edx+010h] ; load fiber local storage + mov [ecx+024h], eax ; save fiber local storage + + lea eax, [esp+04h] ; exclude the return address + mov [ecx+010h], eax ; save as stack pointer + mov eax, [esp] ; load return address + mov [ecx+014h], eax ; save return address + + mov edx, [esp+08h] ; load address of the second fcontext_t arg + mov edi, [edx] ; restore EDI + mov esi, [edx+04h] ; restore ESI + mov ebx, [edx+08h] ; restore EBX + mov ebp, [edx+0ch] ; restore EBP + + mov eax, [esp+010h] ; check if fpu enve preserving was requested + test eax, eax + je nxt + + stmxcsr [ecx+028h] ; save MMX control word + fnstcw [ecx+02ch] ; save x87 control word + ldmxcsr [edx+028h] ; restore MMX control word + fldcw [edx+02ch] ; restore x87 control word +nxt: + mov ecx, edx + assume fs:nothing + mov edx, fs:[018h] ; load NT_TIB + assume fs:error + mov eax, [ecx+020h] ; load SEH exception list + mov [edx], eax ; restore next SEH item + mov eax, [ecx+018h] ; load stack base + mov [edx+04h], eax ; restore stack base + mov eax, [ecx+01ch] ; load stack limit + mov [edx+08h], eax ; restore stack limit + mov eax, [ecx+024h] ; load fiber local storage + mov [edx+010h], eax ; restore fiber local storage + + mov eax, [esp+0ch] ; use third arg as return value after jump + + mov esp, [ecx+010h] ; restore ESP + mov [esp+04h], eax ; use third arg as first arg in context function + mov ecx, [ecx+014h] ; fetch the address to return to + + jmp ecx ; indirect jump to context +jump_fcontext ENDP + +make_fcontext PROC EXPORT + mov eax, [esp+04h] ; load address of the fcontext_t arg0 + mov [eax], eax ; save the address of passed context + mov ecx, [esp+08h] ; load the address of the context function + mov [eax+014h], ecx ; save the address of the context function + mov edx, [eax+018h] ; load the stack base + + push eax ; save pointer to fcontext_t + push edx ; stack pointer as arg for align_stack + call align_stack ; align stack + mov edx, eax ; begin of aligned stack + pop eax ; remove arg for align_stack + pop eax ; restore pointer to fcontext_t + + lea edx, [edx-014h] ; reserve space for last frame on stack, (ESP + 4) & 15 == 0 + mov [eax+010h], edx ; save the aligned stack + + mov ecx, seh_fcontext ; set ECX to exception-handler + mov [edx+0ch], ecx ; save ECX as SEH handler + mov ecx, 0ffffffffh ; set ECX to -1 + mov [edx+08h], ecx ; save ECX as next SEH item + lea ecx, [edx+08h] ; load address of next SEH item + mov [eax+02ch], ecx ; save next SEH + + stmxcsr [eax+028h] ; save MMX control word + fnstcw [eax+02ch] ; save x87 control word + + mov ecx, finish ; address of finish + mov [edx], ecx + + xor eax, eax + ret + +finish: + xor eax, eax + push eax ; exit code is zero + call _exit ; exit application + hlt +make_fcontext ENDP +END diff --git a/third_party/boost_context/src/asm/fcontext_i386_sysv_elf_gas.S b/third_party/boost_context/src/asm/fcontext_i386_sysv_elf_gas.S new file mode 100644 index 0000000000..7c94ea068d --- /dev/null +++ b/third_party/boost_context/src/asm/fcontext_i386_sysv_elf_gas.S @@ -0,0 +1,122 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************** + * * + * -------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | * + * -------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | * + * -------------------------------------------------------------- * + * | EDI | ESI | EBX | EBP | ESP | EIP | * + * -------------------------------------------------------------- * + * -------------------------------------------------------------- * + * | 6 | 7 | | * + * -------------------------------------------------------------- * + * | 0x18 | 0x1c | | * + * -------------------------------------------------------------- * + * | sbase | slimit | | * + * -------------------------------------------------------------- * + * -------------------------------------------------------------- * + * | 8 | 9 | | * + * -------------------------------------------------------------- * + * | 0x20 | 0x24 | | * + * -------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| | * + * -------------------------------------------------------------- * + * * + * *****************************************************************/ + +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,@function +jump_fcontext: + movl 0x4(%esp), %ecx /* load address of the first fcontext_t arg */ + movl %edi, (%ecx) /* save EDI */ + movl %esi, 0x4(%ecx) /* save ESI */ + movl %ebx, 0x8(%ecx) /* save EBX */ + movl %ebp, 0xc(%ecx) /* save EBP */ + + leal 0x4(%esp), %eax /* exclude the return address */ + movl %eax, 0x10(%ecx) /* save as stack pointer */ + movl (%esp), %eax /* load return address */ + movl %eax, 0x14(%ecx) /* save return address */ + + movl 0x8(%esp), %edx /* load address of the second fcontext_t arg */ + movl (%edx), %edi /* restore EDI */ + movl 0x4(%edx), %esi /* restore ESI */ + movl 0x8(%edx), %ebx /* restore EBX */ + movl 0xc(%edx), %ebp /* restore EBP */ + + movl 0x10(%esp), %eax /* check if fpu enve preserving was requested */ + test %eax, %eax + je 1f + + stmxcsr 0x20(%ecx) /* save MMX control and status word */ + fnstcw 0x24(%ecx) /* save x87 control word */ + ldmxcsr 0x20(%edx) /* restore MMX control and status word */ + fldcw 0x24(%edx) /* restore x87 control word */ +1: + movl 0xc(%esp), %eax /* use third arg as return value after jump */ + + movl 0x10(%edx), %esp /* restore ESP */ + movl %eax, 0x4(%esp) /* use third arg as first arg in context function */ + movl 0x14(%edx), %edx /* fetch the address to return to */ + + jmp *%edx /* indirect jump to context */ +.size jump_fcontext,.-jump_fcontext + +.text +.globl make_fcontext +.align 2 +.type make_fcontext,@function +make_fcontext: + movl 0x4(%esp), %eax /* load address of the fcontext_t */ + movl %eax, (%eax) /* save the address of current context */ + movl 0x8(%esp), %ecx /* load the address of the context function */ + movl %ecx, 0x14(%eax) /* save the address of the context function */ + movl 0x18(%eax), %edx /* load the stack base */ + + pushl %eax /* save pointer to fcontext_t */ + pushl %ebx /* save EBX */ + pushl %edx /* stack pointer as arg for align_stack */ + call 1f +1: popl %ebx /* address of label 1 */ + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx /* compute address of GOT and store it in EBX */ + call align_stack@PLT /* align stack */ + movl %eax, %edx /* begin of aligned stack */ + popl %eax /* remove arg for align_stack */ + popl %ebx /* restore EBX */ + popl %eax /* restore pointer to fcontext_t */ + + leal -0x14(%edx), %edx /* reserve space for the last frame on stack, (ESP + 4) % 16 == 0 */ + movl %edx, 0x10(%eax) /* save the aligned stack base */ + + stmxcsr 0x20(%eax) /* save MMX control and status word */ + fnstcw 0x24(%eax) /* save x87 control word */ + + call 2f +2: popl %ecx /* address of label 2 */ + addl $finish-2b, %ecx /* helper code executed after context function returns */ + movl %ecx, (%edx) + + xorl %eax, %eax + ret + +finish: + leal -0xc(%esp), %esp + + call 3f +3: popl %ebx /* address of label 3 */ + addl $_GLOBAL_OFFSET_TABLE_+[.-3b], %ebx /* compute address of GOT and store it in EBX */ + + xorl %eax, %eax + pushl %eax /* exit code is zero */ + call _exit@PLT /* exit application */ + hlt +.size make_fcontext,.-make_fcontext diff --git a/third_party/boost_context/src/asm/fcontext_i386_sysv_macho_gas.S b/third_party/boost_context/src/asm/fcontext_i386_sysv_macho_gas.S new file mode 100644 index 0000000000..a28c87576a --- /dev/null +++ b/third_party/boost_context/src/asm/fcontext_i386_sysv_macho_gas.S @@ -0,0 +1,118 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************** + * * + * -------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | * + * -------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | * + * -------------------------------------------------------------- * + * | EDI | ESI | EBX | EBP | ESP | EIP | * + * -------------------------------------------------------------- * + * -------------------------------------------------------------- * + * | 6 | 7 | | * + * -------------------------------------------------------------- * + * | 0x18 | 0x1c | | * + * -------------------------------------------------------------- * + * | sbase | slimit | | * + * -------------------------------------------------------------- * + * -------------------------------------------------------------- * + * | 8 | 9 | | * + * -------------------------------------------------------------- * + * | 0x20 | 0x24 | | * + * -------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| | * + * -------------------------------------------------------------- * + * * + * *****************************************************************/ + +.text +.globl _jump_fcontext +.align 2 +_jump_fcontext: + movl 0x4(%esp), %ecx /* load address of the first fcontext_t arg */ + movl %edi, (%ecx) /* save EDI */ + movl %esi, 0x4(%ecx) /* save ESI */ + movl %ebx, 0x8(%ecx) /* save EBX */ + movl %ebp, 0xc(%ecx) /* save EBP */ + + leal 0x4(%esp), %eax /* exclude the return address */ + movl %eax, 0x10(%ecx) /* save as stack pointer */ + movl (%esp), %eax /* load return address */ + movl %eax, 0x14(%ecx) /* save return address */ + + movl 0x8(%esp), %edx /* load address of the second fcontext_t arg */ + movl (%edx), %edi /* restore EDI */ + movl 0x4(%edx), %esi /* restore ESI */ + movl 0x8(%edx), %ebx /* restore EBX */ + movl 0xc(%edx), %ebp /* restore EBP */ + + movl 0x10(%esp), %eax /* check if fpu enve preserving was requested */ + test %eax, %eax + je 1f + + stmxcsr 0x20(%ecx) /* save MMX control and status word */ + fnstcw 0x24(%ecx) /* save x87 control word */ + ldmxcsr 0x20(%edx) /* restore MMX control and status word */ + fldcw 0x24(%edx) /* restore x87 control word */ +1: + movl 0xc(%esp), %eax /* use third arg as return value after jump */ + + movl 0x10(%edx), %esp /* restore ESP */ + movl %eax, 0x4(%esp) /* use third arg as first arg in context function */ + movl 0x14(%edx), %edx /* fetch the address to return to */ + + jmp *%edx /* indirect jump to context */ + +.text +.globl _make_fcontext +.align 2 +_make_fcontext: + movl 0x4(%esp), %eax /* load address of the fcontext_t */ + movl %eax, (%eax) /* save the address of current context */ + movl 0x8(%esp), %ecx /* load the address of the context function */ + movl %ecx, 0x14(%eax) /* save the address of the context function */ + movl 0x18(%eax), %edx /* load the stack base */ + + pushl %eax /* save pointer to fcontext_t */ + pushl %ebx /* save EBX */ + pushl %edx /* stack pointer as arg for align_stack */ + call 1f +1: popl %ebx /* address of label 1 */ + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx /* compute address of GOT and store it in EBX */ + call align_stack@PLT /* align stack */ + movl %eax, %edx /* begin of aligned stack */ + popl %eax /* remove arg for align_stack */ + popl %ebx /* restore EBX */ + popl %eax /* restore pointer to fcontext_t */ + + leal -0x14(%edx), %edx /* reserve space for the last frame on stack, (ESP + 4) % 16 == 0 */ + movl %edx, 0x10(%eax) /* save the aligned stack base */ + + stmxcsr 0x20(%eax) /* save MMX control and status word */ + fnstcw 0x24(%eax) /* save x87 control word */ + + call 2f +2: popl %ecx /* address of label 2 */ + addl $finish-2b, %ecx /* helper code executed after context function returns */ + movl %ecx, (%edx) + + xorl %eax, %eax + ret + +finish: + leal -0xc(%esp), %esp + + call 3f +3: popl %ebx /* address of label 3 */ + addl $_GLOBAL_OFFSET_TABLE_+[.-3b], %ebx /* compute address of GOT and store it in EBX */ + + xorl %eax, %eax + pushl %eax /* exit code is zero */ + call _exit@PLT /* exit application */ + hlt diff --git a/third_party/boost_context/src/asm/fcontext_mips32_o32_elf_gas.S b/third_party/boost_context/src/asm/fcontext_mips32_o32_elf_gas.S new file mode 100644 index 0000000000..be86f185ec --- /dev/null +++ b/third_party/boost_context/src/asm/fcontext_mips32_o32_elf_gas.S @@ -0,0 +1,144 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************* + * * + * ------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | * + * ------------------------------------------------------------- * + * | 0 | 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | * + * ------------------------------------------------------------- * + * | S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | GP | SP | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 10 | 11 | 12 | | * + * ------------------------------------------------------------- * + * | 80 | 88 | 96 | | * + * ------------------------------------------------------------- * + * | S8 | RA | PC | | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 13 | 14 | | * + * ------------------------------------------------------------- * + * | 104 | 112 | | * + * ------------------------------------------------------------- * + * |sbase|slimt| | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 15 | 16 | 17 | 18 | 19 | 20 | | * + * ------------------------------------------------------------- * + * | 120 | 128 | 136 | 144 | 152 | 160 | | * + * ------------------------------------------------------------- * + * | F20 | F22 | F24 | F26 | F28 | F30 | | * + * ------------------------------------------------------------- * + * * + * *****************************************************************/ + +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,@function +.ent jump_fcontext +jump_fcontext: + sw $s0, ($a0) # save S0 + sw $s1, 8($a0) # save S1 + sw $s2, 16($a0) # save S2 + sw $s3, 24($a0) # save S3 + sw $s4, 32($a0) # save S4 + sw $s5, 40($a0) # save S5 + sw $s6, 48($a0) # save S6 + sw $s7, 56($a0) # save S7 + sw $gp, 64($a0) # save GP + sw $sp, 72($a0) # save SP + sw $s8, 80($a0) # save S8 + sw $ra, 88($a0) # save RA + sw $ra, 96($a0) # save RA as PC + +#if defined(__mips_hard_float) + beqz $a3, 1f # test if fpu env should be preserved + s.d $f20, 120($a0) # save F20 + s.d $f22, 128($a0) # save F22 + s.d $f24, 136($a0) # save F24 + s.d $f26, 144($a0) # save F26 + s.d $f28, 152($a0) # save F28 + s.d $f30, 160($a0) # save F30 + + l.d $f20, 120($a1) # restore F20 + l.d $f22, 128($a1) # restore F22 + l.d $f24, 136($a1) # restore F24 + l.d $f26, 144($a1) # restore F26 + l.d $f28, 152($a1) # restore F28 + l.d $f30, 160($a1) # restore F30 +1: +#endif + + lw $s0, ($a1) # restore S0 + lw $s1, 8($a1) # restore S1 + lw $s2, 16($a1) # restore S2 + lw $s3, 24($a1) # restore S3 + lw $s4, 32($a1) # restore S4 + lw $s5, 40($a1) # restore S5 + lw $s6, 48($a1) # restore S6 + lw $s7, 56($a1) # restore S7 + lw $gp, 64($a1) # restore GP + lw $sp, 72($a1) # restore SP + lw $s8, 80($a1) # restore S8 + lw $ra, 88($a1) # restore RA + move $a0, $s2 # restore void pointer as argument + + move $v0, $a2 # use third arg as return value after jump + move $a0, $a2 # use third arg as first arg in context function + + lw $t9, 96($a1) # load PC + jr $t9 # jump to context +.end jump_fcontext +.size jump_fcontext, .-jump_fcontext + +.text +.globl make_fcontext +.align 2 +.type make_fcontext,@function +.ent make_fcontext +make_fcontext: +#ifdef __PIC__ +.set noreorder +.cpload $t9 +.set reorder +#endif + sw $a0, ($a0) # save the current context + sw $gp, 24($a0) # save global pointer + sw $a1, 96($a0) # save the address of the context function + lw $t0, 104($a0) # load the stack base + + sub $sp, $sp, 28 + sw $ra, 24($sp) + sw $a0, 20($sp) + move $a0, $t0 # stack pointer as arg for align_stack + lw $t9, %call16(align_stack)($gp) # align stack + jalr $t9 + nop + move $t0, $v0 # begin of aligned stack + lw $ra, 24($sp) + lw $a0, 20($sp) + addi $sp, $sp, 28 + + sub $t0, $t0, 16 # reserve 16 byte of argument space + sw $t0, 72($a0) # save the algned stack base + + la $t9, finish # helper code executed after context function returns + sw $t9, 88($a0) + + move $v0, $zero + jr $ra + +finish: + move $gp, $s3 # restore GP (global pointer) + move $a0, $zero # exit code is zero + lw $t9, %call16(_exit)($gp) # exit application + jalr $t9 +.end make_fcontext +.size make_fcontext, .-make_fcontext diff --git a/third_party/boost_context/src/asm/fcontext_ppc32_sysv_elf_gas.S b/third_party/boost_context/src/asm/fcontext_ppc32_sysv_elf_gas.S new file mode 100644 index 0000000000..69b6ed90b5 --- /dev/null +++ b/third_party/boost_context/src/asm/fcontext_ppc32_sysv_elf_gas.S @@ -0,0 +1,222 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************* + * * + * ------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | * + * ------------------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | * + * ------------------------------------------------------------- * + * | R13 | R14 | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | * + * ------------------------------------------------------------- * + * | 40 | 44 | 48 | 52 | 56 | 60 | 64 | 68 | 72 | 76 | * + * ------------------------------------------------------------- * + * | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | R31 | SP | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 20 | 21 | 22 | | * + * ------------------------------------------------------------- * + * | 80 | 84 | 88 | | * + * ------------------------------------------------------------- * + * | CR | LR | PC | | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 23 | 24 | | * + * ------------------------------------------------------------- * + * | 92 | 96 | | * + * ------------------------------------------------------------- * + * |sbase|slimt| | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | * + * ------------------------------------------------------------- * + * | 100 | 104 | 108 | 112 | 116 | 120 | 124 | 128 | 132 | 136 | * + * ------------------------------------------------------------- * + * | F14 | F15 | F16 | F17 | F18 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | * + * ------------------------------------------------------------- * + * | 140 | 144 | 148 | 152 | 156 | 160 | 164 | 168 | 172 | 176 | * + * ------------------------------------------------------------- * + * | F19 | F20 | F21 | F22 | F23 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | * + * ------------------------------------------------------------- * + * | 180 | 184 | 188 | 192 | 196 | 200 | 204 | 208 | 212 | 216 | * + * ------------------------------------------------------------- * + * | F24 | F25 | F26 | F27 | F28 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | | * + * ------------------------------------------------------------- * + * | 220 | 224 | 228 | 232 | 236 | 240 | 244 | 248 | | * + * ------------------------------------------------------------- * + * | F29 | F30 | F31 | fpscr | | * + * ------------------------------------------------------------- * + * * + * *****************************************************************/ + +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,@function +jump_fcontext: + stw %r13, 0(%r3) # save R13 + stw %r14, 4(%r3) # save R14 + stw %r15, 8(%r3) # save R15 + stw %r16, 12(%r3) # save R16 + stw %r17, 16(%r3) # save R17 + stw %r18, 20(%r3) # save R18 + stw %r19, 24(%r3) # save R19 + stw %r20, 28(%r3) # save R20 + stw %r21, 32(%r3) # save R21 + stw %r22, 36(%r3) # save R22 + stw %r23, 40(%r3) # save R23 + stw %r24, 44(%r3) # save R24 + stw %r25, 48(%r3) # save R25 + stw %r26, 52(%r3) # save R26 + stw %r27, 56(%r3) # save R27 + stw %r28, 60(%r3) # save R28 + stw %r29, 64(%r3) # save R29 + stw %r30, 68(%r3) # save R30 + stw %r31, 72(%r3) # save R31 + stw %r1, 76(%r3) # save SP + + mfcr %r0 # load CR + stw %r0, 80(%r3) # save CR + mflr %r0 # load LR + stw %r0, 84(%r3) # save LR + stw %r0, 88(%r3) # save LR as PC + + cmpwi cr7, %r6, 0 # test if fpu env should be preserved + beq cr7, 1f + + stfd %f14, 100(%r3) # save F14 + stfd %f15, 108(%r3) # save F15 + stfd %f16, 116(%r3) # save F16 + stfd %f17, 124(%r3) # save F17 + stfd %f18, 132(%r3) # save F18 + stfd %f19, 140(%r3) # save F19 + stfd %f20, 148(%r3) # save F20 + stfd %f21, 156(%r3) # save F21 + stfd %f22, 164(%r3) # save F22 + stfd %f23, 172(%r3) # save F23 + stfd %f24, 180(%r3) # save F24 + stfd %f25, 188(%r3) # save F25 + stfd %f26, 196(%r3) # save F26 + stfd %f27, 204(%r3) # save F27 + stfd %f28, 212(%r3) # save F28 + stfd %f29, 220(%r3) # save F29 + stfd %f30, 228(%r3) # save F30 + stfd %f31, 236(%r3) # save F31 + mffs %f0 # load FPSCR + stfd %f0, 244(%r3) # save FPSCR + + lfd %f14, 100(%r4) # restore F14 + lfd %f15, 108(%r4) # restore F15 + lfd %f16, 116(%r4) # restore F16 + lfd %f17, 124(%r4) # restore F17 + lfd %f18, 132(%r4) # restore F18 + lfd %f19, 140(%r4) # restore F19 + lfd %f20, 148(%r4) # restore F20 + lfd %f21, 156(%r4) # restore F21 + lfd %f22, 164(%r4) # restore F22 + lfd %f23, 172(%r4) # restore F23 + lfd %f24, 180(%r4) # restore F24 + lfd %f25, 188(%r4) # restore F25 + lfd %f26, 196(%r4) # restore F26 + lfd %f27, 204(%r4) # restore F27 + lfd %f28, 212(%r4) # restore F28 + lfd %f29, 220(%r4) # restore F29 + lfd %f30, 228(%r4) # restore F30 + lfd %f31, 236(%r4) # restore F31 + lfd %f0, 244(%r4) # load FPSCR + mtfsf 0xff, %f0 # restore FPSCR +1: + + lwz %r13, 0(%r4) # restore R13 + lwz %r14, 4(%r4) # restore R14 + lwz %r15, 8(%r4) # restore R15 + lwz %r16, 12(%r4) # restore R16 + lwz %r17, 16(%r4) # restore R17 + lwz %r18, 20(%r4) # restore R18 + lwz %r19, 24(%r4) # restore R19 + lwz %r20, 28(%r4) # restore R20 + lwz %r21, 32(%r4) # restore R21 + lwz %r22, 36(%r4) # restore R22 + lwz %r23, 40(%r4) # restore R23 + lwz %r24, 44(%r4) # restore R24 + lwz %r25, 48(%r4) # restore R25 + lwz %r26, 52(%r4) # restore R26 + lwz %r27, 56(%r4) # restore R27 + lwz %r28, 60(%r4) # restore R28 + lwz %r29, 64(%r4) # restore R29 + lwz %r30, 68(%r4) # restore R30 + lwz %r31, 72(%r4) # restore R31 + lwz %r1, 76(%r4) # restore SP + + lwz %r0, 80(%r4) # load CR + mtcr %r0 # restore CR + lwz %r0, 84(%r4) # load LR + mtlr %r0 # restore LR + + mr. %r3, %r5 # use third arg as return value after jump + # and as first arg in context function + + lwz %r0, 88(%r4) # load PC + mtctr %r0 # restore CTR + + bctr # jump to context +.size jump_fcontext, .-jump_fcontext + +.text +.globl make_fcontext +.align 2 +.type make_fcontext,@function +make_fcontext: + stw %r3, 0(%r3) # save the current context + stw %r4, 88(%r3) # save the address of the context function + lwz %r0, 92(%r3) # load the stack base + + li %r4, 28 + subf %r1, %r4, %r1 # reserve space on stack + stw %r3, 24(%r1) # store pointer to fcontext_t on stack + mflr %r4 # load LR + stw %r4, 20(%r1) # store LR on stack + mr. %r3, %r0 # context stack as arg to align_stack + bl align_stack@plt # call align_stack + mr. %r0, %r3 # load result into R0 + lwz %r4, 20(%r1) # pop LR from stack + mtlr %r4 # restore LR + lwz %r3, 24(%r1) # pop pointer to fcontext_t from stack + addi %r1, %r1, 28 # release space on stack + + li %r4, 32 + subf %r0, %r4, %r0 # 32 bytes on stack for parameter area(== 8 registers) + stw %r0, 76(%r3) # save the aligned stack base + + mflr %r0 # load LR + bl 1f # jump to label 1 +1: + mflr %r4 # load LR + addi %r4, %r4, finish - 1b # address of finish; called after context function returns + mtlr %r0 # restore LR + stw %r4, 84(%r3) + + li %r3, 0 + blr + +finish: + li %r3, 0 # exit code is zero + bl _exit@plt # exit application +.size make_fcontext, .-make_fcontext diff --git a/third_party/boost_context/src/asm/fcontext_ppc64_sysv_elf_gas.S b/third_party/boost_context/src/asm/fcontext_ppc64_sysv_elf_gas.S new file mode 100644 index 0000000000..0fcb387355 --- /dev/null +++ b/third_party/boost_context/src/asm/fcontext_ppc64_sysv_elf_gas.S @@ -0,0 +1,250 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/******************************************************************* + * * + * ------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | * + * ------------------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | * + * ------------------------------------------------------------- * + * | R13 | R14 | R15 | R16 | R17 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | * + * ------------------------------------------------------------- * + * | 40 | 44 | 48 | 52 | 56 | 60 | 64 | 68 | 72 | 76 | * + * ------------------------------------------------------------- * + * | R18 | R19 | R20 | R21 | R22 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | * + * ------------------------------------------------------------- * + * | 80 | 84 | 88 | 92 | 96 | 100 | 104 | 108 | 112 | 116 | * + * ------------------------------------------------------------- * + * | R23 | R24 | R25 | R26 | R27 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------------------- * + * | 120 | 124 | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------------------- * + * | R28 | R29 | R30 | R31 | SP | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | | * + * ------------------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | | * + * ------------------------------------------------------------- * + * | CR | LR | PC | | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 46 | 47 | 48 | 49 | | * + * ------------------------------------------------------------- * + * | 184 | 188 | 192 | 196 | | * + * ------------------------------------------------------------- * + * | sbase | slimt | | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | * + * ------------------------------------------------------------- * + * | 200 | 204 | 208 | 212 | 216 | 220 | 224 | 228 | 232 | 236 | * + * ------------------------------------------------------------- * + * | F14 | F15 | F16 | F17 | F18 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | * + * ------------------------------------------------------------- * + * | 240 | 244 | 248 | 252 | 256 | 260 | 264 | 268 | 272 | 276 | * + * ------------------------------------------------------------- * + * | F19 | F20 | F21 | F22 | F23 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | * + * ------------------------------------------------------------- * + * | 280 | 284 | 288 | 292 | 296 | 300 | 304 | 308 | 312 | 316 | * + * ------------------------------------------------------------- * + * | F24 | F25 | F26 | F27 | F28 | * + * ------------------------------------------------------------- * + * ------------------------------------------------------------- * + * | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | | * + * ------------------------------------------------------------- * + * | 320 | 324 | 328 | 332 | 336 | 340 | 344 | 348 | | * + * ------------------------------------------------------------- * + * | F29 | F30 | F31 | fpscr | | * + * ------------------------------------------------------------- * + * * + * *****************************************************************/ + +.section ".text" +.align 2 +.globl jump_fcontext +.section ".opd","aw" +.align 3 +jump_fcontext: +.quad .jump_fcontext,.TOC.@tocbase,0 +.previous +.size jump_fcontext,24 +.type .jump_fcontext,@function +.globl .jump_fcontext +.jump_fcontext: + std %r13, 0(%r3) # save R13 + std %r14, 8(%r3) # save R14 + std %r15, 16(%r3) # save R15 + std %r16, 24(%r3) # save R16 + std %r17, 32(%r3) # save R17 + std %r18, 40(%r3) # save R18 + std %r19, 48(%r3) # save R19 + std %r20, 56(%r3) # save R20 + std %r21, 64(%r3) # save R21 + std %r22, 72(%r3) # save R22 + std %r23, 80(%r3) # save R23 + std %r24, 88(%r3) # save R24 + std %r25, 96(%r3) # save R25 + std %r26, 104(%r3) # save R26 + std %r27, 112(%r3) # save R27 + std %r28, 120(%r3) # save R28 + std %r29, 128(%r3) # save R29 + std %r30, 136(%r3) # save R30 + std %r31, 144(%r3) # save R31 + std %r1, 152(%r3) # save SP + + mfcr %r0 # load CR + std %r0, 160(%r3) # save CR + mflr %r0 # load LR + std %r0, 168(%r3) # save LR + std %r0, 176(%r3) # save LR as PC + + cmpwi cr7, %r6, 0 # test if fpu env should be preserved + beq cr7, 1f + + stfd %f14, 200(%r3) # save F14 + stfd %f15, 208(%r3) # save F15 + stfd %f16, 216(%r3) # save F16 + stfd %f17, 224(%r3) # save F17 + stfd %f18, 232(%r3) # save F18 + stfd %f19, 240(%r3) # save F19 + stfd %f20, 248(%r3) # save F20 + stfd %f21, 256(%r3) # save F21 + stfd %f22, 264(%r3) # save F22 + stfd %f23, 272(%r3) # save F23 + stfd %f24, 280(%r3) # save F24 + stfd %f25, 288(%r3) # save F25 + stfd %f26, 296(%r3) # save F26 + stfd %f27, 304(%r3) # save F27 + stfd %f28, 312(%r3) # save F28 + stfd %f29, 320(%r3) # save F29 + stfd %f30, 328(%r3) # save F30 + stfd %f31, 336(%r3) # save F31 + mffs %f0 # load FPSCR + stfd %f0, 344(%r3) # save FPSCR + + lfd %f14, 200(%r4) # restore F14 + lfd %f15, 208(%r4) # restore F15 + lfd %f16, 216(%r4) # restore F16 + lfd %f17, 224(%r4) # restore F17 + lfd %f18, 232(%r4) # restore F18 + lfd %f19, 240(%r4) # restore F19 + lfd %f20, 248(%r4) # restore F20 + lfd %f21, 256(%r4) # restore F21 + lfd %f22, 264(%r4) # restore F22 + lfd %f23, 272(%r4) # restore F23 + lfd %f24, 280(%r4) # restore F24 + lfd %f25, 288(%r4) # restore F25 + lfd %f26, 296(%r4) # restore F26 + lfd %f27, 304(%r4) # restore F27 + lfd %f28, 312(%r4) # restore F28 + lfd %f29, 320(%r4) # restore F29 + lfd %f30, 328(%r4) # restore F30 + lfd %f31, 336(%r4) # restore F31 + lfd %f0, 344(%r4) # load FPSCR + mtfsf 0xff, %f0 # restore FPSCR +1: + + ld %r13, 0(%r4) # restore R13 + ld %r14, 8(%r4) # restore R14 + ld %r15, 16(%r4) # restore R15 + ld %r16, 24(%r4) # restore R16 + ld %r17, 32(%r4) # restore R17 + ld %r18, 40(%r4) # restore R18 + ld %r19, 48(%r4) # restore R19 + ld %r20, 56(%r4) # restore R20 + ld %r21, 64(%r4) # restore R21 + ld %r22, 72(%r4) # restore R22 + ld %r23, 80(%r4) # restore R23 + ld %r24, 88(%r4) # restore R24 + ld %r25, 96(%r4) # restore R25 + ld %r26, 104(%r4) # restore R26 + ld %r27, 112(%r4) # restore R27 + ld %r28, 120(%r4) # restore R28 + ld %r29, 128(%r4) # restore R29 + ld %r30, 136(%r4) # restore r30 + ld %r31, 144(%r4) # restore r31 + ld %r1, 152(%r4) # restore SP + + ld %r0, 160(%r4) # load CR + mtcr %r0 # restore CR + ld %r0, 168(%r4) # load LR + mtlr %r0 # restore LR + + mr. %r3, %r5 # use third arg as return value after jump + # and as first arg in context function + + ld %r0, 176(%r4) # load PC + mtctr %r0 # restore CTR + + bctr # jump to context +.size .jump_fcontext, .-.jump_fcontext + +.section ".text" +.align 2 +.globl make_fcontext +.section ".opd","aw" +.align 3 +make_fcontext: +.quad .make_fcontext,.TOC.@tocbase,0 +.previous +.size make_fcontext,24 +.type .make_fcontext,@function +.globl .make_fcontext +.make_fcontext: + std %r3, 0(%r3) # save the current context + std %r4, 176(%r3) # save the address of the function supposed to be run + ld %r0, 184(%r3) # load the stack base + + li %r4, 56 + subf %r1, %r4, %r1 # reserve space on stack + stw %r3, 48(%r1) # store pointer to fcontext_t on stack + mflr %r4 # load LR + stw %r4, 40(%r1) # store LR on stack + mr. %r3, %r0 # context stack as arg to align_stack + bl align_stack@plt # call align_stack + mr. %r0, %r3 # load result into R0 + lwz %r4, 40(%r1) # pop LR from stack + mtlr %r4 # restore LR + lwz %r3, 48(%r1) # pop pointer to fcontext_t from stack + addi %r1, %r1, 56 # release space on stack + + li %r4, 64 + subf %r0, %r4, %r0 # 64 bytes on stack for parameter area (== 8 registers) + std %r0, 152(%r3) # save the stack base + + mflr %r0 # load LR + bl 1f # jump to label 1 +1: + mflr %r4 # load LR + addi %r4, %r4, finish - 1b # calulate absolute address of finish + mtlr %r0 # restore LR + std %r4, 168(%r3) # save address of finish + + li %r3, 0 # set return value to zero + blr + +finish: + li %r3, 0 # set return value to zero + bl _exit@plt # exit application +.size .make_fcontext, .-.make_fcontext diff --git a/third_party/boost_context/src/asm/fcontext_x86_64_ms_pe_masm.asm b/third_party/boost_context/src/asm/fcontext_x86_64_ms_pe_masm.asm new file mode 100644 index 0000000000..f3a882ce3c --- /dev/null +++ b/third_party/boost_context/src/asm/fcontext_x86_64_ms_pe_masm.asm @@ -0,0 +1,207 @@ + +; Copyright Oliver Kowalke 2009. +; Distributed under the Boost Software License, Version 1.0. +; (See accompanying file LICENSE_1_0.txt or copy at +; http://www.boost.org/LICENSE_1_0.txt) + +; ---------------------------------------------------------------------------------- +; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +; ---------------------------------------------------------------------------------- +; | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | +; ---------------------------------------------------------------------------------- +; | R12 | R13 | R14 | R15 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | +; ---------------------------------------------------------------------------------- +; | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | +; ---------------------------------------------------------------------------------- +; | RDI | RSI | RBX | RBP | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 16 | 17 | 18 | 19 | | +; ---------------------------------------------------------------------------------- +; | 0x40 | 0x44 | 0x48 | 0x4c | | +; ---------------------------------------------------------------------------------- +; | RSP | RIP | | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 20 | 21 | 22 | 23 | | +; ---------------------------------------------------------------------------------- +; | 0x50 | 0x54 | 0x58 | 0x5c | | +; ---------------------------------------------------------------------------------- +; | sbase | slimit | | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 24 | 25 | | +; ---------------------------------------------------------------------------------- +; | 0x60 | 0x64 | | +; ---------------------------------------------------------------------------------- +; | fbr_strg | | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 26 | 27 | 28 | 29 | | +; ---------------------------------------------------------------------------------- +; | 0x68 | 0x6c | 0x70 | 0x74 | | +; ---------------------------------------------------------------------------------- +; | fc_mxcsr|fc_x87_cw| fc_xmm | | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | +; ---------------------------------------------------------------------------------- +; | 0x78 | 0x7c | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | +; ---------------------------------------------------------------------------------- +; | XMM6 | XMM7 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | +; ---------------------------------------------------------------------------------- +; | 0x98 | 0x9c | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | +; ---------------------------------------------------------------------------------- +; | XMM8 | XMM9 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | +; ---------------------------------------------------------------------------------- +; | 0x118 | 0x11c | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | +; ---------------------------------------------------------------------------------- +; | XMM10 | XMM11 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | +; ---------------------------------------------------------------------------------- +; | 0x138 | 0x13c | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | +; ---------------------------------------------------------------------------------- +; | XMM12 | XMM13 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | +; ---------------------------------------------------------------------------------- +; | 0x158 | 0x15c | 0x160 | 0x164 | 0x168 | 0x16c | 0x170 | 0x174 | +; ---------------------------------------------------------------------------------- +; | XMM14 | XMM15 | +; ---------------------------------------------------------------------------------- + +EXTERN _exit:PROC ; standard C library function +EXTERN align_stack:PROC ; stack alignment +EXTERN seh_fcontext:PROC ; exception handler +.code + +jump_fcontext PROC EXPORT FRAME:seh_fcontext + .endprolog + + mov [rcx], r12 ; save R12 + mov [rcx+08h], r13 ; save R13 + mov [rcx+010h], r14 ; save R14 + mov [rcx+018h], r15 ; save R15 + mov [rcx+020h], rdi ; save RDI + mov [rcx+028h], rsi ; save RSI + mov [rcx+030h], rbx ; save RBX + mov [rcx+038h], rbp ; save RBP + + mov r10, gs:[030h] ; load NT_TIB + mov rax, [r10+08h] ; load current stack base + mov [rcx+050h], rax ; save current stack base + mov rax, [r10+010h] ; load current stack limit + mov [rcx+058h], rax ; save current stack limit + mov rax, [r10+018h] ; load fiber local storage + mov [rcx+060h], rax ; save fiber local storage + + test r9, r9 + je nxt + + stmxcsr [rcx+068h] ; save MMX control and status word + fnstcw [rcx+06ch] ; save x87 control word + mov r10, [rcx+070h] ; address of aligned XMM storage + movaps [r10], xmm6 + movaps [r10+010h], xmm7 + movaps [r10+020h], xmm8 + movaps [r10+030h], xmm9 + movaps [r10+040h], xmm10 + movaps [r10+050h], xmm11 + movaps [r10+060h], xmm12 + movaps [r10+070h], xmm13 + movaps [r10+080h], xmm14 + movaps [r10+090h], xmm15 + + ldmxcsr [rdx+068h] ; restore MMX control and status word + fldcw [rdx+06ch] ; restore x87 control word + mov r10, [rdx+070h] ; address of aligned XMM storage + movaps xmm6, [r10] + movaps xmm7, [r10+010h] + movaps xmm8, [r10+020h] + movaps xmm9, [r10+030h] + movaps xmm10, [r10+040h] + movaps xmm11, [r10+050h] + movaps xmm12, [r10+060h] + movaps xmm13, [r10+070h] + movaps xmm14, [r10+080h] + movaps xmm15, [r10+090h] +nxt: + + lea rax, [rsp+08h] ; exclude the return address + mov [rcx+040h], rax ; save as stack pointer + mov rax, [rsp] ; load return address + mov [rcx+048h], rax ; save return address + + mov r12, [rdx] ; restore R12 + mov r13, [rdx+08h] ; restore R13 + mov r14, [rdx+010h] ; restore R14 + mov r15, [rdx+018h] ; restore R15 + mov rdi, [rdx+020h] ; restore RDI + mov rsi, [rdx+028h] ; restore RSI + mov rbx, [rdx+030h] ; restore RBX + mov rbp, [rdx+038h] ; restore RBP + + mov r10, gs:[030h] ; load NT_TIB + mov rax, [rdx+050h] ; load stack base + mov [r10+08h], rax ; restore stack base + mov rax, [rdx+058h] ; load stack limit + mov [r10+010h], rax ; restore stack limit + mov rax, [rdx+060h] ; load fiber local storage + mov [r10+018h], rax ; restore fiber local storage + + mov rsp, [rdx+040h] ; restore RSP + mov r10, [rdx+048h] ; fetch the address to returned to + + mov rax, r8 ; use third arg as return value after jump + mov rcx, r8 ; use third arg as first arg in context function + + jmp r10 ; indirect jump to caller +jump_fcontext ENDP + +make_fcontext PROC EXPORT FRAME ; generate function table entry in .pdata and unwind information in E + .endprolog ; .xdata for a function's structured exception handling unwind behavior + + mov [rcx], rcx ; store the address of current context + mov [rcx+048h], rdx ; save the address of the function supposed to run + mov rdx, [rcx+050h] ; load the address where the context stack beginns + + push rcx ; save pointer to fcontext_t + sub rsp, 028h ; reserve shadow space for align_stack + mov rcx, rdx ; stack pointer as arg for align_stack + mov [rsp+8], rcx + call align_stack ; align stack + mov rdx, rax ; begin of aligned stack + add rsp, 028h + pop rcx ; restore pointer to fcontext_t + + lea rdx, [rdx-028h] ; reserve 32byte shadow space + return address on stack, (RSP + 8) % 16 == 0 + mov [rcx+040h], rdx ; save the address where the context stack beginns + + stmxcsr [rcx+068h] ; save MMX control and status word + fnstcw [rcx+06ch] ; save x87 control word + + lea rax, finish ; helper code executed after fn() returns + mov [rdx], rax ; store address off the helper function as return address + + xor rax, rax ; set RAX to zero + ret + +finish: + xor rcx, rcx + mov [rsp+08h], rcx + call _exit ; exit application + hlt +make_fcontext ENDP +END diff --git a/third_party/boost_context/src/asm/fcontext_x86_64_sysv_elf_gas.S b/third_party/boost_context/src/asm/fcontext_x86_64_sysv_elf_gas.S new file mode 100644 index 0000000000..ad2d42b46c --- /dev/null +++ b/third_party/boost_context/src/asm/fcontext_x86_64_sysv_elf_gas.S @@ -0,0 +1,116 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | RBX | R12 | R13 | R14 | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * + * ---------------------------------------------------------------------------------- * + * | R15 | RBP | RSP | RIP | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 16 | 17 | 18 | 19 | | * + * ---------------------------------------------------------------------------------- * + * | 0x40 | 0x44 | 0x48 | 0x4c | | * + * ---------------------------------------------------------------------------------- * + * | sbase | slimit | | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 20 | 21 | | * + * ---------------------------------------------------------------------------------- * + * | 0x50 | 0x54 | | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| | * + * ---------------------------------------------------------------------------------- * + * * + * **************************************************************************************/ + +.text +.globl jump_fcontext +.type jump_fcontext,@function +.align 16 +jump_fcontext: + movq %rbx, (%rdi) /* save RBX */ + movq %r12, 0x8(%rdi) /* save R12 */ + movq %r13, 0x10(%rdi) /* save R13 */ + movq %r14, 0x18(%rdi) /* save R14 */ + movq %r15, 0x20(%rdi) /* save R15 */ + movq %rbp, 0x28(%rdi) /* save RBP */ + + cmp $0, %rcx + je 1f + + stmxcsr 0x50(%rdi) /* save MMX control and status word */ + fnstcw 0x54(%rdi) /* save x87 control word */ + + ldmxcsr 0x50(%rsi) /* restore MMX control and status word */ + fldcw 0x54(%rsi) /* restore x87 control word */ +1: + + leaq 0x8(%rsp), %rax /* exclude the return address and save as stack pointer */ + movq %rax, 0x30(%rdi) /* save as stack pointer */ + movq (%rsp), %rax /* save return address */ + movq %rax, 0x38(%rdi) /* save return address as RIP */ + + movq (%rsi), %rbx /* restore RBX */ + movq 0x8(%rsi), %r12 /* restore R12 */ + movq 0x10(%rsi), %r13 /* restore R13 */ + movq 0x18(%rsi), %r14 /* restore R14 */ + movq 0x20(%rsi), %r15 /* restore R15 */ + movq 0x28(%rsi), %rbp /* restore RBP */ + + movq 0x30(%rsi), %rsp /* restore RSP */ + movq 0x38(%rsi), %rcx /* fetch the address to return to */ + + movq %rdx, %rax /* use third arg as return value after jump */ + movq %rdx, %rdi /* use third arg as first arg in context function */ + + jmp *%rcx /* indirect jump to context */ +.size jump_fcontext,.-jump_fcontext + +.text +.globl make_fcontext +.type make_fcontext,@function +.align 16 +make_fcontext: + movq %rdi, (%rdi) /* save the address of passed context */ + movq %rsi, 0x38(%rdi) /* save the address of the context function */ + movq 0x40(%rdi), %rdx /* load the stack base */ + + pushq %rdi /* save pointer to fcontext_t */ + movq %rdx, %rdi /* stack pointer as arg for align_stack */ + call align_stack@PLT /* align stack */ + movq %rax, %rdx /* begin of aligned stack */ + popq %rdi /* restore pointer to fcontext_t */ + + leaq -0x8(%rdx), %rdx /* reserve space for the last frame on stack, (RSP + 8) & 15 == 0 */ + movq %rdx, 0x30(%rdi) /* save the algined stack base */ + + stmxcsr 0x50(%rdi) /* save MMX control and status word */ + fnstcw 0x54(%rdi) /* save x87 control word */ + + leaq finish(%rip), %rcx /* address of finish; called after context function returns */ + movq %rcx, (%rdx) + + xorq %rax, %rax + ret + +finish: + xorq %rdi, %rdi /* exit code is zero */ + call _exit@PLT /* exit application */ + hlt +.size make_fcontext,.-make_fcontext + diff --git a/third_party/boost_context/src/asm/fcontext_x86_64_sysv_macho_gas.s b/third_party/boost_context/src/asm/fcontext_x86_64_sysv_macho_gas.s new file mode 100644 index 0000000000..bf5a8e0889 --- /dev/null +++ b/third_party/boost_context/src/asm/fcontext_x86_64_sysv_macho_gas.s @@ -0,0 +1,113 @@ +/* + Copyright Oliver Kowalke 2009. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | RBX | R12 | R13 | R14 | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * + * ---------------------------------------------------------------------------------- * + * | R15 | RBP | RSP | RIP | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 16 | 17 | 18 | 19 | | * + * ---------------------------------------------------------------------------------- * + * | 0x40 | 0x44 | 0x48 | 0x4c | | * + * ---------------------------------------------------------------------------------- * + * | sbase | slimit | | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 20 | 21 | | * + * ---------------------------------------------------------------------------------- * + * | 0x50 | 0x54 | | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| | * + * ---------------------------------------------------------------------------------- * + * * + * **************************************************************************************/ + +.text +.globl _jump_fcontext +.align 8 +_jump_fcontext: + movq %rbx, (%rdi) /* save RBX */ + movq %r12, 0x8(%rdi) /* save R12 */ + movq %r13, 0x10(%rdi) /* save R13 */ + movq %r14, 0x18(%rdi) /* save R14 */ + movq %r15, 0x20(%rdi) /* save R15 */ + movq %rbp, 0x28(%rdi) /* save RBP */ + + cmp $0, %rcx + je 1f + + stmxcsr 0x50(%rdi) /* save MMX control and status word */ + fnstcw 0x54(%rdi) /* save x87 control word */ + + ldmxcsr 0x50(%rsi) /* restore MMX control and status word */ + fldcw 0x54(%rsi) /* restore x87 control word */ +1: + + leaq 0x8(%rsp), %rax /* exclude the return address and save as stack pointer */ + movq %rax, 0x30(%rdi) /* save as stack pointer */ + movq (%rsp), %rax /* save return address */ + movq %rax, 0x38(%rdi) /* save return address as RIP */ + + movq (%rsi), %rbx /* restore RBX */ + movq 0x8(%rsi), %r12 /* restore R12 */ + movq 0x10(%rsi), %r13 /* restore R13 */ + movq 0x18(%rsi), %r14 /* restore R14 */ + movq 0x20(%rsi), %r15 /* restore R15 */ + movq 0x28(%rsi), %rbp /* restore RBP */ + + movq 0x30(%rsi), %rsp /* restore RSP */ + movq 0x38(%rsi), %rcx /* fetch the address to return to */ + + movq %rdx, %rax /* use third arg as return value after jump */ + movq %rdx, %rdi /* use third arg as first arg in context function */ + + jmp *%rcx /* indirect jump to context */ + +.text +.globl _make_fcontext +.align 8 +_make_fcontext: + movq %rdi, (%rdi) /* save the address of current context */ + movq %rsi, 0x38(%rdi) /* save the address of the function supposed to run */ + movq 0x40(%rdi), %rdx /* load the stack base */ + + pushq %rdi /* save pointer to fcontext_t */ + movq %rdx, %rdi /* stack pointer as arg for align_stack */ + call _align_stack /* align stack */ + //call align_stack@PLT /* align stack */ + movq %rax, %rdx /* begin of aligned stack */ + popq %rdi /* restore pointer to fcontext_t */ + + leaq -0x8(%rdx), %rdx /* reserve space for the last frame on stack, (RSP + 8) % 16 == 0 */ + movq %rdx, 0x30(%rdi) /* save the address */ + + stmxcsr 0x50(%rdi) /* save MMX control and status word */ + fnstcw 0x54(%rdi) /* save x87 control word */ + + leaq finish(%rip), %rcx /* helper code executed after context function returns */ + movq %rcx, (%rdx) + + xorq %rax, %rax /* set RAX to zero */ + ret + +finish: + xorq %rdi, %rdi /* exit code is zero */ + //call _exit@PLT /* exit application */ + call _exit /* exit application */ + hlt diff --git a/third_party/boost_context/src/fcontext.cpp b/third_party/boost_context/src/fcontext.cpp new file mode 100644 index 0000000000..e1658ca495 --- /dev/null +++ b/third_party/boost_context/src/fcontext.cpp @@ -0,0 +1,36 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { +namespace detail { + +extern "C" BOOST_CONTEXT_DECL +void * BOOST_CONTEXT_CALLDECL align_stack( void * vp) +{ + void * base = vp; + if ( 0 != ( ( ( uintptr_t) base) & 15) ) + base = ( char * ) ( ( ( ( uintptr_t) base) - 15) & ~0x0F); + return base; +} + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/third_party/boost_context/src/seh.cpp b/third_party/boost_context/src/seh.cpp new file mode 100644 index 0000000000..5c9c9d47a8 --- /dev/null +++ b/third_party/boost_context/src/seh.cpp @@ -0,0 +1,83 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +extern "C" { + +#include +#include + +#include +#include +#include + +#if defined(_MSC_VER) +# define SNPRINTF _snprintf +#else +# define SNPRINTF snprintf +#endif + +static char * exception_description( + _EXCEPTION_RECORD const* record, char * description, size_t len) +{ + const DWORD code = record->ExceptionCode; + const ULONG_PTR * info = record->ExceptionInformation; + + switch ( code) + { + case EXCEPTION_ACCESS_VIOLATION: + { + const char * accessType = ( info[0]) ? "writing" : "reading"; + const ULONG_PTR address = info[1]; + SNPRINTF( description, len, "Access violation %s 0x%08lX", accessType, address); + return description; + } + case EXCEPTION_DATATYPE_MISALIGNMENT: return "Datatype misalignment"; + case EXCEPTION_BREAKPOINT: return "Breakpoint"; + case EXCEPTION_SINGLE_STEP: return "Single step"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "Array bounds exceeded"; + case EXCEPTION_FLT_DENORMAL_OPERAND: return "FPU denormal operand"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "FPU divide by zero"; + case EXCEPTION_FLT_INEXACT_RESULT: return "FPU inexact result"; + case EXCEPTION_FLT_INVALID_OPERATION: return "FPU invalid operation"; + case EXCEPTION_FLT_OVERFLOW: return "FPU overflow"; + case EXCEPTION_FLT_STACK_CHECK: return "FPU stack check"; + case EXCEPTION_FLT_UNDERFLOW: return "FPU underflow"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: return "Integer divide by zero"; + case EXCEPTION_INT_OVERFLOW: return "Integer overflow"; + case EXCEPTION_PRIV_INSTRUCTION: return "Privileged instruction"; + case EXCEPTION_IN_PAGE_ERROR: return "In page error"; + case EXCEPTION_ILLEGAL_INSTRUCTION: return "Illegal instruction"; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "Noncontinuable exception"; + case EXCEPTION_STACK_OVERFLOW: return "Stack overflow"; + case EXCEPTION_INVALID_DISPOSITION: return "Invalid disposition"; + case EXCEPTION_GUARD_PAGE: return "Guard page"; + case EXCEPTION_INVALID_HANDLE: return "Invalid handle"; + } + + SNPRINTF( description, len, "Unknown (0x%08lX)", code); + return description; +} + +EXCEPTION_DISPOSITION seh_fcontext( + struct _EXCEPTION_RECORD * record, + void *, + struct _CONTEXT *, + void *) +{ + char description[255]; + + fprintf( stderr, "exception: %s (%08lX)\n", + exception_description( record, description, sizeof( description) ), + record->ExceptionCode); + + ExitProcess( -1); + + return ExceptionContinueSearch; // never reached +} + +} diff --git a/third_party/boost_context/src/stack_allocator_posix.cpp b/third_party/boost_context/src/stack_allocator_posix.cpp new file mode 100644 index 0000000000..314c7890bc --- /dev/null +++ b/third_party/boost_context/src/stack_allocator_posix.cpp @@ -0,0 +1,84 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +#include + +extern "C" { +#include +#include +#include +#include +#include +} + +#include + +#include +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace ctx { + +void * +stack_allocator::allocate( std::size_t size) const +{ + if ( minimum_stacksize() > size) + throw std::invalid_argument( + boost::str( boost::format("invalid stack size: must be at least %d bytes") + % minimum_stacksize() ) ); + + if ( ! is_stack_unbound() && ( maximum_stacksize() < size) ) + throw std::invalid_argument( + boost::str( boost::format("invalid stack size: must not be larger than %d bytes") + % maximum_stacksize() ) ); + + const std::size_t pages( page_count( size) + 1); // add +1 for guard page + std::size_t size_ = pages * pagesize(); + + const int fd( ::open("/dev/zero", O_RDONLY) ); + BOOST_ASSERT( -1 != fd); + void * limit = +# if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +# else + ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); +# endif + ::close( fd); + if ( ! limit) throw std::bad_alloc(); + + const int result( ::mprotect( limit, pagesize(), PROT_NONE) ); + BOOST_ASSERT( 0 == result); + + return static_cast< char * >( limit) + size_; +} + +void +stack_allocator::deallocate( void * vp, std::size_t size) const +{ + if ( vp) + { + const std::size_t pages( page_count( size) + 1); // add +1 for guard page + std::size_t size_ = pages * pagesize(); + BOOST_ASSERT( 0 < size && 0 < size_); + void * limit = static_cast< char * >( vp) - size_; + ::munmap( limit, size_); + } +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/third_party/boost_context/src/stack_allocator_windows.cpp b/third_party/boost_context/src/stack_allocator_windows.cpp new file mode 100644 index 0000000000..6759e9b3b2 --- /dev/null +++ b/third_party/boost_context/src/stack_allocator_windows.cpp @@ -0,0 +1,85 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +#include + +extern "C" { +#include +} + +#include + +#include +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +# if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable:4244 4267) +# endif + +namespace boost { +namespace ctx { + +void * +stack_allocator::allocate( std::size_t size) const +{ + if ( minimum_stacksize() > size) + throw std::invalid_argument( + boost::str( boost::format("invalid stack size: must be at least %d bytes") + % minimum_stacksize() ) ); + + if ( ! is_stack_unbound() && ( maximum_stacksize() < size) ) + throw std::invalid_argument( + boost::str( boost::format("invalid stack size: must not be larger than %d bytes") + % maximum_stacksize() ) ); + + const std::size_t pages( page_count( size) + 1); // add +1 for guard page + std::size_t size_ = pages * pagesize(); + +#ifndef BOOST_CONTEXT_FIBER + void * limit = ::VirtualAlloc( 0, size_, MEM_COMMIT, PAGE_READWRITE); + if ( ! limit) throw std::bad_alloc(); + + DWORD old_options; + const BOOL result = ::VirtualProtect( + limit, pagesize(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); + BOOST_ASSERT( FALSE != result); + + return static_cast< char * >( limit) + size_; +#endif +} + +void +stack_allocator::deallocate( void * vp, std::size_t size) const +{ + if ( vp) + { + const std::size_t pages( page_count( size) + 1); // add +1 for guard page + std::size_t size_ = pages * pagesize(); + BOOST_ASSERT( 0 < size && 0 < size_); + void * limit = static_cast< char * >( vp) - size_; + ::VirtualFree( limit, 0, MEM_RELEASE); + } +} + +}} + +# if defined(BOOST_MSVC) +# pragma warning(pop) +# endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/third_party/boost_context/src/stack_utils_posix.cpp b/third_party/boost_context/src/stack_utils_posix.cpp new file mode 100644 index 0000000000..11350dbfe1 --- /dev/null +++ b/third_party/boost_context/src/stack_utils_posix.cpp @@ -0,0 +1,80 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +#include + +extern "C" { +#include +#include +#include +} + +#include +#include + +#include + +namespace { + +static rlimit stacksize_limit_() +{ + rlimit limit; + const int result = ::getrlimit( RLIMIT_STACK, & limit); + BOOST_ASSERT( 0 == result); + return limit; +} + +static rlimit stacksize_limit() +{ + static rlimit limit = stacksize_limit_(); + return limit; +} + +} + +namespace boost { +namespace ctx { + +BOOST_CONTEXT_DECL +std::size_t default_stacksize() +{ + static std::size_t size = 256 * 1024; + return size; +} + +BOOST_CONTEXT_DECL +std::size_t minimum_stacksize() +{ return SIGSTKSZ; } + +BOOST_CONTEXT_DECL +std::size_t maximum_stacksize() +{ + BOOST_ASSERT( ! is_stack_unbound() ); + return static_cast< std::size_t >( stacksize_limit().rlim_max); +} + +BOOST_CONTEXT_DECL +bool is_stack_unbound() +{ return RLIM_INFINITY == stacksize_limit().rlim_max; } + +BOOST_CONTEXT_DECL +std::size_t pagesize() +{ + static std::size_t pagesize( ::getpagesize() ); + return pagesize; +} + +BOOST_CONTEXT_DECL +std::size_t page_count( std::size_t stacksize) +{ + return static_cast< std::size_t >( + std::ceil( + static_cast< float >( stacksize) / pagesize() ) ); +} + +}} diff --git a/third_party/boost_context/src/stack_utils_windows.cpp b/third_party/boost_context/src/stack_utils_windows.cpp new file mode 100644 index 0000000000..373033dac2 --- /dev/null +++ b/third_party/boost_context/src/stack_utils_windows.cpp @@ -0,0 +1,84 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CONTEXT_SOURCE + +#include + +extern "C" { +#include +} + +#include +#include + +#include + +namespace { + +static SYSTEM_INFO system_info_() +{ + SYSTEM_INFO si; + ::GetSystemInfo( & si); + return si; +} + +static SYSTEM_INFO system_info() +{ + static SYSTEM_INFO si = system_info_(); + return si; +} + +} + +namespace boost { +namespace ctx { + +BOOST_CONTEXT_DECL +std::size_t default_stacksize() +{ + static std::size_t size = 256 * 1024; + return size; +} + +BOOST_CONTEXT_DECL +std::size_t minimum_stacksize() +{ + static std::size_t stacksize( + static_cast< std::size_t >( system_info().dwAllocationGranularity) ); + return stacksize; +} + +BOOST_CONTEXT_DECL +std::size_t maximum_stacksize() +{ + BOOST_ASSERT( ! is_stack_unbound() ); + static std::size_t stacksize = 8 * 1024 * 1024; + return stacksize; +} + +// Windows seams not to provide a limit for the stacksize +BOOST_CONTEXT_DECL +bool is_stack_unbound() +{ return true; } + +BOOST_CONTEXT_DECL +std::size_t pagesize() +{ + static std::size_t pagesize( + static_cast< std::size_t >( system_info().dwPageSize) ); + return pagesize; +} + +BOOST_CONTEXT_DECL +std::size_t page_count( std::size_t stacksize) +{ + return static_cast< std::size_t >( + std::ceil( + static_cast< float >( stacksize) / pagesize() ) ); +} + +}} diff --git a/unit_testing/CMakeLists.txt b/unit_testing/CMakeLists.txt new file mode 100644 index 0000000000..f8cbf4c998 --- /dev/null +++ b/unit_testing/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 2.6) +project(cppa_unit_tests CXX) + +# Set up environment paths to cmake modules and libcppa +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +add_executable(unit_tests + main.cpp + test__atom.cpp + test__intrusive_containers.cpp + test__local_group.cpp + test__pattern.cpp + test__remote_actor.cpp + test__serialization.cpp + test__tuple.cpp + test__uniform_type.cpp + ping_pong.cpp + test__fixed_vector.cpp + test__intrusive_ptr.cpp + test__match.cpp + test__primitive_variant.cpp + test__ripemd_160.cpp + test__spawn.cpp + test__type_list.cpp + test__yield_interface.cpp) + +# search for libs +if(NOT cppa_LIBRARY) + find_package(Libcppa REQUIRED) +endif (NOT cppa_LIBRARY) + +find_package(Boost COMPONENTS thread REQUIRED) + +link_directories(${Boost_LIBRARY_DIRS}) +include_directories(. ${cppa_INCLUDE} ${Boost_INCLUDE_DIRS}) + +set(EXAMPLE_LIBS ${CMAKE_DL_LIBS} ${CPPA_LIBRARY} ${Boost_THREAD_LIBRARY}) + +target_link_libraries(unit_tests ${EXAMPLE_LIBS}) diff --git a/unit_testing/FindLibcppa.cmake b/unit_testing/FindLibcppa.cmake new file mode 100644 index 0000000000..c1f1d2236a --- /dev/null +++ b/unit_testing/FindLibcppa.cmake @@ -0,0 +1,65 @@ +# - Try to find libcppa +# Once done this will define +# +# CPPA_FOUND - system has libcppa +# CPPA_INCLUDE - libcppa include dir +# CPPA_LIBRARY - link againgst libcppa +# + +if (CPPA_LIBRARY AND CPPA_INCLUDE) + set(CPPA_FOUND TRUE) +else (CPPA_LIBRARY AND CPPA_INCLUDE) + + find_path(CPPA_INCLUDE + NAMES + cppa/cppa.hpp + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ${CPPA_INCLUDE_PATH} + ${CPPA_LIBRARY_PATH} + ${CMAKE_INCLUDE_PATH} + ${CMAKE_INSTALL_PREFIX}/include + ) + + if (CPPA_INCLUDE) + message (STATUS "Header files found ...") + else (CPPA_INCLUDE) + message (SEND_ERROR "Header files NOT found. Provide absolute path with -DCPPA_INCLUDE_PATH=.") + endif (CPPA_INCLUDE) + + find_library(CPPA_LIBRARY + NAMES + libcppa + cppa + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ${CPPA_INCLUDE_PATH} + ${CPPA_INCLUDE_PATH}/.libs + ${CPPA_LIBRARY_PATH} + ${CPPA_LIBRARY_PATH}/.libs + ${CMAKE_LIBRARY_PATH} + ${CMAKE_INSTALL_PREFIX}/lib + ${LIBRARY_OUTPUT_PATH} + ) + + if (CPPA_LIBRARY) + message (STATUS "Library found ...") + else (CPPA_LIBRARY) + message (SEND_ERROR "Library NOT found. Provide absolute path with -DCPPA_LIBRARY_PATH=.") + endif (CPPA_LIBRARY) + + if (CPPA_INCLUDE AND CPPA_LIBRARY) + set(CPPA_FOUND TRUE) + set(CPPA_INCLUDE ${CPPA_INCLUDE}) + set(CPPA_LIBRARY ${CPPA_LIBRARY}) + else (CPPA_INCLUDE AND CPPA_LIBRARY) + message (FATAL_ERROR "CPPA LIBRARY AND/OR HEADER NOT FOUND!") + endif (CPPA_INCLUDE AND CPPA_LIBRARY) + +endif (CPPA_LIBRARY AND CPPA_INCLUDE) diff --git a/unit_testing/Makefile.am b/unit_testing/Makefile.am deleted file mode 100644 index 21659ba151..0000000000 --- a/unit_testing/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -AUTOMAKE_OPTIONS = subdir-objects -ACLOCAL_AMFLAGS = -I ../m4 - -noinst_PROGRAMS = unit_tests - -unit_tests_SOURCES = main.cpp \ - ping_pong.cpp \ - test__atom.cpp \ - test__fixed_vector.cpp \ - test__intrusive_containers.cpp \ - test__intrusive_ptr.cpp \ - test__local_group.cpp \ - test__pattern.cpp \ - test__primitive_variant.cpp \ - test__remote_actor.cpp \ - test__ripemd_160.cpp \ - test__match.cpp \ - test__serialization.cpp \ - test__spawn.cpp \ - test__tuple.cpp \ - test__type_list.cpp \ - test__uniform_type.cpp \ - test__yield_interface.cpp - -unit_tests_DEPENDENCIES = ../.libs/libcppa.la - -AM_CPPFLAGS = -I../ -unit_tests_CXXFLAGS = --std=c++0x -pedantic -Wall -Wextra -unit_tests_LDADD = -L../.libs/ -lcppa $(BOOST_LDFLAGS) $(BOOST_THREAD_LIB) diff --git a/unit_testing/main.cpp b/unit_testing/main.cpp index 659b58677b..9f9255b0c2 100644 --- a/unit_testing/main.cpp +++ b/unit_testing/main.cpp @@ -13,28 +13,26 @@ #include #include "test.hpp" +#include "ping_pong.hpp" #include "cppa/cppa.hpp" -#include "cppa/cow_tuple.hpp" #include "cppa/match.hpp" #include "cppa/config.hpp" #include "cppa/anything.hpp" +#include "cppa/cow_tuple.hpp" #include "cppa/detail/demangle.hpp" #include "cppa/uniform_type_info.hpp" #include "cppa/process_information.hpp" -#include "cppa/detail/mock_scheduler.hpp" #include "cppa/detail/thread_pool_scheduler.hpp" #define CPPA_TEST_CATCH_BLOCK() \ -catch (std::exception& e) \ -{ \ +catch (std::exception& e) { \ std::cerr << "test exited after throwing an instance of \"" \ << ::cppa::detail::demangle(typeid(e).name()) \ << "\"\n what(): " << e.what() << std::endl; \ errors += 1; \ } \ -catch (...) \ -{ \ +catch (...) { \ std::cerr << "test exited because of an unknown exception" << std::endl; \ errors += 1; \ } @@ -65,8 +63,7 @@ using std::endl; using namespace cppa; -std::vector split(const std::string& str, char delim) -{ +std::vector split(const std::string& str, char delim) { std::vector result; std::stringstream strs{str}; std::string tmp; @@ -74,8 +71,7 @@ std::vector split(const std::string& str, char delim) return result; } -void print_node_id() -{ +void print_node_id() { auto pinfo = cppa::process_information::get(); auto node_id_hash = cppa::to_string(pinfo->node_id()); cout << "node id: " << node_id_hash << endl; @@ -87,97 +83,74 @@ void print_node_id() << endl; } -std::vector get_kv_pairs(int argc, char** argv, int begin = 1) -{ +std::vector get_kv_pairs(int argc, char** argv, int begin = 1) { std::vector result; - for (int i = begin; i < argc; ++i) - { + for (int i = begin; i < argc; ++i) { auto vec = split(argv[i], '='); - if (vec.size() != 2) - { + if (vec.size() != 2) { cerr << "\"" << argv[i] << "\" is not a key-value pair" << endl; } else if (std::any_of(result.begin(), result.end(), - [&](const string_pair& p) { return p.first == vec[0]; })) - { + [&](const string_pair& p) { return p.first == vec[0]; })) { cerr << "key \"" << vec[0] << "\" is already defined" << endl; } - else - { + else { result.emplace_back(vec[0], vec[1]); } } return result; } -void usage(char const* argv0) -{ +void usage(const char* argv0) { cout << "usage: " << split(argv0, '/').back() << " " << "[run=remote_actor] " << "[scheduler=(thread_pool_scheduler|mock_scheduler)]" << endl; } -int main(int argc, char** argv) -{ - /* - match_each(argv + 1, argv + argc) - ( - on_arg_match >> [](const std::string& str) - { - cout << "matched \"" << str << "\"" << endl; - } - ); - - pmatch_each(argv + 1, argv + argc, [](char const* cstr) { return split(cstr, '='); }) - ( - on_arg_match >> [](const std::string& key, const std::string& value) - { - cout << "key = \"" << key << "\", value = \"" << value << "\"" - << endl; - }, - others() >> [](const any_tuple& oops) - { - cout << "not a key value pair: " << to_string(oops) << endl; - } - ); - - return 0; - //*/ - - - /* - auto nao = remote_actor("192.168.1.148", 12000); - send(nao, atom("speak"), "i am an actor! seriously!"); - return 0; - */ - - +int main(int argc, char** argv) { auto args = get_kv_pairs(argc, argv); - match_each(args) - ( - on("run", val) >> [&](const std::string& what) - { - if (what == "remote_actor") - { - test__remote_actor(argv[0], true, args); - exit(0); + match_each(args) ( + on("run", "remote_actor") >> [&]() { + test__remote_actor(argv[0], true, args); + exit(0); + }, + on("run", "threaded_ping_pong") >> []() { + spawn(pong, spawn(ping, 1000)); + await_all_others_done(); + exit(0); + }, + on("run", "ping_pong") >> []() { + spawn_event_based_pong(spawn_event_based_ping(1000000)); + await_all_others_done(); + exit(0); + }, + on("run_ping", arg_match) >> [&](const std::string& num_pings) { + auto ping_actor = spawn(ping, std::stoi(num_pings)); + //auto ping_actor = spawn_event_based_ping(std::stoi(num_pings)); + std::uint16_t port = 4242; + bool success = false; + do { + try { + publish(ping_actor, port); + success = true; + } + catch (bind_failure&) { + // try next port + ++port; + } } + while (!success); + cout << "port is " << port << endl; + await_all_others_done(); + exit(0); }, - on("scheduler", val) >> [](const std::string& sched) - { - if (sched == "thread_pool_scheduler") - { + on("scheduler", val) >> [](const std::string& sched) { + if (sched == "thread_pool_scheduler") { cout << "using thread_pool_scheduler" << endl; set_scheduler(new cppa::detail::thread_pool_scheduler); } - else if (sched == "mock_scheduler") - { - cout << "using mock_scheduler" << endl; - set_scheduler(new cppa::detail::mock_scheduler); - } - else - { + else { cerr << "unknown scheduler: " << sched << endl; exit(1); } @@ -185,7 +158,6 @@ int main(int argc, char** argv) ); std::cout << std::boolalpha; size_t errors = 0; - //print_node_id(); RUN_TEST(test__ripemd_160); RUN_TEST(test__primitive_variant); @@ -198,10 +170,10 @@ int main(int argc, char** argv) RUN_TEST(test__fixed_vector); RUN_TEST(test__tuple); RUN_TEST(test__serialization); - RUN_TEST(test__local_group); RUN_TEST(test__atom); RUN_TEST(test__yield_interface); RUN_TEST(test__spawn); + RUN_TEST(test__local_group); RUN_TEST_A3(test__remote_actor, argv[0], false, args); cout << endl << "error(s) in all tests: " << errors diff --git a/unit_testing/ping_pong.cpp b/unit_testing/ping_pong.cpp index 43a3448385..41f91f8e37 100644 --- a/unit_testing/ping_pong.cpp +++ b/unit_testing/ping_pong.cpp @@ -3,48 +3,107 @@ #include "ping_pong.hpp" #include "cppa/cppa.hpp" +#include "cppa/sb_actor.hpp" #include "cppa/to_string.hpp" -namespace { int s_pongs = 0; } +namespace { size_t s_pongs = 0; } using std::cout; using std::endl; using namespace cppa; -int pongs() -{ +size_t pongs() { return s_pongs; } -void ping() -{ +void ping(size_t num_pings) { s_pongs = 0; - receive_loop - ( - on() >> [](int value) - { - ++s_pongs; - reply(atom("ping"), value + 1); + do_receive ( + on() >> [&](int value) { + //cout << to_string(self->last_dequeued()) << endl; + if (++s_pongs == num_pings) { + reply(atom("EXIT"), exit_reason::user_defined); + } + else { + reply(atom("ping"), value); + } + }, + others() >> []() { + cout << "unexpected message; " + << __FILE__ << " line " << __LINE__ << ": " + << to_string(self->last_dequeued()) << endl; + self->quit(exit_reason::user_defined); } - ); + ) + .until(gref(s_pongs) == num_pings); +} + +actor_ptr spawn_event_based_ping(size_t num_pings) { + s_pongs = 0; + struct impl : public sb_actor { + behavior init_state; + impl(size_t num_pings) { + init_state = ( + on() >> [num_pings, this](int value) { + //cout << to_string(self->last_dequeued()) << endl; + if (++s_pongs >= num_pings) { + reply(atom("EXIT"), exit_reason::user_defined); + quit(); + } + else { + reply(atom("ping"), value); + } + }, + others() >> []() { + cout << "unexpected message; " + << __FILE__ << " line " << __LINE__ << ": " + << to_string(self->last_dequeued()) << endl; + self->quit(exit_reason::user_defined); + } + ); + } + }; + return spawn(num_pings); } -void pong(actor_ptr ping_actor) -{ - self->link_to(ping_actor); +void pong(actor_ptr ping_actor) { // kickoff send(ping_actor, atom("pong"), 0); - receive_loop - ( - on(atom("ping"), 9) >> []() - { - // terminate with non-normal exit reason - // to force ping actor to quit - self->quit(exit_reason::user_defined); - }, - on() >> [](int value) - { + receive_loop ( + on() >> [](int value) { + //cout << to_string(self->last_dequeued()) << endl; reply(atom("pong"), value + 1); + }, + others() >> []() { + cout << "unexpected message; " + << __FILE__ << " line " << __LINE__ << ": " + << to_string(self->last_dequeued()) << endl; + self->quit(exit_reason::user_defined); } ); } + +actor_ptr spawn_event_based_pong(actor_ptr ping_actor) { + CPPA_REQUIRE(ping_actor.get() != nullptr); + struct impl : public sb_actor { + behavior init_state; + impl() { + init_state = ( + on() >> [](int value) { + //cout << to_string(self->last_dequeued()) << endl; + reply(atom("pong"), value + 1); + }, + others() >> []() { + cout << "unexpected message; " + << __FILE__ << " line " << __LINE__ << ": " + << to_string(self->last_dequeued()) << endl; + self->quit(exit_reason::user_defined); + } + ); + } + }; + auto pptr = spawn(); + // kickoff + ping_actor->enqueue(pptr.get(), make_any_tuple(atom("pong"), 0)); + return pptr; +} diff --git a/unit_testing/ping_pong.hpp b/unit_testing/ping_pong.hpp index 664ef9e1bf..1f247a8ad5 100644 --- a/unit_testing/ping_pong.hpp +++ b/unit_testing/ping_pong.hpp @@ -3,10 +3,15 @@ #include "cppa/actor.hpp" -void ping(); +void ping(size_t num_pings); + +cppa::actor_ptr spawn_event_based_ping(size_t num_pings); + void pong(cppa::actor_ptr ping_actor); +cppa::actor_ptr spawn_event_based_pong(cppa::actor_ptr ping_actor); + // returns the number of messages ping received -int pongs(); +size_t pongs(); #endif // PING_PONG_HPP diff --git a/unit_testing/test.hpp b/unit_testing/test.hpp index d2b534e673..d98d5d9db7 100644 --- a/unit_testing/test.hpp +++ b/unit_testing/test.hpp @@ -13,8 +13,7 @@ inline bool cppa_check_value_fun_eq(const T1& value1, const T2& value2, typename std::enable_if< !std::is_integral::value || !std::is_integral::value - >::type* = 0) -{ + >::type* = 0) { return value1 == value2; } @@ -23,19 +22,16 @@ inline bool cppa_check_value_fun_eq(T1 value1, T2 value2, typename std::enable_if< std::is_integral::value && std::is_integral::value - >::type* = 0) -{ + >::type* = 0) { return value1 == static_cast(value2); } template inline bool cppa_check_value_fun(const T1& value1, const T2& value2, - char const* file_name, + const char* file_name, int line_number, - size_t& error_count) -{ - if (cppa_check_value_fun_eq(value1, value2) == false) - { + size_t& error_count) { + if (cppa_check_value_fun_eq(value1, value2) == false) { std::cerr << "ERROR in file " << file_name << " on line " << line_number << " => expected value: " << value1 << ", found: " << value2 @@ -48,24 +44,20 @@ inline bool cppa_check_value_fun(const T1& value1, const T2& value2, template inline void cppa_check_value_verbose_fun(const T1& value1, const T2& value2, - char const* file_name, + const char* file_name, int line_number, - size_t& error_count) -{ + size_t& error_count) { if (cppa_check_value_fun(value1, value2, file_name, - line_number, error_count)) - { + line_number, error_count)) { std::cout << "line " << line_number << " passed" << std::endl; } } #define CPPA_TEST(name) \ -struct cppa_test_scope \ -{ \ +struct cppa_test_scope { \ size_t error_count; \ cppa_test_scope() : error_count(0) { } \ - ~cppa_test_scope() \ - { \ + ~cppa_test_scope() { \ std::cout << error_count << " error(s) detected" << std::endl; \ } \ } cppa_ts; @@ -75,17 +67,14 @@ struct cppa_test_scope \ #ifdef CPPA_VERBOSE_CHECK #define CPPA_IF_VERBOSE(line_of_code) line_of_code #define CPPA_CHECK(line_of_code) \ -if (!(line_of_code)) \ -{ \ +if (!(line_of_code)) { \ std::cerr << "ERROR in file " << __FILE__ << " on line " << __LINE__ \ << " => " << #line_of_code << std::endl; \ ++cppa_ts.error_count; \ } \ -else \ -{ \ +else { \ std::cout << "line " << __LINE__ << " passed" << std::endl; \ -} \ -((void) 0) +} ((void) 0) #define CPPA_CHECK_EQUAL(lhs_loc, rhs_loc) \ cppa_check_value_verbose_fun((lhs_loc), (rhs_loc), __FILE__, __LINE__, \ cppa_ts.error_count) @@ -93,8 +82,7 @@ else \ #else #define CPPA_IF_VERBOSE(line_of_code) ((void) 0) #define CPPA_CHECK(line_of_code) \ -if (!(line_of_code)) \ -{ \ +if (!(line_of_code)) { \ std::cerr << "ERROR in file " << __FILE__ << " on line " << __LINE__ \ << " => " << #line_of_code << std::endl; \ ++cppa_ts.error_count; \ @@ -115,7 +103,7 @@ if (!(line_of_code)) \ typedef std::pair string_pair; size_t test__yield_interface(); -size_t test__remote_actor(char const* app_path, bool is_client, +size_t test__remote_actor(const char* app_path, bool is_client, const std::vector& args); size_t test__ripemd_160(); size_t test__uniform_type(); diff --git a/unit_testing/test__atom.cpp b/unit_testing/test__atom.cpp index c2cf26f47c..06f19861cd 100644 --- a/unit_testing/test__atom.cpp +++ b/unit_testing/test__atom.cpp @@ -6,6 +6,12 @@ #include "cppa/cppa.hpp" +namespace cppa { +inline std::ostream& operator<<(std::ostream& out, const atom_value& a) { + return (out << to_string(a)); +} +} + using std::cout; using std::endl; using std::string; @@ -13,20 +19,10 @@ using std::string; using namespace cppa; using namespace cppa::util; -namespace { - -constexpr auto s_foo = atom("FooBar"); - -inline std::ostream& operator<<(std::ostream& out, const atom_value& a) -{ - return (out << to_string(a)); -} - -} // namespace +namespace { constexpr auto s_foo = atom("FooBar"); } template -void foo() -{ +void foo() { cout << "foo(" << static_cast(AtomValue) << " = " << to_string(AtomValue) @@ -34,8 +30,7 @@ void foo() << endl; } -size_t test__atom() -{ +size_t test__atom() { bool matched_pattern[3] = { false, false, false }; CPPA_TEST(test__atom); // check if there are leading bits that distinguish "zzz" and "000 " @@ -50,29 +45,23 @@ size_t test__atom() << make_cow_tuple(atom("b"), atom("a"), atom("c"), 23.f) << make_cow_tuple(atom("a"), atom("b"), atom("c"), 23.f); int i = 0; - receive_for(i, 3) - ( - on() >> [&](std::uint32_t value) - { + receive_for(i, 3) ( + on() >> [&](std::uint32_t value) { matched_pattern[0] = true; CPPA_CHECK_EQUAL(value, 42); }, - on() >> [&](const string& str) - { + on() >> [&](const string& str) { matched_pattern[1] = true; CPPA_CHECK_EQUAL(str, "cstring"); }, - on() >> [&](float value) - { + on() >> [&](float value) { matched_pattern[2] = true; CPPA_CHECK_EQUAL(value, 23.f); } ); CPPA_CHECK(matched_pattern[0] && matched_pattern[1] && matched_pattern[2]); - receive - ( - others() >> []() - { + receive ( + others() >> []() { // "erase" message { atom("b"), atom("a"), atom("c"), 23.f } } ); diff --git a/unit_testing/test__fixed_vector.cpp b/unit_testing/test__fixed_vector.cpp index 110acabc65..16e8a39b92 100644 --- a/unit_testing/test__fixed_vector.cpp +++ b/unit_testing/test__fixed_vector.cpp @@ -11,8 +11,7 @@ using std::endl; using std::equal; using cppa::util::fixed_vector; -size_t test__fixed_vector() -{ +size_t test__fixed_vector() { CPPA_TEST(test__fixed_vector); int arr1[] {1, 2, 3, 4}; fixed_vector vec1 {1, 2, 3, 4}; diff --git a/unit_testing/test__intrusive_containers.cpp b/unit_testing/test__intrusive_containers.cpp index efda075de6..f61d0741d5 100644 --- a/unit_testing/test__intrusive_containers.cpp +++ b/unit_testing/test__intrusive_containers.cpp @@ -39,40 +39,34 @@ using std::end; namespace { size_t s_iint_instances = 0; } -struct iint -{ +struct iint { iint* next; int value; inline iint(int val = 0) : next(nullptr), value(val) { ++s_iint_instances; } ~iint() { --s_iint_instances; } }; -inline bool operator==(const iint& lhs, const iint& rhs) -{ +inline bool operator==(const iint& lhs, const iint& rhs) { return lhs.value == rhs.value; } -inline bool operator==(const iint& lhs, int rhs) -{ +inline bool operator==(const iint& lhs, int rhs) { return lhs.value == rhs; } -inline bool operator==(int lhs, const iint& rhs) -{ +inline bool operator==(int lhs, const iint& rhs) { return lhs == rhs.value; } typedef cppa::intrusive::singly_linked_list iint_list; typedef cppa::intrusive::single_reader_queue iint_queue; -size_t test__intrusive_containers() -{ +size_t test__intrusive_containers() { CPPA_TEST(test__intrusive_containers); iint_list ilist1; ilist1.push_back(new iint(1)); ilist1.emplace_back(2); - ilist1.push_back(new iint(3)); - { + ilist1.push_back(new iint(3)); { iint_list tmp; tmp.push_back(new iint(4)); tmp.push_back(new iint(5)); @@ -112,14 +106,31 @@ size_t test__intrusive_containers() int iarr3[] = { 2, 4 }; CPPA_CHECK((std::equal(begin(iarr3), end(iarr3), begin(ilist2)))); - auto x = ilist2.take_after(ilist2.before_begin()); - CPPA_CHECK_EQUAL(x->value, 2); - delete x; + auto xy = ilist2.take_after(ilist2.before_begin()); + CPPA_CHECK_EQUAL(xy->value, 2); + delete xy; ilist2.clear(); // two dummies CPPA_CHECK_EQUAL(s_iint_instances, 2); CPPA_CHECK(ilist2.empty()); + cppa::intrusive::single_reader_queue q; + q.push_back(new iint(1)); + q.push_back(new iint(2)); + q.push_back(new iint(3)); + + auto x = q.pop(); + CPPA_CHECK_EQUAL(1, x->value); + delete x; + x = q.pop(); + CPPA_CHECK_EQUAL(2, x->value); + delete x; + x = q.pop(); + CPPA_CHECK_EQUAL(3, x->value); + delete x; + x = q.try_pop(); + CPPA_CHECK(x == nullptr); + return CPPA_TEST_RESULT; } diff --git a/unit_testing/test__intrusive_ptr.cpp b/unit_testing/test__intrusive_ptr.cpp index 11c362856a..18d8933b55 100644 --- a/unit_testing/test__intrusive_ptr.cpp +++ b/unit_testing/test__intrusive_ptr.cpp @@ -15,8 +15,7 @@ int class1_instances = 0; } -struct class0 : cppa::detail::ref_counted_impl -{ +struct class0 : cppa::detail::ref_counted_impl { class0() { ++class0_instances; } virtual ~class0() { --class0_instances; } @@ -24,8 +23,7 @@ struct class0 : cppa::detail::ref_counted_impl virtual class0* create() const { return new class0; } }; -struct class1 : class0 -{ +struct class1 : class0 { class1() { ++class1_instances; } virtual ~class1() { --class1_instances; } @@ -36,39 +34,33 @@ struct class1 : class0 typedef intrusive_ptr class0_ptr; typedef intrusive_ptr class1_ptr; -class0* get_test_rc() -{ +class0* get_test_rc() { return new class0; } -class0_ptr get_test_ptr() -{ +class0_ptr get_test_ptr() { return get_test_rc(); } -size_t test__intrusive_ptr() -{ +size_t test__intrusive_ptr() { // this test dosn't test thread-safety of intrusive_ptr // however, it is thread safe since it uses atomic operations only CPPA_TEST(test__intrusive_ptr); - - { + { class0_ptr p(new class0); CPPA_CHECK_EQUAL(class0_instances, 1); CPPA_CHECK(p->unique()); } CPPA_CHECK_EQUAL(class0_instances, 0); - - { + { class0_ptr p; p = new class0; CPPA_CHECK_EQUAL(class0_instances, 1); CPPA_CHECK(p->unique()); } CPPA_CHECK_EQUAL(class0_instances, 0); - - { + { class0_ptr p1; p1 = get_test_rc(); class0_ptr p2 = p1; @@ -76,8 +68,7 @@ size_t test__intrusive_ptr() CPPA_CHECK_EQUAL(p1->unique(), false); } CPPA_CHECK_EQUAL(class0_instances, 0); - - { + { std::list pl; pl.push_back(get_test_ptr()); pl.push_back(get_test_rc()); @@ -86,8 +77,7 @@ size_t test__intrusive_ptr() CPPA_CHECK_EQUAL(class0_instances, 3); } CPPA_CHECK_EQUAL(class0_instances, 0); - - { + { class0_ptr p1(new class0); p1 = new class1; CPPA_CHECK_EQUAL(class0_instances, 1); diff --git a/unit_testing/test__local_group.cpp b/unit_testing/test__local_group.cpp index ef451158b3..36f85cd746 100644 --- a/unit_testing/test__local_group.cpp +++ b/unit_testing/test__local_group.cpp @@ -22,34 +22,26 @@ using std::endl; using std::string; using namespace cppa; -size_t test__local_group() -{ +size_t test__local_group() { CPPA_TEST(test__local_group); auto foo_group = group::get("local", "foo"); actor_ptr master = self; - for (int i = 0; i < 5; ++i) - { + for (int i = 0; i < 5; ++i) { // spawn five workers and let them join local/foo - auto w = spawn([&master]() - { - receive(on() >> [&master](int v) - { - send(master, v); - }); - }); - w->join(foo_group); + spawn_in_group(foo_group, [master]() { + receive(on() >> [master](int v) { + send(master, v); + }); + }); } send(foo_group, 2); int result = 0; - do_receive - ( - on() >> [&](int value) - { + do_receive ( + on() >> [&](int value) { CPPA_CHECK(value == 2); result += value; }, - after(std::chrono::seconds(2)) >> [&]() - { + after(std::chrono::seconds(2)) >> [&]() { CPPA_CHECK(false); result = 10; } diff --git a/unit_testing/test__match.cpp b/unit_testing/test__match.cpp index 3b0eeeb474..2195bfb825 100644 --- a/unit_testing/test__match.cpp +++ b/unit_testing/test__match.cpp @@ -23,18 +23,105 @@ bool is_even(int i) { return i % 2 == 0; } * */ -bool ascending(int a, int b, int c) -{ +bool ascending(int a, int b, int c) { return a < b && b < c; } -size_t test__match() -{ +vector to_vec(util::type_list<>, vector vec = vector{}) { + return vec; +} + +template +vector to_vec(util::type_list, vector vec = vector{}) { + vec.push_back(uniform_typeid()); + return to_vec(util::type_list{}, std::move(vec)); +} + +template +class __ { + + typedef typename util::get_callable_trait::type trait; + + public: + + __(Fun f, string annotation = "") : m_fun(f), m_annotation(annotation) { } + + __ operator[](const string& str) const { + return {m_fun, str}; + } + + template + void operator()(Args&&... args) const { + m_fun(std::forward(args)...); + } + + void plot_signature() { + auto vec = to_vec(typename trait::arg_types{}); + for (auto i : vec) { + cout << i->name() << " "; + } + cout << endl; + } + + const string& annotation() const { + return m_annotation; + } + + private: + + Fun m_fun; + string m_annotation; + +}; + +template +__ get__(Fun f) { + return {f}; +} + +struct fobaz : sb_actor { + + behavior init_state; + + void vfun() { + cout << "fobaz::mfun" << endl; + } + + void ifun(int i) { + cout << "fobaz::ifun(" << i << ")" << endl; + } + + fobaz() { + init_state = ( + on() >> [=](int i) { ifun(i); }, + others() >> std::function{std::bind(&fobaz::vfun, this)} + ); + } + +}; + +size_t test__match() { CPPA_TEST(test__match); using namespace std::placeholders; using namespace cppa::placeholders; + /* + auto x_ = get__([](int, float) { cout << "yeeeehaaaa!" << endl; })["prints 'yeeeehaaaa'"]; + cout << "x_: "; x_(1, 1.f); + cout << "x_.annotation() = " << x_.annotation() << endl; + cout << "x_.plot_signature: "; x_.plot_signature(); + + auto fun = ( + on() >> [](int i) { + cout << "i = " << i << endl; + }, + after(std::chrono::seconds(0)) >> []() { + cout << "no int found in mailbox" << endl; + } + ); + */ + auto expr0_a = gcall(ascending, _x1, _x2, _x3); CPPA_CHECK(ge_invoke(expr0_a, 1, 2, 3)); CPPA_CHECK(!ge_invoke(expr0_a, 3, 2, 1)); @@ -140,10 +227,52 @@ size_t test__match() bool invoked = false; - match("abc") - ( - on().when(_x1 == "abc") >> [&]() - { + auto kvp_split1 = [](const string& str) -> vector { + auto pos = str.find('='); + if (pos != string::npos && pos == str.rfind('=')) { + return vector{str.substr(0, pos), str.substr(pos+1)}; + } + return {}; + }; + /* + auto kvp_split2 = [](const string& str) -> option > { + auto pos = str.find('='); + if (pos != string::npos && pos == str.rfind('=')) { + return vector{str.substr(0, pos-1), str.substr(pos+1)}; + } + return {}; + }; + */ + + match("value=42") ( + on(kvp_split1).when(_x1.not_empty()) >> [&](const vector& vec) { + CPPA_CHECK_EQUAL(vec[0], "value"); + CPPA_CHECK_EQUAL(vec[1], "42"); + invoked = true; + } + ); + CPPA_CHECK(invoked); + invoked = false; + + auto toint = [](const string& str) -> option { + char* endptr = nullptr; + int result = static_cast(strtol(str.c_str(), &endptr, 10)); + if (endptr != nullptr && *endptr == '\0') { + return result; + } + return {}; + }; + match("42") ( + on(toint) >> [&](int i) { + CPPA_CHECK_EQUAL(i, 42); + invoked = true; + } + ); + CPPA_CHECK(invoked); + invoked = false; + + match("abc") ( + on().when(_x1 == "abc") >> [&]() { invoked = true; } ); @@ -153,14 +282,11 @@ size_t test__match() bool disable_case1 = true; bool case1_invoked = false; bool case2_invoked = false; - auto expr19 = - ( - on().when(gref(disable_case1) == false) >> [&]() - { + auto expr19 = ( + on().when(gref(disable_case1) == false) >> [&]() { case1_invoked = true; }, - on() >> [&]() - { + on() >> [&]() { case2_invoked = true; } ); @@ -179,8 +305,7 @@ size_t test__match() std::vector expr21_vec_a{1, 2, 3}; std::vector expr21_vec_b{1, 0, 2}; - auto vec_sorted = [](const std::vector& vec) - { + auto vec_sorted = [](const std::vector& vec) { return std::is_sorted(vec.begin(), vec.end()); }; auto expr21 = gcall(vec_sorted, _x1); @@ -190,12 +315,10 @@ size_t test__match() auto expr22 = _x1.empty() && _x2.not_empty(); CPPA_CHECK(ge_invoke(expr22, std::string(""), std::string("abc"))); - match(std::vector{1, 2, 3}) - ( + match(std::vector{1, 2, 3}) ( on().when( _x1 + _x2 + _x3 == 6 && _x2(is_even) - && _x3 % 2 == 1) >> [&]() - { + && _x3 % 2 == 1) >> [&]() { invoked = true; } ); @@ -203,41 +326,31 @@ size_t test__match() invoked = false; string sum; - match_each({"-h", "--version", "-wtf"}) - ( - on().when(_x1.in({"-h", "--help"})) >> [&](string s) - { + match_each({"-h", "--version", "-wtf"}) ( + on().when(_x1.in({"-h", "--help"})) >> [&](string s) { sum += s; }, - on().when(_x1 == "-v" || _x1 == "--version") >> [&](string s) - { + on().when(_x1 == "-v" || _x1 == "--version") >> [&](string s) { sum += s; }, - on().when(_x1.starts_with("-")) >> [&](const string& str) - { - match_each(str.begin() + 1, str.end()) - ( - on().when(_x1.in({'w', 't', 'f'})) >> [&](char c) - { + on().when(_x1.starts_with("-")) >> [&](const string& str) { + match_each(str.begin() + 1, str.end()) ( + on().when(_x1.in({'w', 't', 'f'})) >> [&](char c) { sum += c; }, - others() >> [&]() - { + others() >> [&]() { CPPA_ERROR("unexpected match"); } ); }, - others() >> [&]() - { + others() >> [&]() { CPPA_ERROR("unexpected match"); } ); CPPA_CHECK_EQUAL("-h--versionwtf", sum); - match(5) - ( - on().when(_x1 < 6) >> [&](int i) - { + match(5) ( + on().when(_x1 < 6) >> [&](int i) { CPPA_CHECK_EQUAL(5, i); invoked = true; } @@ -246,10 +359,8 @@ size_t test__match() invoked = false; vector vec{"a", "b", "c"}; - match(vec) - ( - on("a", "b", val) >> [&](string& str) - { + match(vec) ( + on("a", "b", val) >> [&](string& str) { invoked = true; str = "C"; } @@ -258,10 +369,8 @@ size_t test__match() CPPA_CHECK_EQUAL("C", vec.back()); invoked = false; - match_each(vec) - ( - on("a") >> [&](string& str) - { + match_each(vec) ( + on("a") >> [&](string& str) { invoked = true; str = "A"; } @@ -271,16 +380,12 @@ size_t test__match() invoked = false; /* - match(vec) - ( - others() >> [&](any_tuple& tup) - { - if (detail::matches(tup)) - { + match(vec) ( + others() >> [&](any_tuple& tup) { + if (detail::matches(tup)) { tup.get_as_mutable(1) = "B"; } - else - { + else { CPPA_ERROR("matches(tup) == false"); } invoked = true; @@ -293,8 +398,7 @@ size_t test__match() vector vec2{"a=0", "b=1", "c=2"}; auto c2 = split(vec2.back(), '='); - match(c2) - ( + match(c2) ( on("c", "2") >> [&]() { invoked = true; } ); CPPA_CHECK_EQUAL(true, invoked); @@ -303,28 +407,23 @@ size_t test__match() /*, int pmatches = 0; using std::placeholders::_1; - pmatch_each(vec2.begin(), vec2.end(), std::bind(split, _1, '=')) - ( - on("a", val) >> [&](const string& value) - { + match_each(vec2.begin(), vec2.end(), std::bind(split, _1, '=')) ( + on("a", val) >> [&](const string& value) { CPPA_CHECK_EQUAL("0", value); CPPA_CHECK_EQUAL(0, pmatches); ++pmatches; }, - on("b", val) >> [&](const string& value) - { + on("b", val) >> [&](const string& value) { CPPA_CHECK_EQUAL("1", value); CPPA_CHECK_EQUAL(1, pmatches); ++pmatches; }, - on("c", val) >> [&](const string& value) - { + on("c", val) >> [&](const string& value) { CPPA_CHECK_EQUAL("2", value); CPPA_CHECK_EQUAL(2, pmatches); ++pmatches; } - others() >> [](const any_tuple& value) - { + others() >> [](const any_tuple& value) { cout << to_string(value) << endl; } ); diff --git a/unit_testing/test__pattern.cpp b/unit_testing/test__pattern.cpp index c7bebb0f3f..cb8d2e9714 100644 --- a/unit_testing/test__pattern.cpp +++ b/unit_testing/test__pattern.cpp @@ -18,7 +18,6 @@ #include "cppa/util/is_primitive.hpp" #include "cppa/util/is_mutable_ref.hpp" -#include "cppa/detail/invokable.hpp" #include "cppa/detail/types_array.hpp" #include "cppa/detail/decorated_tuple.hpp" @@ -28,12 +27,10 @@ using std::string; using namespace cppa; template -string plot(const Arr& arr) -{ +string plot(const Arr& arr) { std::ostringstream oss; oss << "{ "; - for (size_t i = 0; i < Arr::size; ++i) - { + for (size_t i = 0; i < Arr::size; ++i) { if (i > 0) oss << ", "; oss << "arr[" << i << "] = " << ((arr[i]) ? arr[i]->name() : "anything"); } @@ -41,66 +38,46 @@ string plot(const Arr& arr) return oss.str(); } -typedef std::pair foobar; +typedef std::pair foobar; -static detail::types_array arr1; -static detail::types_array arr2; +static detail::types_array arr1; +static detail::types_array arr2; template -void match_test(const T& value) -{ - match(value) - ( - on() >> [&](int a, int b, int c) - { +void match_test(const T& value) { + match(value) ( + on() >> [&](int a, int b, int c) { cout << "(" << a << ", " << b << ", " << c << ")" << endl; }, - on_arg_match >> [&](const string& str) - { + on_arg_match >> [&](const string& str) { cout << str << endl; } ); } template -void invoke_test(std::vector& test_tuples, Testee& x) -{ +void invoke_test(std::vector& test_tuples, Testee& x) { boost::progress_timer t; - for (int i = 0; i < 1000000; ++i) - { + for (int i = 0; i < 1000000; ++i) { for (auto& t : test_tuples) x(t); } } -size_t test__pattern() -{ +size_t test__pattern() { CPPA_TEST(test__pattern); - //match_test(make_cow_tuple(1,2,3)); - //match_test(std::list{1, 2, 3}); - //match_test("abc"); - pattern i3; any_tuple i3_any_tup = make_cow_tuple(1, 2, 3); - /* - auto opt = tuple_cast(i3_any_tup, i3); - CPPA_CHECK(opt.valid()); - if (opt.valid()) - { - CPPA_CHECK_EQUAL(get<0>(*opt), 1); - CPPA_CHECK_EQUAL(get<1>(*opt), 3); - } - */ announce(&foobar::first, &foobar::second); - static constexpr char const* arr1_as_string = + static constexpr const char* arr1_as_string = "{ arr[0] = @i32, arr[1] = anything, arr[2] = float }"; - CPPA_CHECK_EQUAL(plot(arr1), arr1_as_string); - static constexpr char const* arr2_as_string = + CPPA_CHECK_EQUAL(arr1_as_string, plot(arr1)); + static constexpr const char* arr2_as_string = "{ arr[0] = @i32, arr[1] = anything, " "arr[2] = std::pair<@i32,@i32> }"; - CPPA_CHECK_EQUAL(plot(arr2), arr2_as_string); + CPPA_CHECK_EQUAL(arr2_as_string, plot(arr2)); // some pattern objects to play with pattern p0{util::wrapped{}}; @@ -159,10 +136,8 @@ size_t test__pattern() CPPA_CHECK(p11._matches_values(t3)); bool invoked = false; - match(t3) - ( - on() >> [&](int i) - { + match(t3) ( + on() >> [&](int i) { invoked = true; CPPA_CHECK_EQUAL(42, i); } @@ -178,10 +153,8 @@ size_t test__pattern() CPPA_CHECK(p13._matches_values(t4)); invoked = false; - match('a') - ( - on() >> [&](char c) - { + match('a') ( + on() >> [&](char c) { invoked = true; CPPA_CHECK_EQUAL('a', c); } @@ -190,10 +163,8 @@ size_t test__pattern() invoked = false; const char muhaha = 'a'; - match(muhaha) - ( - on() >> [&](char c) - { + match(muhaha) ( + on() >> [&](char c) { invoked = true; CPPA_CHECK_EQUAL('a', c); } @@ -224,44 +195,35 @@ size_t test__pattern() // let's check some invoke rules constexpr size_t num_lambdas = 6; bool lambda_invoked[num_lambdas]; - auto reset_invoke_states = [&]() - { - for (size_t i = 0; i < num_lambdas; ++i) - { + auto reset_invoke_states = [&]() { + for (size_t i = 0; i < num_lambdas; ++i) { lambda_invoked[i] = false; } }; reset_invoke_states(); - auto patterns = - ( - on() >> [&](int v1, int v2) - { + auto patterns = ( + on() >> [&](int v1, int v2) { CPPA_CHECK_EQUAL(v1, 1); CPPA_CHECK_EQUAL(v2, 3); lambda_invoked[0] = true; }, - on() >> [&](const string& str) - { + on() >> [&](const string& str) { CPPA_CHECK_EQUAL(str, "hello foo"); lambda_invoked[1] = true; }, - on("1", val, any_vals) >> [&](int value) - { + on("1", val, any_vals) >> [&](int value) { CPPA_CHECK_EQUAL(value, 2); lambda_invoked[2] = true; }, - on(1, val(), any_vals) >> [&](const string& str) - { + on(1, val(), any_vals) >> [&](const string& str) { CPPA_CHECK_EQUAL(str, "2"); lambda_invoked[3] = true; }, - on() >> [&](int value) - { + on() >> [&](int value) { CPPA_CHECK_EQUAL(value, 1); lambda_invoked[4] = true; }, - on_arg_match >> [&](double v1, const float& v2) - { + on_arg_match >> [&](double v1, const float& v2) { CPPA_CHECK_EQUAL(v1, 1.0); CPPA_CHECK_EQUAL(v2, 2.0f); lambda_invoked[5] = true; diff --git a/unit_testing/test__primitive_variant.cpp b/unit_testing/test__primitive_variant.cpp index 6bb22d4f08..eef5d6b243 100644 --- a/unit_testing/test__primitive_variant.cpp +++ b/unit_testing/test__primitive_variant.cpp @@ -2,33 +2,35 @@ #include "cppa/primitive_variant.hpp" -using namespace cppa; - namespace { -struct streamer -{ +struct streamer { std::ostream& o; streamer(std::ostream& mo) : o(mo) { } template - void operator()(const T& value) - { + void operator()(const T& value) { o << value; } + void operator()(const std::u16string&) { + } + void operator()(const std::u32string&) { + } }; -inline std::ostream& operator<<(std::ostream& o, - const cppa::primitive_variant& pv) -{ +} // namespace + + +namespace cppa { +inline std::ostream& operator<<(std::ostream& o, const primitive_variant& pv) { streamer s{o}; pv.apply(s); return o; } +} // namespace cppa -} // namespace +using namespace cppa; -size_t test__primitive_variant() -{ +size_t test__primitive_variant() { CPPA_TEST(test__primitive_variant); std::uint32_t forty_two = 42; @@ -38,19 +40,19 @@ size_t test__primitive_variant() CPPA_CHECK_EQUAL(v1.ptype(), pt_uint32); CPPA_CHECK_EQUAL(v2.ptype(), pt_uint32); get_ref(v2) = forty_two; - CPPA_CHECK_EQUAL(v1, v2); - CPPA_CHECK_EQUAL(v1, forty_two); - CPPA_CHECK_EQUAL(forty_two, v2); + CPPA_CHECK(equal(v1, v2)); + CPPA_CHECK(equal(v1, forty_two)); + CPPA_CHECK(equal(forty_two, v2)); // type mismatch => unequal - CPPA_CHECK(v2 != static_cast(forty_two)); + CPPA_CHECK(!equal(v2, static_cast(forty_two))); v1 = "Hello world"; CPPA_CHECK_EQUAL(v1.ptype(), pt_u8string); v2 = "Hello"; CPPA_CHECK_EQUAL(v2.ptype(), pt_u8string); get_ref(v2) += " world"; - CPPA_CHECK_EQUAL(v1, v2); + CPPA_CHECK(equal(v1, v2)); v2 = u"Hello World"; - CPPA_CHECK(v1 != v2); + CPPA_CHECK(!equal(v1, v2)); return CPPA_TEST_RESULT; } diff --git a/unit_testing/test__remote_actor.cpp b/unit_testing/test__remote_actor.cpp index 92f2cc0954..1fcf64bc97 100644 --- a/unit_testing/test__remote_actor.cpp +++ b/unit_testing/test__remote_actor.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,7 +7,6 @@ #include "ping_pong.hpp" #include "cppa/cppa.hpp" #include "cppa/exception.hpp" -#include "cppa/detail/thread.hpp" using std::cout; using std::cerr; @@ -16,45 +16,38 @@ using namespace cppa; namespace { -void client_part(const std::vector& args) -{ +void client_part(const std::vector& args) { auto i = std::find_if(args.begin(), args.end(), [](const string_pair& p) { return p.first == "port"; }); - if (i == args.end()) - { + if (i == args.end()) { throw std::runtime_error("no port specified"); } - std::istringstream iss(i->second); - std::uint16_t port; - iss >> port; + auto port = static_cast(std::stoi(i->second)); auto ping_actor = remote_actor("localhost", port); - spawn(pong, ping_actor); + //spawn_event_based_pong(ping_actor); + spawn(pong, ping_actor); await_all_others_done(); } } // namespace -size_t test__remote_actor(char const* app_path, bool is_client, - const std::vector& args) -{ - if (is_client) - { +size_t test__remote_actor(const char* app_path, bool is_client, + const std::vector& args) { + if (is_client) { client_part(args); return 0; } CPPA_TEST(test__remote_actor); - auto ping_actor = spawn(ping); + auto ping_actor = spawn_event_based_ping(10); + //auto ping_actor = spawn(ping, 10); std::uint16_t port = 4242; bool success = false; - do - { - try - { + do { + try { publish(ping_actor, port); success = true; } - catch (bind_failure&) - { + catch (bind_failure&) { // try next port ++port; } @@ -64,17 +57,17 @@ size_t test__remote_actor(char const* app_path, bool is_client, oss << app_path << " run=remote_actor port=" << port;// << " &>/dev/null"; // execute client_part() in a separate process, // connected via localhost socket - detail::thread child([&oss]() - { + std::thread child([&oss]() { std::string cmdstr = oss.str(); - if (system(cmdstr.c_str()) != 0) - { + if (system(cmdstr.c_str()) != 0) { cerr << "FATAL: command \"" << cmdstr << "\" failed!" << endl; abort(); } }); await_all_others_done(); - CPPA_CHECK_EQUAL(pongs(), 5); + CPPA_CHECK_EQUAL(10, pongs()); + // kill pong actor + // wait until separate process (in sep. thread) finished execution child.join(); return CPPA_TEST_RESULT; diff --git a/unit_testing/test__ripemd_160.cpp b/unit_testing/test__ripemd_160.cpp index acd4de01cd..b58e76dbc4 100644 --- a/unit_testing/test__ripemd_160.cpp +++ b/unit_testing/test__ripemd_160.cpp @@ -9,14 +9,12 @@ using cppa::util::ripemd_160; namespace { -std::string str_hash(const std::string& what) -{ +std::string str_hash(const std::string& what) { std::array hash; ripemd_160(hash, what); std::ostringstream oss; oss << std::hex; - for (auto i : hash) - { + for (auto i : hash) { oss.width(2); oss.fill('0'); oss << static_cast(i); @@ -28,8 +26,7 @@ std::string str_hash(const std::string& what) // verify ripemd implementation with example hash results from // http://homes.esat.kuleuven.be/~bosselae/ripemd160.html -size_t test__ripemd_160() -{ +size_t test__ripemd_160() { CPPA_TEST(test__ripemd_160); CPPA_CHECK_EQUAL(str_hash(""), "9c1185a5c5e9fc54612808977ee8f548b2258d31"); diff --git a/unit_testing/test__serialization.cpp b/unit_testing/test__serialization.cpp index d69a7edb41..eb284c75de 100644 --- a/unit_testing/test__serialization.cpp +++ b/unit_testing/test__serialization.cpp @@ -60,59 +60,51 @@ using namespace cppa::util; using cppa::detail::type_to_ptype; using cppa::detail::ptype_to_type; -struct struct_a -{ +struct struct_a { int x; int y; }; -bool operator==(const struct_a& lhs, const struct_a& rhs) -{ +bool operator==(const struct_a& lhs, const struct_a& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } -bool operator!=(const struct_a& lhs, const struct_a& rhs) -{ +bool operator!=(const struct_a& lhs, const struct_a& rhs) { return !(lhs == rhs); } -struct struct_b -{ +struct struct_b { struct_a a; int z; std::list ints; }; -bool operator==(const struct_b& lhs, const struct_b& rhs) -{ +bool operator==(const struct_b& lhs, const struct_b& rhs) { return lhs.a == rhs.a && lhs.z == rhs.z && lhs.ints == rhs.ints; } -bool operator!=(const struct_b& lhs, const struct_b& rhs) -{ +bool operator!=(const struct_b& lhs, const struct_b& rhs) { return !(lhs == rhs); } -struct struct_c -{ - std::map strings; +typedef std::map strmap; + +struct struct_c { + strmap strings; std::set ints; }; -bool operator==(const struct_c& lhs, const struct_c& rhs) -{ +bool operator==(const struct_c& lhs, const struct_c& rhs) { return lhs.strings == rhs.strings && lhs.ints == rhs.ints; } -bool operator!=(const struct_c& lhs, const struct_c& rhs) -{ +bool operator!=(const struct_c& lhs, const struct_c& rhs) { return !(lhs == rhs); } static const char* msg1str = u8R"__(@<> ( { @i32 ( 42 ), @str ( "Hello \"World\"!" ) } ))__"; -size_t test__serialization() -{ +size_t test__serialization() { CPPA_TEST(test__serialization); auto oarr = new detail::object_array; @@ -120,23 +112,19 @@ size_t test__serialization() oarr->push_back(object::from("foo" )); any_tuple atuple1(oarr); - try - { + try { auto opt = tuple_cast(atuple1); CPPA_CHECK(opt.valid()); - if (opt) - { + if (opt) { auto& tup = *opt; CPPA_CHECK_EQUAL(tup.size(), static_cast(2)); CPPA_CHECK_EQUAL(get<0>(tup), static_cast(42)); CPPA_CHECK_EQUAL(get<1>(tup), "foo"); } } - catch (std::exception& e) - { + catch (std::exception& e) { CPPA_ERROR("exception: " << e.what()); } - { any_tuple ttup = make_cow_tuple(1, 2, actor_ptr(self)); binary_serializer bs; @@ -146,7 +134,6 @@ size_t test__serialization() uniform_typeid()->deserialize(&ttup2, &bd); CPPA_CHECK(ttup == ttup2); } - { // serialize b1 to buf binary_serializer bs; @@ -155,29 +142,24 @@ size_t test__serialization() binary_deserializer bd(bs.data(), bs.size()); any_tuple atuple2; uniform_typeid()->deserialize(&atuple2, &bd); - try - { + try { auto opt = tuple_cast(atuple2); CPPA_CHECK(opt.valid()); - if (opt.valid()) - { + if (opt.valid()) { auto& tup = *opt; CPPA_CHECK_EQUAL(tup.size(), 2); CPPA_CHECK_EQUAL(get<0>(tup), 42); CPPA_CHECK_EQUAL(get<1>(tup), "foo"); } } - catch (std::exception& e) - { + catch (std::exception& e) { CPPA_ERROR("exception: " << e.what()); } } - { any_tuple msg1 = cppa::make_cow_tuple(42, std::string("Hello \"World\"!")); auto msg1_tostring = to_string(msg1); - if (msg1str != msg1_tostring) - { + if (msg1str != msg1_tostring) { CPPA_ERROR("msg1str != to_string(msg1)"); cerr << "to_string(msg1) = " << msg1_tostring << endl; } @@ -188,15 +170,13 @@ size_t test__serialization() bd >> obj1; object obj2 = from_string(to_string(msg1)); CPPA_CHECK(obj1 == obj2); - if (typeid(any_tuple) == *(obj1.type()) && obj2.type() == obj1.type()) - { + if (typeid(any_tuple) == *(obj1.type()) && obj2.type() == obj1.type()) { auto& content1 = get(obj1); auto& content2 = get(obj2); auto opt1 = tuple_cast(content1); auto opt2 = tuple_cast(content2); CPPA_CHECK(opt1.valid() && opt2.valid()); - if (opt1.valid() && opt2.valid()) - { + if (opt1.valid() && opt2.valid()) { auto& tup1 = *opt1; auto& tup2 = *opt2; CPPA_CHECK_EQUAL(tup1.size(), 2); @@ -207,8 +187,7 @@ size_t test__serialization() CPPA_CHECK_EQUAL(get<1>(tup2), "Hello \"World\"!"); } } - else - { + else { CPPA_ERROR("obj.type() != typeid(message)"); } } @@ -218,20 +197,17 @@ size_t test__serialization() CPPA_CHECK((is_iterable::value) == false); CPPA_CHECK((is_iterable>::value) == true); CPPA_CHECK((is_iterable>::value) == true); - // test meta_object implementation for primitive types - { + { // test meta_object implementation for primitive types auto meta_int = uniform_typeid(); CPPA_CHECK(meta_int != nullptr); - if (meta_int) - { + if (meta_int) { auto o = meta_int->create(); get_ref(o) = 42; auto str = to_string(get(o)); CPPA_CHECK_EQUAL(str, "@u32 ( 42 )"); } } - // test serializers / deserializers with struct_b - { + { // test serializers / deserializers with struct_b // get meta object for struct_b announce(compound_member(&struct_b::a, &struct_a::x, @@ -239,15 +215,14 @@ size_t test__serialization() &struct_b::z, &struct_b::ints); // testees - struct_b b1 = { { 1, 2 }, 3, { 4, 5, 6, 7, 8, 9, 10 } }; + struct_b b1 = { { 1, 2 }, 3, std::list{ 4, 5, 6, 7, 8, 9, 10 } }; struct_b b2; struct_b b3; // expected result of to_string(&b1, meta_b) auto b1str = "struct_b ( struct_a ( 1, 2 ), 3, " "{ 4, 5, 6, 7, 8, 9, 10 } )"; // verify - CPPA_CHECK_EQUAL((to_string(b1)), b1str); - { + CPPA_CHECK_EQUAL((to_string(b1)), b1str); { // serialize b1 to buf binary_serializer bs; bs << b1; @@ -261,22 +236,19 @@ size_t test__serialization() // verify result of serialization / deserialization CPPA_CHECK(b1 == b2); CPPA_CHECK_EQUAL(to_string(b2), b1str); - // deserialize b3 from string - { + { // deserialize b3 from string object res = from_string(b1str); CPPA_CHECK_EQUAL(res.type()->name(), "struct_b"); b3 = get(res); } CPPA_CHECK(b1 == b3); } - // test serializers / deserializers with struct_c - { + { // test serializers / deserializers with struct_c // get meta type of struct_c and "announce" announce(&struct_c::strings, &struct_c::ints); // testees - struct_c c1 = { { { "abc", u"cba" }, { "x", u"y" } }, { 9, 4, 5 } }; - struct_c c2; - { + struct_c c1{strmap{{"abc", u"cba" }, { "x", u"y" }}, std::set{9, 4, 5}}; + struct_c c2; { // serialize c1 to buf binary_serializer bs; bs << c1; diff --git a/unit_testing/test__spawn.cpp b/unit_testing/test__spawn.cpp index 79fafcd942..0906d0c620 100644 --- a/unit_testing/test__spawn.cpp +++ b/unit_testing/test__spawn.cpp @@ -1,3 +1,5 @@ +//#define CPPA_VERBOSE_CHECK + #include #include #include @@ -9,12 +11,13 @@ #include "cppa/on.hpp" #include "cppa/cppa.hpp" #include "cppa/actor.hpp" +#include "cppa/factory.hpp" #include "cppa/scheduler.hpp" -#include "cppa/fsm_actor.hpp" +#include "cppa/sb_actor.hpp" #include "cppa/to_string.hpp" #include "cppa/exit_reason.hpp" #include "cppa/event_based_actor.hpp" -#include "cppa/stacked_event_based_actor.hpp" +#include "cppa/util/callable_trait.hpp" using std::cerr; using std::cout; @@ -22,44 +25,62 @@ using std::endl; using namespace cppa; +#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 7) + +struct simple_mirror : sb_actor { + + behavior init_state = ( + others() >> []() { + self->last_sender() << self->last_dequeued(); + } + ); + +}; + +#else + +struct simple_mirror : event_based_actor { + + void init() { + become ( + others() >> []() { + self->last_sender() << self->last_dequeued(); + } + ); + } + +}; + +#endif + // GCC 4.7 supports non-static member initialization #if 0 //(__GNUC__ >= 4) && (__GNUC_MINOR__ >= 7) -struct event_testee : public fsm_actor -{ +struct event_testee : public fsm_actor { - behavior wait4string = - ( - on() >> [=]() - { + behavior wait4string = ( + on() >> [=]() { become(&wait4int); }, - on() >> [=]() - { + on() >> [=]() { reply("wait4string"); } ); - behavior wait4float = - ( - on() >> [=]() - { + behavior wait4float = ( + on() >> [=]() { become(&wait4string); }, - on() >> [=]() - { + on() >> [=]() { reply("wait4float"); } ); - behavior wait4int = - ( - on() >> [=]() - { + behavior wait4int = ( + on() >> [=]() { become(&wait4float); }, - on() >> [=]() - { + on() >> [=]() { reply("wait4int"); } ); @@ -70,10 +91,9 @@ struct event_testee : public fsm_actor #else -class event_testee : public fsm_actor -{ +class event_testee : public sb_actor { - friend class fsm_actor; + friend class sb_actor; behavior wait4string; behavior wait4float; @@ -83,40 +103,30 @@ class event_testee : public fsm_actor public: - event_testee() : init_state(wait4int) - { - wait4string = - ( - on() >> [=]() - { + event_testee() : init_state(wait4int) { + wait4string = ( + on() >> [=]() { become(&wait4int); }, - on() >> [=]() - { + on() >> [=]() { reply("wait4string"); } ); - wait4float = - ( - on() >> [=]() - { + wait4float = ( + on() >> [=]() { become(&wait4string); }, - on() >> [=]() - { + on() >> [=]() { reply("wait4float"); } ); - wait4int = - ( - on() >> [=]() - { + wait4int = ( + on() >> [=]() { become(&wait4float); }, - on() >> [=]() - { + on() >> [=]() { reply("wait4int"); } ); @@ -127,17 +137,12 @@ class event_testee : public fsm_actor #endif // quits after 5 timeouts -abstract_event_based_actor* event_testee2() -{ - struct impl : fsm_actor - { - behavior wait4timeout(int remaining) - { - return - ( - after(std::chrono::milliseconds(50)) >> [=]() - { - if (remaining == 1) become_void(); +actor_ptr spawn_event_testee2() { + struct impl : sb_actor { + behavior wait4timeout(int remaining) { + return ( + after(std::chrono::milliseconds(50)) >> [=]() { + if (remaining == 1) quit(); else become(wait4timeout(remaining - 1)); } ); @@ -147,86 +152,66 @@ abstract_event_based_actor* event_testee2() impl() : init_state(wait4timeout(5)) { } }; - return new impl; + return spawn(); } -struct chopstick : public fsm_actor -{ +struct chopstick : public sb_actor { - behavior taken_by(actor_ptr hakker) - { - return - ( - on() >> [=]() - { + behavior taken_by(actor_ptr hakker) { + return ( + on() >> [=]() { reply(atom("busy")); }, - on(atom("put"), hakker) >> [=]() - { + on(atom("put"), hakker) >> [=]() { become(&init_state); }, - on(atom("break")) >> [=]() - { - become_void(); + on(atom("break")) >> [=]() { + quit(); } ); } behavior init_state; - chopstick() - { - init_state = - ( - on(atom("take"), arg_match) >> [=](actor_ptr hakker) - { + chopstick() { + init_state = ( + on(atom("take"), arg_match) >> [=](actor_ptr hakker) { become(taken_by(hakker)); reply(atom("taken")); }, - on(atom("break")) >> [=]() - { - become_void(); + on(atom("break")) >> [=]() { + quit(); }, - others() >> [=]() - { + others() >> [=]() { } ); } }; -class testee_actor : public scheduled_actor -{ +class testee_actor { - void wait4string() - { + void wait4string() { bool string_received = false; - do_receive - ( - on() >> [&]() - { + do_receive ( + on() >> [&]() { string_received = true; }, - on() >> [&]() - { + on() >> [&]() { reply("wait4string"); } ) .until(gref(string_received)); } - void wait4float() - { + void wait4float() { bool float_received = false; - do_receive - ( - on() >> [&]() - { + do_receive ( + on() >> [&]() { float_received = true; wait4string(); }, - on() >> [&]() - { + on() >> [&]() { reply("wait4float"); } ) @@ -235,16 +220,12 @@ class testee_actor : public scheduled_actor public: - void act() - { - receive_loop - ( - on() >> [&]() - { + void operator()() { + receive_loop ( + on() >> [&]() { wait4float(); }, - on() >> [&]() - { + on() >> [&]() { reply("wait4int"); } ); @@ -253,22 +234,17 @@ class testee_actor : public scheduled_actor }; // receives one timeout and quits -void testee1() -{ - receive - ( +void testee1() { + receive ( after(std::chrono::milliseconds(10)) >> []() { } ); } -void testee2(actor_ptr other) -{ +void testee2(actor_ptr other) { self->link_to(other); send(other, std::uint32_t(1)); - receive_loop - ( - on() >> [](std::uint32_t sleep_time) - { + receive_loop ( + on() >> [](std::uint32_t sleep_time) { // "sleep" for sleep_time milliseconds receive(after(std::chrono::milliseconds(sleep_time)) >> []() {}); //reply(sleep_time * 2); @@ -276,17 +252,13 @@ void testee2(actor_ptr other) ); } -void testee3(actor_ptr parent) -{ - // test a future_send / delayed_reply based loop - future_send(self, std::chrono::milliseconds(50), atom("Poll")); +void testee3(actor_ptr parent) { + // test a delayed_send / delayed_reply based loop + delayed_send(self, std::chrono::milliseconds(50), atom("Poll")); int polls = 0; - receive_for(polls, 5) - ( - on(atom("Poll")) >> [&]() - { - if (polls < 4) - { + receive_for(polls, 5) ( + on(atom("Poll")) >> [&]() { + if (polls < 4) { delayed_reply(std::chrono::milliseconds(50), atom("Poll")); } send(parent, atom("Push"), polls); @@ -294,12 +266,18 @@ void testee3(actor_ptr parent) ); } +void echo_actor() { + receive ( + others() >> []() { + self->last_sender() << self->last_dequeued(); + } + ); +} + template -std::string behavior_test() -{ +std::string behavior_test(actor_ptr et) { std::string result; std::string testee_name = detail::to_uniform_name(typeid(Testee)); - auto et = spawn(new Testee); send(et, 1); send(et, 2); send(et, 3); @@ -310,24 +288,127 @@ std::string behavior_test() send(et, "hello again " + testee_name); send(et, "goodbye " + testee_name); send(et, atom("get_state")); - receive - ( - on_arg_match >> [&](const std::string& str) - { + receive ( + on_arg_match >> [&](const std::string& str) { result = str; }, - after(std::chrono::seconds(2)) >> [&]() - { + after(std::chrono::minutes(1)) >> [&]() { + //after(std::chrono::seconds(2)) >> [&]() { throw std::runtime_error(testee_name + " does not reply"); } ); - send(et, atom(":Exit"), exit_reason::user_defined); + send(et, atom("EXIT"), exit_reason::user_defined); await_all_others_done(); return result; } -size_t test__spawn() -{ +#ifdef __clang__ +class fixed_stack : public sb_actor { + + friend class sb_actor; + + size_t max_size; + + std::vector data; + + behavior full = ( + on(atom("push"), arg_match) >> [=](int) { }, + on(atom("pop")) >> [=]() { + reply(atom("ok"), data.back()); + data.pop_back(); + become(&filled); + } + ); + + behavior filled = ( + on(atom("push"), arg_match) >> [=](int what) { + data.push_back(what); + if (data.size() == max_size) + become(&full); + }, + on(atom("pop")) >> [=]() { + reply(atom("ok"), data.back()); + data.pop_back(); + if (data.empty()) + become(&empty); + } + ); + + behavior empty = ( + on(atom("push"), arg_match) >> [=](int what) { + data.push_back(what); + become(&filled); + }, + on(atom("pop")) >> [=]() { + reply(atom("failure")); + } + ); + + behavior& init_state = empty; + + public: + + fixed_stack(size_t max) : max_size(max) { } + +}; +#else +class fixed_stack : public sb_actor { + + friend class sb_actor; + + size_t max_size = 10; + + std::vector data; + + behavior full; + behavior filled; + behavior empty; + behavior& init_state; + + public: + + fixed_stack(size_t max) : max_size(max), init_state(empty) { + + full = ( + on(atom("push"), arg_match) >> [=](int) { }, + on(atom("pop")) >> [=]() { + reply(atom("ok"), data.back()); + data.pop_back(); + become(&filled); + } + ); + + filled = ( + on(atom("push"), arg_match) >> [=](int what) { + data.push_back(what); + if (data.size() == max_size) + become(&full); + }, + on(atom("pop")) >> [=]() { + reply(atom("ok"), data.back()); + data.pop_back(); + if (data.empty()) + become(&empty); + } + ); + + empty = ( + on(atom("push"), arg_match) >> [=](int what) { + data.push_back(what); + become(&filled); + }, + on(atom("pop")) >> [=]() { + reply(atom("failure")); + } + ); + + } + +}; +#endif + +size_t test__spawn() { + using std::string; CPPA_TEST(test__spawn); CPPA_IF_VERBOSE(cout << "test send() ... " << std::flush); @@ -335,8 +416,35 @@ size_t test__spawn() receive(on(1, 2, 3) >> []() { }); CPPA_IF_VERBOSE(cout << "ok" << endl); - CPPA_IF_VERBOSE(cout << "test future_send() ... " << std::flush); - future_send(self, std::chrono::seconds(1), 1, 2, 3); + CPPA_IF_VERBOSE(cout << "test receive with zero timeout ... " << std::flush); + receive ( + others() >> []() { + cerr << "WTF?? received: " << to_string(self->last_dequeued()) + << endl; + }, + after(std::chrono::seconds(0)) >> []() { + // mailbox empty + } + ); + CPPA_IF_VERBOSE(cout << "ok" << endl); + + CPPA_IF_VERBOSE(cout << "test echo actor ... " << std::flush); + auto mecho = spawn(echo_actor); + send(mecho, "hello echo"); + receive(on("hello echo") >> []() { }); + await_all_others_done(); + CPPA_IF_VERBOSE(cout << "ok" << endl); + + auto mirror = spawn(); + + CPPA_IF_VERBOSE(cout << "test mirror ... " << std::flush); + send(mirror, "hello mirror"); + receive(on("hello mirror") >> []() { }); + send(mirror, atom("EXIT"), exit_reason::user_defined); + CPPA_IF_VERBOSE(cout << "ok" << endl); + + CPPA_IF_VERBOSE(cout << "test delayed_send() ... " << std::flush); + delayed_send(self, std::chrono::seconds(1), 1, 2, 3); receive(on(1, 2, 3) >> []() { }); CPPA_IF_VERBOSE(cout << "ok" << endl); @@ -350,17 +458,15 @@ size_t test__spawn() CPPA_IF_VERBOSE(cout << "ok" << endl); CPPA_IF_VERBOSE(cout << "event_testee2 ... " << std::flush); - spawn(event_testee2()); + spawn_event_testee2(); await_all_others_done(); CPPA_IF_VERBOSE(cout << "ok" << endl); CPPA_IF_VERBOSE(cout << "chopstick ... " << std::flush); - auto cstk = spawn(new chopstick); + auto cstk = spawn(); send(cstk, atom("take"), self); - receive - ( - on(atom("taken")) >> [&]() - { + receive ( + on(atom("taken")) >> [&]() { send(cstk, atom("put"), self); send(cstk, atom("break")); } @@ -368,71 +474,218 @@ size_t test__spawn() await_all_others_done(); CPPA_IF_VERBOSE(cout << "ok" << endl); - CPPA_CHECK_EQUAL(behavior_test(), "wait4int"); - CPPA_CHECK_EQUAL(behavior_test(), "wait4int"); + CPPA_IF_VERBOSE(cout << "test event-based factory ... " << std::flush); + auto factory = factory::event_based([&](int* i, float*, std::string*) { + self->become ( + on(atom("get_int")) >> [i]() { + reply(*i); + }, + on(atom("set_int"), arg_match) >> [i](int new_value) { + *i = new_value; + }, + on(atom("done")) >> []() { + self->quit(); + } + ); + }); + auto foobaz_actor = factory.spawn(23); + send(foobaz_actor, atom("get_int")); + send(foobaz_actor, atom("set_int"), 42); + send(foobaz_actor, atom("get_int")); + send(foobaz_actor, atom("done")); + receive ( + on_arg_match >> [&](int value) { + CPPA_CHECK_EQUAL(23, value); + } + ); + receive ( + on_arg_match >> [&](int value) { + CPPA_CHECK_EQUAL(42, value); + } + ); + await_all_others_done(); + CPPA_IF_VERBOSE(cout << "ok" << endl); - // create 20,000 actors linked to one single actor - // and kill them all through killing the link - auto my_link = spawn(new event_testee); - for (int i = 0; i < 20000; ++i) + CPPA_IF_VERBOSE(cout << "test fixed_stack ... " << std::flush); + auto st = spawn(10); + // push 20 values + for (int i = 0; i < 20; ++i) send(st, atom("push"), i); + // pop 20 times + for (int i = 0; i < 20; ++i) send(st, atom("pop")); + // expect 10 failure messages + { + int i = 0; + receive_for(i, 10) ( + on(atom("failure")) >> []() { } + ); + } + // expect 10 {'ok', value} messages { - link(my_link, spawn(new event_testee)); + std::vector values; + int i = 0; + receive_for(i, 10) ( + on(atom("ok"), arg_match) >> [&](int value) { + values.push_back(value); + } + ); + std::vector expected{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + CPPA_CHECK(values == expected); } - send(my_link, atom(":Exit"), exit_reason::user_defined); + // terminate st + send(st, atom("EXIT"), exit_reason::user_defined); await_all_others_done(); + CPPA_IF_VERBOSE(cout << "ok" << endl); - auto report_unexpected = [&]() - { - cerr << "unexpected message: " - << to_string(self->last_dequeued()) << endl; - CPPA_CHECK(false); - }; + int zombie_init_called = 0; + int zombie_on_exit_called = 0; + factory::event_based([&]() { + ++zombie_init_called; + }, + [&]() { + ++zombie_on_exit_called; + }) + .spawn(); + CPPA_CHECK_EQUAL(1, zombie_init_called); + CPPA_CHECK_EQUAL(1, zombie_on_exit_called); + factory::event_based([&](int* i) { + CPPA_CHECK_EQUAL(42, *i); + ++zombie_init_called; + }, + [&](int* i) { + CPPA_CHECK_EQUAL(42, *i); + ++zombie_on_exit_called; + }) + .spawn(42); + CPPA_CHECK_EQUAL(2, zombie_init_called); + CPPA_CHECK_EQUAL(2, zombie_on_exit_called); + factory::event_based([&](int* i) { + CPPA_CHECK_EQUAL(23, *i); + ++zombie_init_called; + }, + [&]() { + ++zombie_on_exit_called; + }) + .spawn(23); + CPPA_CHECK_EQUAL(3, zombie_init_called); + CPPA_CHECK_EQUAL(3, zombie_on_exit_called); + + auto f = factory::event_based([](std::string* name) { + self->become ( + on(atom("get_name")) >> [name]() { + reply(atom("name"), *name); + } + ); + }); + auto a1 = f.spawn("alice"); + auto a2 = f.spawn("bob"); + send(a1, atom("get_name")); + receive ( + on(atom("name"), arg_match) >> [&](const std::string& name) { + CPPA_CHECK_EQUAL("alice", name); + } + ); + send(a2, atom("get_name")); + receive ( + on(atom("name"), arg_match) >> [&](const std::string& name) { + CPPA_CHECK_EQUAL("bob", name); + } + ); + auto kill_msg = make_any_tuple(atom("EXIT"), exit_reason::user_defined); + a1 << kill_msg; + a2 << kill_msg; + await_all_others_done(); + + auto res1 = behavior_test(spawn(testee_actor{})); + CPPA_CHECK_EQUAL(res1, "wait4int"); + CPPA_CHECK_EQUAL(behavior_test(spawn()), "wait4int"); + + // create 20,000 actors linked to one single actor + // and kill them all through killing the link + auto twenty_thousand = spawn([]() { + for (int i = 0; i < 20000; ++i) { + self->link_to(spawn()); + } + receive_loop ( + others() >> []() { + cout << "wtf? => " << to_string(self->last_dequeued()) << endl; + } + ); + }); + send(twenty_thousand, atom("EXIT"), exit_reason::user_defined); + await_all_others_done(); self->trap_exit(true); - auto pong_actor = spawn(pong, spawn(ping)); - monitor(pong_actor); + auto ping_actor = spawn(ping, 10); + auto pong_actor = spawn(pong, ping_actor); + self->monitor(pong_actor); + self->monitor(ping_actor); self->link_to(pong_actor); int i = 0; int flags = 0; - future_send(self, std::chrono::seconds(1), atom("FooBar")); - // wait for :Down and :Exit messages of pong - receive_for(i, 3) - ( - on() >> [&](std::uint32_t reason) - { + delayed_send(self, std::chrono::seconds(1), atom("FooBar")); + // wait for DOWN and EXIT messages of pong + receive_for(i, 4) ( + on() >> [&](std::uint32_t reason) { CPPA_CHECK_EQUAL(reason, exit_reason::user_defined); - //CPPA_CHECK_EQUAL(who, pong_actor); + CPPA_CHECK(self->last_sender() == pong_actor); flags |= 0x01; }, - on() >> [&](const actor_ptr& who, - std::uint32_t reason) - { - CPPA_CHECK_EQUAL(reason, exit_reason::user_defined); - if (who == pong_actor) - { + on() >> [&](std::uint32_t reason) { + auto who = self->last_sender(); + if (who == pong_actor) { flags |= 0x02; + CPPA_CHECK_EQUAL(reason, exit_reason::user_defined); + } + else if (who == ping_actor) { + flags |= 0x04; + CPPA_CHECK_EQUAL(reason, exit_reason::normal); } }, - on() >> [&]() - { - flags |= 0x04; + on() >> [&]() { + flags |= 0x08; }, - others() >> [&]() - { - report_unexpected(); - CPPA_CHECK(false); + others() >> [&]() { + CPPA_ERROR("unexpected message: " << to_string(self->last_dequeued())); }, - after(std::chrono::seconds(5)) >> [&]() - { - cout << "!!! TIMEOUT !!!" << endl; - CPPA_CHECK(false); + after(std::chrono::seconds(5)) >> [&]() { + CPPA_ERROR("timeout in file " << __FILE__ << " in line " << __LINE__); } ); // wait for termination of all spawned actors await_all_others_done(); - CPPA_CHECK_EQUAL(flags, 0x07); + CPPA_CHECK_EQUAL(0x0F, flags); // verify pong messages - CPPA_CHECK_EQUAL(pongs(), 5); - - await_all_others_done(); + CPPA_CHECK_EQUAL(10, pongs()); return CPPA_TEST_RESULT; + + /****** TODO + + int add_fun(int, int); + int sub_fun(int, int); + + ... + + class math { + public: + int add_fun(int, int); + int sub_fun(int, int); + }; + + ... + + auto factory1 = actor_prototype ( + on().reply_with(atom("result"), add_fun), + on().reply_with(atom("result"), add_fun) + ); + auto a1 = factory1.spawn(); + + ... + + auto factory2 = actor_facade ( + on().reply_with(atom("result"), &math::add_fun), <-- possible? + on().reply_with(atom("result"), &math::sub_fun) + ); + auto a2 = factory2.spawn(); + + */ + } diff --git a/unit_testing/test__tuple.cpp b/unit_testing/test__tuple.cpp index c15678428c..8c7a300f34 100644 --- a/unit_testing/test__tuple.cpp +++ b/unit_testing/test__tuple.cpp @@ -26,7 +26,6 @@ #include "cppa/util/deduce_ref_type.hpp" #include "cppa/detail/matches.hpp" -#include "cppa/detail/invokable.hpp" #include "cppa/detail/projection.hpp" #include "cppa/detail/types_array.hpp" #include "cppa/detail/value_guard.hpp" @@ -45,17 +44,14 @@ using namespace cppa::detail; #define VERBOSE(LineOfCode) cout << #LineOfCode << " = " << (LineOfCode) << endl -std::string int2str(int i) -{ +std::string int2str(int i) { return std::to_string(i); } -option str2int(const std::string& str) -{ +option str2int(const std::string& str) { char* endptr = nullptr; int result = static_cast(strtol(str.c_str(), &endptr, 10)); - if (endptr != nullptr && *endptr == '\0') - { + if (endptr != nullptr && *endptr == '\0') { return result; } return {}; @@ -89,8 +85,7 @@ typedef util::type_list< template -struct is_same_ : std::is_same -{ +struct is_same_ : std::is_same { }; #define CPPA_CHECK_INVOKED(FunName, Args) \ @@ -103,8 +98,7 @@ struct is_same_ : std::is_same CPPA_ERROR(#FunName " erroneously invoked"); \ } invoked = "" -size_t test__tuple() -{ +size_t test__tuple() { CPPA_TEST(test__tuple); using namespace cppa::placeholders; @@ -145,8 +139,7 @@ size_t test__tuple() CPPA_CHECK_NOT_INVOKED(f03, (0, 0)); CPPA_CHECK_INVOKED(f03, (42, 42)); - auto f04 = on(42, int2str).when(_x2 == "42") >> [&](std::string& str) - { + auto f04 = on(42, int2str).when(_x2 == "42") >> [&](std::string& str) { CPPA_CHECK_EQUAL("42", str); invoked = "f04"; }; @@ -202,8 +195,7 @@ size_t test__tuple() // no longer the same data CPPA_CHECK_NOT_EQUAL(f09_any_val.at(0), f09_any_val_copy.at(0)); - auto f10 = - ( + auto f10 = ( on().when(_x1 < 10) >> [&]() { invoked = "f10.0"; }, on() >> [&]() { invoked = "f10.1"; }, on() >> [&](std::string&) { invoked = "f10.2"; } @@ -223,8 +215,7 @@ size_t test__tuple() //CPPA_CHECK(f10(const static_cast(foobar), "b", "c")); int f11_fun = 0; - auto f11 = - ( + auto f11 = ( on().when(_x1 == 1) >> [&]() { f11_fun = 1; }, on().when(_x1 == 2) >> [&]() { f11_fun = 2; }, on().when(_x1 == 3) >> [&]() { f11_fun = 3; }, @@ -251,10 +242,8 @@ size_t test__tuple() CPPA_CHECK(f11("10")); CPPA_CHECK_EQUAL(10, f11_fun); - auto f12 = - ( - on().when(_x1 < _x2) >> [&](int a, int b) - { + auto f12 = ( + on().when(_x1 < _x2) >> [&](int a, int b) { CPPA_CHECK_EQUAL(1, a); CPPA_CHECK_EQUAL(5, b); invoked = "f12"; @@ -263,26 +252,22 @@ size_t test__tuple() CPPA_CHECK_INVOKED(f12, (1, 2, 3, 4, 5)); int f13_fun = 0; - auto f13 = - ( - on().when(_x1 < _x3 && _x2.starts_with("-")) >> [&](int a, const std::string& str, int b) - { + auto f13 = ( + on().when(_x1 < _x3 && _x2.starts_with("-")) >> [&](int a, const std::string& str, int b) { CPPA_CHECK_EQUAL("-h", str); CPPA_CHECK_EQUAL(1, a); CPPA_CHECK_EQUAL(10, b); f13_fun = 1; invoked = "f13"; }, - on() >> [&](const std::string& str, int a, float b) - { + on() >> [&](const std::string& str, int a, float b) { CPPA_CHECK_EQUAL("h", str); CPPA_CHECK_EQUAL(12, a); CPPA_CHECK_EQUAL(1.f, b); f13_fun = 2; invoked = "f13"; }, - on().when(_x1 * 2 == _x2) >> [&](float a, float b) - { + on().when(_x1 * 2 == _x2) >> [&](float a, float b) { CPPA_CHECK_EQUAL(1.f, a); CPPA_CHECK_EQUAL(2.f, b); f13_fun = 3; @@ -300,16 +285,14 @@ size_t test__tuple() return CPPA_TEST_RESULT; - auto old_pf = - ( + auto old_pf = ( on(42) >> []() { }, on("abc") >> []() { }, on() >> []() { }, on() >> []() { } ); - auto new_pf = - ( + auto new_pf = ( on(42) >> []() { }, on(std::string("abc")) >> []() { }, on() >> []() { }, @@ -339,84 +322,69 @@ size_t test__tuple() int dummy_counter = 0; - cout << "time for for " << numInvokes << " guards(1)*" << endl; - { + cout << "time for for " << numInvokes << " guards(1)*" << endl; { boost::progress_timer t0; for (size_t i = 0; i < numInvokes; ++i) if (guard1(1, 2, *p3))//const_cast(three))) ++dummy_counter; } - cout << "time for for " << numInvokes << " guards(1)*" << endl; - { + cout << "time for for " << numInvokes << " guards(1)*" << endl; { boost::progress_timer t0; for (size_t i = 0; i < numInvokes; ++i) if (guard1(get_ref<0>(xvals), get_ref<1>(xvals), get_ref<2>(xvals))) ++dummy_counter; } - cout << "time for for " << numInvokes << " guards(1)" << endl; - { + cout << "time for for " << numInvokes << " guards(1)" << endl; { boost::progress_timer t0; for (size_t i = 0; i < numInvokes; ++i) if (util::unchecked_apply_tuple(guard1, xvals)) ++dummy_counter; } - cout << "time for for " << numInvokes << " guards(2)" << endl; - { + cout << "time for for " << numInvokes << " guards(2)" << endl; { boost::progress_timer t0; for (size_t i = 0; i < numInvokes; ++i) if (util::unchecked_apply_tuple(guard2, xvals)) ++dummy_counter; } - cout << "time for for " << numInvokes << " guards(3)" << endl; - { + cout << "time for for " << numInvokes << " guards(3)" << endl; { boost::progress_timer t0; for (size_t i = 0; i < numInvokes; ++i) if (util::unchecked_apply_tuple(guard3, xvals)) ++dummy_counter; } - cout << "time for " << numInvokes << " equal if-statements" << endl; - { + cout << "time for " << numInvokes << " equal if-statements" << endl; { boost::progress_timer t0; - for (size_t i = 0; i < (numInvokes / sizeof(testee)); ++i) - { - if (get<0>(xvals) + get<1>(xvals) == 3 && get<2>(xvals) == "3") - { + for (size_t i = 0; i < (numInvokes / sizeof(testee)); ++i) { + if (get<0>(xvals) + get<1>(xvals) == 3 && get<2>(xvals) == "3") { ++dummy_counter; } } } */ - cout << "old partial function implementation for " << numInvokes << " matches" << endl; - { + cout << "old partial function implementation for " << numInvokes << " matches" << endl; { boost::progress_timer t0; - for (size_t i = 0; i < (numInvokes / sizeof(testee)); ++i) - { + for (size_t i = 0; i < (numInvokes / sizeof(testee)); ++i) { for (auto& x : testee) { old_pf(x); } } } - cout << "new partial function implementation for " << numInvokes << " matches" << endl; - { + cout << "new partial function implementation for " << numInvokes << " matches" << endl; { boost::progress_timer t0; - for (size_t i = 0; i < (numInvokes / sizeof(testee)); ++i) - { + for (size_t i = 0; i < (numInvokes / sizeof(testee)); ++i) { for (auto& x : testee) { new_pf.invoke(x); } } } - cout << "old partial function with on() inside loop" << endl; - { + cout << "old partial function with on() inside loop" << endl; { boost::progress_timer t0; - for (size_t i = 0; i < (numInvokes / sizeof(testee)); ++i) - { - auto tmp = - ( + for (size_t i = 0; i < (numInvokes / sizeof(testee)); ++i) { + auto tmp = ( on(42) >> []() { }, on("abc") >> []() { }, on() >> []() { }, @@ -426,13 +394,10 @@ size_t test__tuple() } } - cout << "new partial function with on() inside loop" << endl; - { + cout << "new partial function with on() inside loop" << endl; { boost::progress_timer t0; - for (size_t i = 0; i < (numInvokes / sizeof(testee)); ++i) - { - auto tmp = - ( + for (size_t i = 0; i < (numInvokes / sizeof(testee)); ++i) { + auto tmp = ( on(42) >> []() { }, on(std::string("abc")) >> []() { }, on() >> []() { }, @@ -501,8 +466,7 @@ size_t test__tuple() VERBOSE(f0.invoke(*i2.vals()->type_token(), i2.vals()->impl_type(), i2.vals()->native_data(), *(i2.vals()))); VERBOSE(f1.invoke(*i2.vals()->type_token(), i2.vals()->impl_type(), i2.vals()->native_data(), *(i2.vals()))); - any_tuple dt1; - { + any_tuple dt1; { auto oarr = new detail::object_array; oarr->push_back(object::from(1)); oarr->push_back(object::from(2)); @@ -533,8 +497,7 @@ size_t test__tuple() CPPA_CHECK( at0.size() == 2 && at0.at(0) == &get<0>(t0) && at0.at(1) == &get<1>(t0)); - if (v0opt) - { + if (v0opt) { auto& v0 = *v0opt; CPPA_CHECK((std::is_same&>::value)); CPPA_CHECK((std::is_same(v0)), const std::string&>::value)); @@ -553,13 +516,11 @@ size_t test__tuple() CPPA_CHECK(lhs == rhs); CPPA_CHECK(rhs == lhs); } - any_tuple at1 = make_cow_tuple("one", 2, 3.f, 4.0); - { + any_tuple at1 = make_cow_tuple("one", 2, 3.f, 4.0); { // perfect match auto opt0 = tuple_cast(at1); CPPA_CHECK(opt0); - if (opt0) - { + if (opt0) { CPPA_CHECK((*opt0 == make_cow_tuple("one", 2, 3.f, 4.0))); CPPA_CHECK_EQUAL(&get<0>(*opt0), at1.at(0)); CPPA_CHECK_EQUAL(&get<1>(*opt0), at1.at(1)); @@ -569,24 +530,21 @@ size_t test__tuple() // leading wildcard auto opt1 = tuple_cast(at1); CPPA_CHECK(opt1); - if (opt1) - { + if (opt1) { CPPA_CHECK_EQUAL(get<0>(*opt1), 4.0); CPPA_CHECK_EQUAL(&get<0>(*opt1), at1.at(3)); } // trailing wildcard auto opt2 = tuple_cast(at1); CPPA_CHECK(opt2); - if (opt2) - { + if (opt2) { CPPA_CHECK_EQUAL(get<0>(*opt2), "one"); CPPA_CHECK_EQUAL(&get<0>(*opt2), at1.at(0)); } // wildcard in between auto opt3 = tuple_cast(at1); CPPA_CHECK(opt3); - if (opt3) - { + if (opt3) { CPPA_CHECK((*opt3 == make_cow_tuple("one", 4.0))); CPPA_CHECK_EQUAL(get<0>(*opt3), "one"); CPPA_CHECK_EQUAL(get<1>(*opt3), 4.0); diff --git a/unit_testing/test__type_list.cpp b/unit_testing/test__type_list.cpp index aef326425d..c47aac0387 100644 --- a/unit_testing/test__type_list.cpp +++ b/unit_testing/test__type_list.cpp @@ -15,8 +15,7 @@ using std::is_same; using namespace cppa::util; -size_t test__type_list() -{ +size_t test__type_list() { CPPA_TEST(test__type_list); diff --git a/unit_testing/test__uniform_type.cpp b/unit_testing/test__uniform_type.cpp index d62f93f998..a9b3e7da68 100644 --- a/unit_testing/test__uniform_type.cpp +++ b/unit_testing/test__uniform_type.cpp @@ -15,10 +15,13 @@ #include "test.hpp" +#include "cppa/atom.hpp" #include "cppa/announce.hpp" #include "cppa/serializer.hpp" #include "cppa/deserializer.hpp" #include "cppa/uniform_type_info.hpp" +#include "cppa/detail/types_array.hpp" +#include "cppa/detail/addressed_message.hpp" #include "cppa/util/callable_trait.hpp" @@ -27,28 +30,20 @@ using std::endl; namespace { -struct foo -{ +struct foo { int value; explicit foo(int val = 0) : value(val) { } }; -inline bool operator==(const foo& lhs, const foo& rhs) -{ +inline bool operator==(const foo& lhs, const foo& rhs) { return lhs.value == rhs.value; } -inline bool operator!=(const foo& lhs, const foo& rhs) -{ - return !(lhs == rhs); -} - } // namespace using namespace cppa; -size_t test__uniform_type() -{ +size_t test__uniform_type() { CPPA_TEST(test__uniform_type); bool announce1 = announce(&foo::value); bool announce2 = announce(&foo::value); @@ -72,8 +67,7 @@ size_t test__uniform_type() CPPA_CHECK_EQUAL(successful_announces, 1); // these types (and only those) are present if // the uniform_type_info implementation is correct - std::set expected = - { + std::set expected = { "@_::foo", // ::foo "@i8", "@i16", "@i32", "@i64", // signed integer names "@u8", "@u16", "@u32", "@u64", // unsigned integer names @@ -81,44 +75,109 @@ size_t test__uniform_type() "float", "double", // floating points "@0", // cppa::util::void_type // default announced cppa types - "@atom", // cppa::atom_value - "@<>", // cppa::any_tuple - "@msg", // cppa::message - "@actor", // cppa::actor_ptr - "@group", // cppa::group_ptr - "@channel", // cppa::channel_ptr + "@atom", // cppa::atom_value + "@<>", // cppa::any_tuple + "@msg", // cppa::detail::addressed_message + "@actor", // cppa::actor_ptr + "@group", // cppa::group_ptr + "@channel", // cppa::channel_ptr + "@process_info", // cppa::intrusive_ptr "cppa::util::duration" }; // holds the type names we see at runtime std::set found; // fetch all available type names auto types = uniform_type_info::instances(); - for (uniform_type_info* tinfo : types) - { + for (auto tinfo : types) { found.insert(tinfo->name()); } // compare the two sets CPPA_CHECK_EQUAL(expected.size(), found.size()); bool expected_equals_found = false; - if (expected.size() == found.size()) - { + if (expected.size() == found.size()) { expected_equals_found = std::equal(found.begin(), found.end(), expected.begin()); CPPA_CHECK(expected_equals_found); } - if (!expected_equals_found) - { + if (!expected_equals_found) { cout << "found:" << endl; - for (const std::string& tname : found) - { + for (const std::string& tname : found) { cout << " - " << tname << endl; } cout << "expected: " << endl; - for (const std::string& tname : expected) - { + for (const std::string& tname : expected) { cout << " - " << tname << endl; } } + + // check if static types are identical to runtime types + auto& sarr = detail::static_types_array< + std::int8_t, std::int16_t, std::int32_t, std::int64_t, + std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t, + std::string, std::u16string, std::u32string, + float, double, + atom_value, any_tuple, detail::addressed_message, + actor_ptr, group_ptr, + channel_ptr, intrusive_ptr + >::arr; + + std::vector rarr{ + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid(), + uniform_typeid >() + }; + + CPPA_CHECK_EQUAL(true, sarr.is_pure()); + + for (size_t i = 0; i < sarr.size; ++i) { + CPPA_CHECK_EQUAL(sarr[i]->name(), rarr[i]->name()); + CPPA_CHECK(sarr[i] == rarr[i]); + } + + auto& arr0 = detail::static_types_array::arr; + CPPA_CHECK(arr0.is_pure()); + CPPA_CHECK(arr0[0] == uniform_typeid()); + CPPA_CHECK(arr0[0] == uniform_type_info::from("@atom")); + CPPA_CHECK(arr0[1] == uniform_typeid()); + CPPA_CHECK(arr0[1] == uniform_type_info::from("@u32")); + CPPA_CHECK(uniform_type_info::from("@u32") == uniform_typeid()); + + auto& arr1 = detail::static_types_array::arr; + CPPA_CHECK(arr1[0] == uniform_typeid()); + CPPA_CHECK(arr1[0] == uniform_type_info::from("@str")); + CPPA_CHECK(arr1[1] == uniform_typeid()); + CPPA_CHECK(arr1[1] == uniform_type_info::from("@i8")); + + auto& arr2 = detail::static_types_array::arr; + CPPA_CHECK(arr2[0] == uniform_typeid()); + CPPA_CHECK(arr2[0] == uniform_type_info::from("@u8")); + CPPA_CHECK(arr2[1] == uniform_typeid()); + CPPA_CHECK(arr2[1] == uniform_type_info::from("@i8")); + + auto& arr3 = detail::static_types_array::arr; + CPPA_CHECK(arr3[0] == uniform_typeid()); + CPPA_CHECK(arr3[0] == uniform_type_info::from("@atom")); + CPPA_CHECK(arr3[1] == uniform_typeid()); + CPPA_CHECK(arr3[1] == uniform_type_info::from("@u16")); + CPPA_CHECK(uniform_type_info::from("@u16") == uniform_typeid()); + return CPPA_TEST_RESULT; } diff --git a/unit_testing/test__yield_interface.cpp b/unit_testing/test__yield_interface.cpp index 127918a45e..f6a8e5756b 100644 --- a/unit_testing/test__yield_interface.cpp +++ b/unit_testing/test__yield_interface.cpp @@ -8,16 +8,13 @@ #include "cppa/util/fiber.hpp" #include "cppa/detail/yield_interface.hpp" -using namespace cppa; -using namespace cppa::util; -using namespace cppa::detail; +#include + -namespace { +namespace cppa { namespace detail { -std::ostream& operator<<(std::ostream& o, yield_state ys) -{ - switch (ys) - { +std::ostream& operator<<(std::ostream& o, yield_state ys) { + switch (ys) { case yield_state::invalid: return (o << "yield_state::invalid"); case yield_state::ready: @@ -31,26 +28,25 @@ std::ostream& operator<<(std::ostream& o, yield_state ys) } } -} // namespace +} } // namespace cppa::detail + +using namespace cppa; +using namespace cppa::util; +using namespace cppa::detail; -struct pseudo_worker -{ +struct pseudo_worker { int m_count; bool m_blocked; pseudo_worker() : m_count(0), m_blocked(true) { } - void operator()() - { - for (;;) - { - if (m_blocked) - { + void operator()() { + for (;;) { + if (m_blocked) { yield(yield_state::blocked); } - else - { + else { ++m_count; yield(m_count < 10 ? yield_state::ready : yield_state::done); } @@ -59,13 +55,10 @@ struct pseudo_worker }; -void coroutine(void* worker) -{ - (*reinterpret_cast(worker))(); +void coroutine(void* worker) { (*reinterpret_cast(worker))(); } -size_t test__yield_interface() -{ +size_t test__yield_interface() { CPPA_TEST(test__yield_interface); # ifdef CPPA_DISABLE_CONTEXT_SWITCHING cout << "WARNING: context switching was explicitly disabled using " @@ -77,16 +70,15 @@ size_t test__yield_interface() fiber fcoroutine(coroutine, &worker); yield_state ys; int i = 0; - do - { + do { if (i == 2) worker.m_blocked = false; ys = call(&fcoroutine, &fself); ++i; } while (ys != yield_state::done && i < 12); - CPPA_CHECK_EQUAL(ys, yield_state::done); - CPPA_CHECK_EQUAL(worker.m_count, 10); - CPPA_CHECK_EQUAL(i, 12); + CPPA_CHECK_EQUAL(yield_state::done, ys); + CPPA_CHECK_EQUAL(10, worker.m_count); + CPPA_CHECK_EQUAL(12, i); # endif return CPPA_TEST_RESULT; } diff --git a/variadic_templates_test.cpp b/variadic_templates_test.cpp deleted file mode 100644 index 1c2e9904d3..0000000000 --- a/variadic_templates_test.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include - -template -inline Out& print(Out& out) -{ - return out; -} - -template -inline Out& print(Out& out, const A0 arg0, const Args&... args) -{ - return print(out << arg0, args...); -} - -int main() -{ - print(std::cout, "y", 'e', "s", '\n'); - return 0; -} -