Commit faca57bb by Tobias Schuele

Initial version of open source release.

parents
*.sh binary
# The following files are ignored by Git
*.TMP
*.o
*.exe
build*
*~
*#
# Eclipse CDT project files
.project
.cproject
.settings/
# Latex output files
*.aux
*.log
*.out
*.pdf
*.toc
*.synctex.gz
# Copyright (c) 2014, Siemens AG. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## CheckPartestInstall: Checks if partest install path is defined
# Reads: PARTEST_INSTALL_PREFIX
# Sets: partest_includepath_var
# partest_libpath_var
#
function(CheckPartestInstall BUILD_TESTS _partest_includepath _partest_libpath)
if (BUILD_TESTS STREQUAL ON)
set (PARTEST_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/partest_install PARENT_SCOPE)
set (PARTEST_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/partest_install)
set(${_partest_includepath} ${PARTEST_INSTALL_PREFIX}/include PARENT_SCOPE)
set(${_partest_libpath} ${PARTEST_INSTALL_PREFIX}/lib PARENT_SCOPE)
set (tar_extraction_directory ${CMAKE_CURRENT_BINARY_DIR})
message("-- Extracting partest to directoy ${tar_extraction_directory}/partest")
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xf ${PROJECT_SOURCE_DIR}/partest.tar
WORKING_DIRECTORY ${tar_extraction_directory}
)
if (TARGET PARTEST)
else()
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/partest ${CMAKE_CURRENT_BINARY_DIR}/partest_build)
endif()
endif()
endfunction()
# Copyright (c) 2014, Siemens AG. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Copies the binary target bin after build to the destination.
#
function(CopyBin
BIN bin
DEST destination
)
get_target_property(bin_full_name ${bin} LOCATION)
add_custom_command(
TARGET ${bin}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${bin_full_name} ${destination}
#COMMENT "Copying ${bin} to ${destination}"
)
endfunction()
# Copyright (c) 2014, Siemens AG. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## DOXYGEN DOCUMENTATION
#
# Is only generated when option(.* ON) is set...
function (CreateDoxygenDocumentationTarget)
option(BUILD_DOCUMENTATION "Use Doxygen to create the HTML based API documentation" ON)
if(BUILD_DOCUMENTATION)
FIND_PACKAGE(Doxygen)
#if (NOT DOXYGEN_FOUND)
# message(FATAL_ERROR
# "Doxygen is needed to build the documentation. Please install it correctly")
#endif()
#-- Configure the Template Doxyfile for our specific project
configure_file(doc/reference/Doxyfile.in
${PROJECT_BINARY_DIR}/Doxyfile @ONLY IMMEDIATE)
#-- Add a custom target to run Doxygen when ever the project is built
if (TARGET doxygen)
# Do nothing, since the repeated adding causes an error
else()
add_custom_target (
doxygen
#ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile
SOURCES ${PROJECT_BINARY_DIR}/Doxyfile)
# IF you do NOT want the documentation to be generated EVERY time you build the project
# then leave out the 'ALL' keyword from the above command.
endif()
endif()
endfunction()
# Copyright (c) 2014, Siemens AG. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Visual Studio Project Adaptions
#
# Make a browsable file hierarchy when opening
# the generated visual c++ solution project in visual studio
function(GroupSourcesMSVC directory)
file(GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${directory} ${PROJECT_SOURCE_DIR}/${directory}/*)
foreach(child ${children})
if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/${directory}/${child})
GroupSourcesMSVC(${directory}/${child})
else()
string(REPLACE "/" "\\" groupname ${directory})
string(REPLACE "src" "Sources" groupname ${groupname})
string(REPLACE "include" "Includes" groupname ${groupname})
source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${directory}/${child})
endif()
endforeach()
endfunction()
# Copyright (c) 2014, Siemens AG. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## DETERMINE COMPILER AND LINKER FLAGS
#
function(SetGNUCompilerFlags compiler_libs)
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(compiler_libs pthread rt PARENT_SCOPE)
# -Wall -> All warnings
# -Wextra -> Even more warnings
# -Werror -> Warnings are errors
set(warning_flags "-Wall -Wextra")
if (WARNINGS_ARE_ERRORS STREQUAL ON)
set(warning_flags "${warning_flags} -Werror")
endif()
if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -std=c99 ${warning_flags}"
PARENT_SCOPE)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DEMBB_DEBUG"
PARENT_SCOPE)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG"
PARENT_SCOPE)
endif()
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -std=c++03 ${warning_flags}"
PARENT_SCOPE)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DEMBB_DEBUG"
PARENT_SCOPE)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG"
PARENT_SCOPE)
endif()
endif()
endfunction()
function(SetVisualStudioCompilerFlags)
if(MSVC)
# /Wall -> All warnings
# /WX -> Warnings as errors
#
# Globally deactivated warning numbers (by flag \wd#):
# 4820 -> Deactivates warning "2/4/... bytes padding added after some type"
# 4514 -> Deactivates warning "'fct': unreferenced inline function has
# been removed"
# 4668 -> Deactivates warning "'macro' is not defined as preprocessor macro,
# replacing with '0' in #if/#elif"
# 4710 -> Deactivates warning "Function not inlined"
# 4350 -> Deactivates warning "Behavior change ...", which warns a
# behavior change since VS C++ 2002, when using R-values as
# L-value arguments. This warning occurs a lot in the VC libs.
# 4571 -> Deactivates warning that when compiling with /EHs,
# a catch(...) block will not catch a structured exception.
# 4625 -> Deactivates warning for derived classes
# when copy constructor could not be generated because
# a base class copy constructor is inaccessible
# 4626 -> Deactivates warning for derived classes
# when assignment operator could not be generated because
# a base class assignment operator is inaccessible
# 4711 -> Deactivates warning for inline functions
# This is only an informational warning about which functions
# have been inlined by the compiler.
# 4255 -> Deactivates warning "no function prototype given converting () to (void)"
#
# Locally suppressed warnings (should not be globally suppressed):
# 4640 -> Information that local static variable initialization is not
# thread-safe.
set(warning_flags "/Wall /wd4820 /wd4514 /wd4668 /wd4710 /wd4350 /wd4571 /wd4625 /wd4626 /wd4711 /wd4255")
if (WARNINGS_ARE_ERRORS STREQUAL ON)
set(warning_flags "${warning_flags} /WX")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${warning_flags}" PARENT_SCOPE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${warning_flags}" PARENT_SCOPE)
endif()
endfunction()
# Copyright (c) 2014, Siemens AG. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
## Sets the install base path for headers, libraries, and the documentation
#
function(SetInstallPaths)
if (DEFINED INSTALL_PREFIX)
# User given install path given when calling cmake as "-DINSTALL_PREFIX=...".
set(CMAKE_INSTALL_PREFIX ${INSTALL_PREFIX})
set(INSTALL_PREFIX_DOCS "${CMAKE_INSTALL_PREFIX}/doc")
else()
# Default install path is in build directory.
if (DEFINED UNIX)
set(CMAKE_INSTALL_PREFIX "/usr/local")
set(INSTALL_PREFIX_DOCS "/usr/local/share/doc/${CMAKE_PROJECT_NAME}-${EMBB_BASE_VERSION_MAJOR}.${EMBB_BASE_VERSION_MINOR}")
else()
file(TO_CMAKE_PATH "$ENV{ProgramFiles}" _PROG_FILES) # 32-bit dir on win32, useless to us on win64
file(TO_CMAKE_PATH "$ENV{ProgramFiles(x86)}" _PROG_FILES_X86) # 32-bit dir: only set on win64
file(TO_CMAKE_PATH "$ENV{ProgramW6432}" _PROG_FILES_W6432) # 64-bit dir: only set on win64
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
# 64-bit build on win64
set(_PROGFILESDIR "${_PROG_FILES_W6432}")
else()
if(_PROG_FILES_W6432)
# 32-bit build on win64
set(_PROGFILESDIR "${_PROG_FILES_X86}")
else()
# 32-bit build on win32
set(_PROGFILESDIR "${_PROG_FILES}")
endif()
endif()
set(CMAKE_INSTALL_PREFIX "${_PROGFILESDIR}/${CMAKE_PROJECT_NAME}-${EMBB_BASE_VERSION_MAJOR}.${EMBB_BASE_VERSION_MINOR}.${EMBB_BASE_VERSION_PATCH}")
set(INSTALL_PREFIX_DOCS "${CMAKE_INSTALL_PREFIX}/doc")
message(${INSTALL_PREFIX_DOCS})
IF (WIN32)
STRING(REPLACE "\\" "\\\\" CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} )
STRING(REPLACE "/" "\\\\" CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} )
STRING(REPLACE "\\" "\\\\" INSTALL_PREFIX_DOCS ${INSTALL_PREFIX_DOCS} )
STRING(REPLACE "/" "\\\\" INSTALL_PREFIX_DOCS ${INSTALL_PREFIX_DOCS} )
endif()
endif()
endif()
set(INSTALL_PREFIX ${INSTALL_PREFIX} PARENT_SCOPE)
set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} PARENT_SCOPE)
set(INSTALL_PREFIX_DOCS ${INSTALL_PREFIX_DOCS} PARENT_SCOPE)
message("-- Installation path is ${CMAKE_INSTALL_PREFIX}")
if (INSTALL_DOCS STREQUAL "ON")
message("-- Installation path for documentation is ${INSTALL_PREFIX_DOCS}")
else()
message("-- Disabled installation of documentation")
endif()
endfunction()
# Copyright (c) 2014, Siemens AG. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
project (EMBB)
cmake_minimum_required (VERSION 2.8.9)
# Version number
set (EMBB_BASE_VERSION_MAJOR 0)
set (EMBB_BASE_VERSION_MINOR 2)
set (EMBB_BASE_VERSION_PATCH 0)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build, options are: Debug Release
RelWithDebInfo MinSizeRel." FORCE)
endif(NOT CMAKE_BUILD_TYPE)
## Command line options
#
# The set option will be converted to uppercase letters by cmake!! --> ON/OFF
# Note that the help string (second argument) cannot be printed by cmake.
#
option(BUILD_TESTS "Specify whether tests should be built" ON)
option(BUILD_EXAMPLES "Specify whether examples should be built" OFF)
option(USE_EXCEPTIONS "Specify whether exceptions should be activated in C++" ON)
option(INSTALL_DOCS "Specify whether Doxygen docs should be installed" ON)
option(WARNINGS_ARE_ERRORS "Specify whether warnings should be treated as errors" OFF)
## LOCAL INSTALLATION OF SUBPROJECT BINARIES
#
include(CMakeCommon/CopyInstallFiles.cmake) # Needed in all subprojects
set(local_install_dir ${CMAKE_CURRENT_BINARY_DIR}/binaries)
if (WARNINGS_ARE_ERRORS STREQUAL ON)
message("-- Warnings are treated as errors")
set(EMBB_USE_EXCEPTIONS 1)
else()
message("-- Warnings are not treated as errors (default)")
endif()
message(" (set with command line option -DWARNINGS_ARE_ERRORS=ON/OFF)")
include(CMakeCommon/SetCompilerFlags.cmake)
SetGNUCompilerFlags(compiler_libs compiler_flags)
SetVisualStudioCompilerFlags(compiler_libs compiler_flags)
## Exception handling in C++
#
if (USE_EXCEPTIONS STREQUAL ON)
message("-- Exceptions enabled (default) ")
set(EMBB_USE_EXCEPTIONS 1)
else()
message("-- Exceptions disabled")
set(EMBB_NO_EXCEPTIONS) # A preprocessor define
if (CMAKE_COMPILER_IS_GNUCXX)
LIST(APPEND ${CMAKE_CXX_FLAGS} "-fno-exceptions")
elseif (MSVC)
LIST(FIND ${CMAKE_CXX_FLAGS} "/EHsc" EXCEPTION_FLAG)
if (EXCEPTION_FLAG)
string(REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D_HAS_EXCEPTIONS=0")
endif()
endif()
message(" (set with command line option -DUSE_EXCEPTIONS=ON/OFF)")
## Copy test execution script to local binaries folder
#
if (DEFINED CYGWIN)
set(test_script_in run_tests_cygwin.sh)
set(test_script_out run_tests.sh)
elseif (DEFINED UNIX)
set(test_script_in run_tests_linux.sh)
set(test_script_out run_tests.sh)
else()
set(test_script_in run_tests_windows.bat)
set(test_script_out run_tests.bat)
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy ../scripts/${test_script_in} binaries/${test_script_out}
)
## Test and Partest build
#
include(CMakeCommon/CheckEnableTests.cmake)
if (BUILD_TESTS STREQUAL ON)
message("-- Building tests enabled (default)")
else()
message("-- Building tests disabled")
endif()
message(" (set with command line option -DBUILD_TESTS=ON/OFF)")
CheckPartestInstall(${BUILD_TESTS} partest_includepath partest_libpath)
## SUBPROJECTS
#
add_subdirectory(base_c)
add_subdirectory(base_cpp)
add_subdirectory(mtapi_c)
add_subdirectory(mtapi_cpp)
add_subdirectory(containers_cpp)
add_subdirectory(algorithms_cpp)
add_subdirectory(dataflow_cpp)
if (BUILD_EXAMPLES STREQUAL ON)
message("-- Building examples enabled")
add_subdirectory(doc/examples)
else()
message("-- Building examples disabled (default)")
endif()
message(" (set with command line option -DBUILD_EXAMPLES=ON/OFF)")
## INSTALLATION
#
include(CMakeCommon/SetInstallPaths.cmake)
SetInstallPaths()
## DOXYGEN
#
include(CMakeCommon/CreateDoxygenDocumentationTarget.cmake)
CreateDoxygenDocumentationTarget()
if (INSTALL_DOCS STREQUAL ON)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc/
DESTINATION ${INSTALL_PREFIX_DOCS} FILES_MATCHING PATTERN "*.*" PATTERN "CMakeLists.txt" EXCLUDE)
endif()
This project is licensed under the BSD 2-clause license given below.
The MTAPI header file is copyrighted by the Multicore Association
(http://www.multicore-association.org/) and licensed under the BSD 3-clause
license (see file include\embb\mtapi\c\mtapi.h).
================================================================================
Copyright (c) 2014 Siemens AG. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted to Siemens employees only in order to
develop Siemens owned applications.
Redistribution and use in source and binary forms, with or without
modification, are NOT permitted to external companies or persons unless they
* use it to develop applications for Siemens
* commit themselves to not redistribute the software elsewhere.
Any redistribution must meet the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This diff is collapsed. Click to expand it.
project (project_embb_algorithms)
file(GLOB_RECURSE EMBB_ALGORITHMS_CPP_SOURCES "src/*.cc" "src/*.h")
file(GLOB_RECURSE EMBB_ALGORITHMS_CPP_HEADERS "include/*.h")
file(GLOB_RECURSE EMBB_ALGORITHMS_CPP_TEST_SOURCES "test/*.cc" "test/*.h")
# Execute the GroupSources macro
include(../CMakeCommon/GroupSourcesMSVC.cmake)
GroupSourcesMSVC(include)
GroupSourcesMSVC(src)
GroupSourcesMSVC(test)
set (EMBB_ALGORITHMS_CPP_INCLUDE_DIRS "include" "src" "test")
include_directories(${EMBB_ALGORITHMS_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../base_c/include
${CMAKE_CURRENT_BINARY_DIR}/../base_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include)
add_library(embb_algorithms_cpp ${EMBB_ALGORITHMS_CPP_SOURCES}
${EMBB_ALGORITHMS_CPP_HEADERS})
target_link_libraries(embb_algorithms_cpp embb_mtapi_cpp)
if (BUILD_TESTS STREQUAL ON)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include)
add_executable (embb_algorithms_cpp_test ${EMBB_ALGORITHMS_CPP_TEST_SOURCES})
target_link_libraries(embb_algorithms_cpp_test embb_algorithms_cpp
embb_mtapi_cpp embb_mtapi_c partest embb_base_cpp
embb_base_c ${compiler_libs})
CopyBin(BIN embb_algorithms_cpp_test DEST ${local_install_dir})
endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_algorithms_cpp DESTINATION lib)
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_ALGORITHMS_H_
#define EMBB_ALGORITHMS_ALGORITHMS_H_
/**
* \defgroup CPP_ALGORITHMS Algorithms
* High-level parallel algorithms and functionalities.
* \ingroup CPP
*/
#include <embb/algorithms/count.h>
#include <embb/algorithms/execution_policy.h>
#include <embb/algorithms/for_each.h>
#include <embb/algorithms/identity.h>
#include <embb/algorithms/invoke.h>
#include <embb/algorithms/merge_sort.h>
#include <embb/algorithms/quick_sort.h>
#include <embb/algorithms/reduce.h>
#include <embb/algorithms/scan.h>
#include <embb/algorithms/zip_iterator.h>
#endif // EMBB_ALGORITHMS_ALGORITHMS_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_COUNT_H_
#define EMBB_ALGORITHMS_COUNT_H_
#include <embb/algorithms/execution_policy.h>
namespace embb {
namespace algorithms {
/**
* \defgroup CPP_ALGORITHMS_COUNT Counting
* Parallel count operation
* \ingroup CPP_ALGORITHMS
* \{
*/
#ifdef DOXYGEN
/**
* Counts in parallel the number of elements in a range that are equal to
* the specified value.
*
* The range consists of the elements from \c first to \c last, excluding the
* last element.
*
* \return The number of elements that are equal to \c value
* \throws embb::base::ErrorException if not enough MTAPI tasks can be created
* to satisfy the requirements of the algorithm.
* \threadsafe if the elements in the range are not modified by another thread
* while the algorithm is executed.
* \note No guarantee is given on the execution order of the comparison
* operations.
* \see CountIf(), ExecutionPolicy
* \tparam RAI Random access iterator
* \tparam ValueType Type of \c value that is compared to the elements in the
* range using the \c operator==.
*/
template<typename RAI, typename ValueType>
typename std::iterator_traits<RAI>::difference_type Count(
RAI first,
/**< [IN] Random access iterator pointing to the first element of the range */
RAI last,
/**< [IN] Random access iterator pointing to the last plus one element of the
range */
const ValueType& value,
/**< [IN] Value that the elements in the range are compared to using
\c operator== */
const ExecutionPolicy& policy = ExecutionPolicy(),
/**< [IN] ExecutionPolicy for the counting algorithm */
size_t block_size = 0
/**< [IN] Lower bound for partitioning the range of elements into blocks that
are sorted in parallel. Partitioning of a block stops if its size
is less than or equal to \c block_size. The default value 0 means
that the minimum block size is determined automatically depending on
the number of elements in the range divided by the number of
available cores. */
);
/**
* Counts in parallel the number of elements in a range for which the comparison
* function returns \c true.
*
* The range consists of the elements from \c first to \c last, excluding the
* last element.
*
* \return The number of elements for which \c comparison returns true
* \throws embb::base::ErrorException if not enough MTAPI tasks can be created
* to satisfy the requirements of the algorithm.
* \threadsafe if the elements in the range are not modified by another thread
* while the algorithm is executed.
* \note No guarantee is given on the execution order of the comparison
* function.
* \see Count(), ExecutionPolicy
* \tparam RAI Random access iterator
* \tparam ComparisonFunction Unary predicate with argument of type
* <tt>std::iterator_traits<RAI>::value_type</tt>.
*/
template<typename RAI, typename ComparisonFunction>
typename std::iterator_traits<RAI>::difference_type CountIf(
RAI first,
/**< [IN] Random access iterator pointing to the first element of the range
RAI last, */
/**< [IN] Random access iterator pointing to the last plus one element of the
range */
ComparisonFunction comparison,
/**< [IN] Unary predicate used to test the elements in the range. Elements for
which \c comparison returns true are counted. */
const ExecutionPolicy& policy = ExecutionPolicy(),
/**< [IN] ExecutionPolicy for the counting algorithm */
size_t block_size = 0
/**< [IN] Lower bound for partitioning the range of elements into blocks that
are sorted in parallel. Partitioning of a block stops if its size
is less than or equal to \c block_size. The default value 0 means
that the minimum block size is determined automatically depending on
the number of elements in the range divided by the number of
available cores. */
);
#else // DOXYGEN
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename ValueType>
typename std::iterator_traits<RAI>::difference_type Count(
RAI first,
RAI last,
const ValueType& value
) {
return Count(first, last, value, ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename ValueType>
typename std::iterator_traits<RAI>::difference_type Count(
RAI first,
RAI last,
const ValueType& value,
const ExecutionPolicy& policy
) {
return Count(first, last, value, policy, 0);
}
/**
* Overload of above described Doxygen dummy.
*/
template<typename RAI, typename ValueType>
typename std::iterator_traits<RAI>::difference_type Count(
RAI first,
RAI last,
const ValueType& value,
const ExecutionPolicy& policy,
size_t block_size
);
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename ComparisonFunction>
typename std::iterator_traits<RAI>::difference_type CountIf(
RAI first,
RAI last,
ComparisonFunction comparison
) {
return CountIf(first, last, comparison, ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename ComparisonFunction>
typename std::iterator_traits<RAI>::difference_type CountIf(
RAI first,
RAI last,
ComparisonFunction comparison,
const ExecutionPolicy& policy
) {
return CountIf(first, last, comparison, policy, 0);
}
/**
* Overload of above described Doxygen dummy.
*/
template<typename RAI, typename ComparisonFunction>
typename std::iterator_traits<RAI>::difference_type CountIf(
RAI first,
RAI last,
ComparisonFunction comparison,
const ExecutionPolicy& policy,
size_t block_size
);
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include <embb/algorithms/internal/count-inl.h>
#endif // EMBB_ALGORITHMS_COUNT_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_EXECUTION_POLICY_H_
#define EMBB_ALGORITHMS_EXECUTION_POLICY_H_
#include <embb/mtapi/mtapi.h>
#include <embb/mtapi/affinity.h>
namespace embb {
namespace algorithms {
/**
* Describes the execution policy of a parallel algorithm.
* The execution policy comprises
* - the affinity of tasks to MTAPI worker threads (not CPU cores) and
* - the priority of the spawned tasks.
*
* \ingroup CPP_ALGORITHMS_SCAN
* \ingroup CPP_ALGORITHMS_REDUCTION
* \ingroup CPP_ALGORITHMS_FOREACH
* \ingroup CPP_ALGORITHMS_COUNT
* \ingroup CPP_ALGORITHMS_SORTING
*/
class ExecutionPolicy{
public:
/**
* Constructs the default execution policy.
* Sets the affinity to all worker threads and the priority to the default
* value.
*/
ExecutionPolicy();
/**
* Constructs an execution policy with the specified affinity and priority.
*/
ExecutionPolicy(
bool initial_affinity, /**<
[IN] \c true sets the affinity to all worker threads, \c false to no
worker threads. */
mtapi_uint_t priority /**<
[IN] Priority for the execution policy. */
);
/**
* Constructs an execution policy with the specified priority.
* Sets the affinity to all worker threads.
*/
explicit ExecutionPolicy(
mtapi_uint_t priority /**<
[IN] Priority for the execution policy. */
);
/**
* Constructs an execution policy with the specified affinity.
* Sets the priority to the default value.
*/
explicit ExecutionPolicy(
bool initial_affinity /**<
[IN] \c true sets the affinity to all worker threads, \c false to no
worker threads. */
);
/**
* Sets affinity to a specific worker thread.
*/
void AddWorker(
mtapi_uint_t worker
/**< [IN] Worker thread index */
);
/**
* Removes affinity to a specific worker thread.
*/
void RemoveWorker(
mtapi_uint_t worker
/**< [IN] Worker thread index */
);
/**
* Checks if affinity to a specific worker thread is set.
*
* \return \c true if affinity is set, otherwise \c false
*/
bool IsSetWorker(
mtapi_uint_t worker
/**< [IN] Worker thread index */
);
/**
* Returns the affinity
*
* \return the affinity
*/
const mtapi::Affinity &GetAffinity() const;
/** Returns the priority
*
* \return the priority
*/
mtapi_uint_t GetPriority() const;
private:
/**
* Default priority.
* Currently set to 0 = MAX priority.
*/
static const mtapi_uint_t DefaultPriority;
/**
* Task Affinity.
* Maps the affinity of tasks to MTAPI worker threads (not CPU cores).
*/
mtapi::Affinity affinity_;
/**
* Task Priority.
*/
mtapi_uint_t priority_;
};
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_EXECUTION_POLICY_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_FOR_EACH_H_
#define EMBB_ALGORITHMS_FOR_EACH_H_
#include <embb/algorithms/execution_policy.h>
namespace embb {
namespace algorithms {
/**
* \defgroup CPP_ALGORITHMS_FOREACH Foreach
* Parallel foreach loop
* \ingroup CPP_ALGORITHMS
* \{
*/
#ifdef DOXYGEN
/**
* Applies a unary function to the elements of a range in parallel.
*
* The range consists of the elements from \c first to \c last, excluding the
* last element.
*
* \throws embb::base::ErrorException if not enough MTAPI tasks can be created
* to satisfy the requirements of the algorithm.
* \threadsafe if the elements in the range are not modified by another thread
* while the algorithm is executed.
* \note No guarantee is given on the order in which the function is applied to
* the elements.
* \see ExecutionPolicy, ZipIterator
* \tparam RAI Random access iterator
* \tparam Function Unary function with argument of type
* <tt>std::iterator_traits<RAI>::value_type</tt>.
*/
template<typename RAI, typename Function>
void ForEach(
RAI first,
/**< [IN] Random access iterator pointing to the first element of the range */
RAI last,
/**< [IN] Random access iterator pointing to the last plus one element of the
range */
Function unary,
/**< [IN] Unary function applied to each element in the range */
const ExecutionPolicy& policy = ExecutionPolicy(),
/**< [IN] ExecutionPolicy for the foreach loop execution */
size_t block_size = 0
/**< [IN] Lower bound for partitioning the range of elements into blocks that
are treated in parallel. Partitioning of a block stops if its size
is less than or equal to \c block_size. The default value 0 means
that the minimum block size is determined automatically depending on
the number of elements in the range divided by the number of
available cores. */
);
#else // DOXYGEN
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename Function>
void ForEach(
RAI first,
RAI last,
Function unary
) {
ForEach(first, last, unary, ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename Function>
void ForEach(
RAI first,
RAI last,
Function unary,
const ExecutionPolicy& policy
) {
ForEach(first, last, unary, policy, 0);
}
/**
* Overload of above described Doxygen dummy.
*/
template<typename RAI, typename Function>
void ForEach(
RAI first,
RAI last,
Function unary,
const ExecutionPolicy& policy,
size_t block_size
);
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include <embb/algorithms/internal/for_each-inl.h>
#endif // EMBB_ALGORITHMS_FOR_EACH_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_IDENTITY_H_
#define EMBB_ALGORITHMS_IDENTITY_H_
namespace embb {
namespace algorithms {
/**
* Unary identity functor.
*
* \ingroup CPP_ALGORITHMS_SCAN
* \ingroup CPP_ALGORITHMS_REDUCTION
* \ingroup CPP_ALGORITHMS_FOREACH
* \ingroup CPP_ALGORITHMS_COUNT
* \ingroup CPP_ALGORITHMS_SORTING
*/
struct Identity {
/**
* Returns \c value unchanged.
*
* \return \c value
* \tparam Type Any type
*/
template<typename Type>
Type& operator()(
Type& value
/**< [IN] Value that is returned unchanged */
) {
return value;
}
/**
* Returns \c value unchanged.
*
* \return \c value
* \tparam Type Any type
*/
template<typename Type>
const Type& operator()(
const Type& value
/**< [IN] Value that is returned unchanged */
) {
return value;
}
};
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_IDENTITY_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_INTERNAL_COUNT_INL_H_
#define EMBB_ALGORITHMS_INTERNAL_COUNT_INL_H_
#include <functional>
#include <embb/algorithms/reduce.h>
namespace embb {
namespace algorithms {
namespace internal {
template<typename ValueType>
class ValueComparisonFunction{
public:
explicit ValueComparisonFunction(const ValueType &value)
:value_(value) {}
ValueComparisonFunction(const ValueComparisonFunction &other)
:value_(other.value_) {}
template<typename ElementType>
int operator()(ElementType element) {
if(element == value_)
return 1;
else
return 0;
}
private:
const ValueType &value_;
ValueComparisonFunction &operator=(const ValueComparisonFunction &other);
};
template<typename Function>
class FunctionComparisonFunction{
public:
explicit FunctionComparisonFunction(Function function)
:function_(function) {}
FunctionComparisonFunction(const FunctionComparisonFunction &other)
:function_(other.function_) {}
template<typename ElementType>
int operator()(ElementType element) {
if(function_(element))
return 1;
else
return 0;
}
private:
Function function_;
FunctionComparisonFunction &operator=(const FunctionComparisonFunction &
other);
};
} // namespace internal
template<typename RAI, typename ValueType>
typename std::iterator_traits<RAI>::difference_type
Count(RAI first, RAI last, const ValueType& value,
const ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type Difference;
return Reduce(first, last, Difference(0), std::plus<Difference>(),
internal::ValueComparisonFunction<ValueType>(value), policy,
block_size);
}
template<typename RAI, typename ComparisonFunction>
typename std::iterator_traits<RAI>::difference_type
CountIf(RAI first, RAI last, ComparisonFunction comparison,
const ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type Difference;
return Reduce(first, last, Difference(0), std::plus<Difference>(),
internal::FunctionComparisonFunction<ComparisonFunction>
(comparison), policy, block_size);
}
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_INTERNAL_COUNT_INL_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_INTERNAL_FOR_EACH_INL_H_
#define EMBB_ALGORITHMS_INTERNAL_FOR_EACH_INL_H_
#include <cassert>
#include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h>
#include <embb/algorithms/internal/partition.h>
#include <embb/algorithms/zip_iterator.h>
namespace embb {
namespace algorithms {
namespace internal {
template<typename RAI, typename Function>
class ForEachFunctor {
public:
/**
* Constructs a for-each functor with arguments.
*/
ForEachFunctor(RAI first, RAI last, Function unary,
const ExecutionPolicy& policy, size_t block_size)
: first_(first), last_(last), unary_(unary), policy_(policy),
block_size_(block_size) {
}
void Action(mtapi::TaskContext&) {
size_t distance = static_cast<size_t>(std::distance(first_, last_));
if (distance == 0) return;
if (distance <= block_size_) { // leaf case -> do work
for (RAI curIter(first_); curIter != last_; ++curIter) {
unary_(*curIter);
}
} else { // recurse further
ChunkPartitioner<RAI> partitioner(first_, last_, 2);
ForEachFunctor<RAI, Function> functorL(partitioner[0].GetFirst(),
partitioner[0].GetLast(), unary_, policy_, block_size_);
ForEachFunctor<RAI, Function> functorR(partitioner[1].GetFirst(),
partitioner[1].GetLast(), unary_, policy_, block_size_);
mtapi::Node& node = mtapi::Node::GetInstance();
mtapi::Task taskL = node.Spawn(mtapi::Action(base::MakeFunction(
functorL, &ForEachFunctor<RAI, Function>::Action),
policy_.GetAffinity()), policy_.GetPriority());
mtapi::Task taskR = node.Spawn(mtapi::Action(base::MakeFunction(
functorR, &ForEachFunctor<RAI, Function>::Action),
policy_.GetAffinity()), policy_.GetPriority());
taskL.Wait(MTAPI_INFINITE);
taskR.Wait(MTAPI_INFINITE);
}
}
private:
RAI first_;
RAI last_;
Function unary_;
const ExecutionPolicy& policy_;
size_t block_size_;
/**
* Disables assignment.
*/
ForEachFunctor& operator=(const ForEachFunctor&);
};
template<typename RAI, typename Function>
void ForEachRecurcive(RAI first, RAI last, Function unary,
const ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last);
assert(distance > 0);
mtapi::Node& node = mtapi::Node::GetInstance();
// Determine actually used block size
if (block_size == 0) {
block_size = (static_cast<size_t>(distance) / node.GetCoreCount());
if (block_size == 0) {
block_size = 1;
}
}
// Perform check of task number sufficiency
if (((distance / block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) {
EMBB_THROW(embb::base::ErrorException, "Not enough MTAPI tasks available "
"to perform the parallel foreach loop");
}
ForEachFunctor<RAI, Function> functor(first, last, unary, policy, block_size);
mtapi::Task task = node.Spawn(mtapi::Action(
base::MakeFunction(functor,
&ForEachFunctor<RAI, Function>::Action),
policy.GetAffinity()), policy.GetPriority());
task.Wait(MTAPI_INFINITE);
}
template<typename RAI, typename Function>
void ForEachIteratorCheck(RAI first, RAI last, Function unary,
const ExecutionPolicy& policy, size_t block_size,
std::random_access_iterator_tag) {
return ForEachRecurcive(first, last, unary, policy, block_size);
}
} // namespace internal
template<typename RAI, typename Function>
void ForEach(RAI first, RAI last, Function unary, const ExecutionPolicy& policy,
size_t block_size) {
typename std::iterator_traits<RAI>::iterator_category category;
internal::ForEachIteratorCheck(first, last, unary, policy, block_size,
category);
}
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_INTERNAL_FOR_EACH_INL_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_INTERNAL_MERGE_SORT_INL_H_
#define EMBB_ALGORITHMS_INTERNAL_MERGE_SORT_INL_H_
#include <cassert>
#include <iterator>
#include <functional>
#include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h>
#include <embb/algorithms/internal/partition.h>
namespace embb {
namespace algorithms {
namespace internal {
/**
* Contains the merge sort MTAPI action function and data needed there.
*/
template <typename RAI, typename RAITemp, typename ComparisonFunction>
class MergeSortFunctor {
public:
typedef typename std::iterator_traits<RAI>::value_type value_type;
MergeSortFunctor(RAI first, RAI last, RAITemp temporary_first,
ComparisonFunction comparison, const ExecutionPolicy& policy,
size_t block_size, const RAI& global_first, int depth)
: first_(first), last_(last), temp_first_(temporary_first),
comparison_(comparison), policy_(policy), block_size_(block_size),
global_first_(global_first), depth_(depth) {
}
void Action(mtapi::TaskContext& context) {
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
size_t distance = static_cast<size_t>(std::distance(first_, last_));
if (distance <= 1) {
if(!CloneBackToInput() && distance != 0) {
RAITemp temp_first = temp_first_;
temp_first += std::distance(global_first_, first_);
*temp_first = *first_;
}
return;
}
internal::ChunkPartitioner<RAI> partitioner(first_, last_, 2);
MergeSortFunctor<RAI, RAITemp, ComparisonFunction> functorL(
partitioner[0].GetFirst(), partitioner[0].GetLast(), temp_first_,
comparison_, policy_, block_size_, global_first_, depth_ + 1);
MergeSortFunctor<RAI, RAITemp, ComparisonFunction> functorR(
partitioner[1].GetFirst(), partitioner[1].GetLast(), temp_first_,
comparison_, policy_, block_size_, global_first_, depth_ + 1);
if (distance <= block_size_) {
functorL.Action(context);
functorR.Action(context);
} else {
mtapi::Node& node = mtapi::Node::GetInstance();
mtapi::Task taskL = node.Spawn(mtapi::Action(base::MakeFunction(functorL,
&MergeSortFunctor<RAI, RAITemp, ComparisonFunction>::Action),
policy_.GetAffinity()), policy_.GetPriority());
mtapi::Task taskR = node.Spawn(mtapi::Action(base::MakeFunction(functorR,
&MergeSortFunctor<RAI, RAITemp, ComparisonFunction>::Action),
policy_.GetAffinity()), policy_.GetPriority());
taskL.Wait(MTAPI_INFINITE);
taskR.Wait(MTAPI_INFINITE);
}
if(CloneBackToInput()) {
difference_type first = std::distance(global_first_, functorL.first_);
difference_type mid = std::distance(global_first_, functorR.first_);
difference_type last = std::distance(global_first_, functorR.last_);
SerialMerge(temp_first_ + first, temp_first_ + mid,
temp_first_ + last, functorL.first_, comparison_);
} else {
SerialMerge(functorL.first_, functorR.first_, functorR.last_,
temp_first_ + std::distance(global_first_, functorL.first_),
comparison_);
}
}
/**
* Determines the input and output arrays for one level in merge sort.
*
* \return \c true if the temporary data range is input and the array to be
* sorted is output. \c false, if the other way around.
*/
bool CloneBackToInput() {
return depth_ % 2 == 0 ? true : false;
}
private:
RAI first_;
RAI last_;
RAITemp temp_first_;
ComparisonFunction comparison_;
const ExecutionPolicy &policy_;
size_t block_size_;
const RAI& global_first_;
int depth_;
MergeSortFunctor(const MergeSortFunctor&);
MergeSortFunctor& operator=(const MergeSortFunctor&);
template<typename RAIIn, typename RAIOut>
void SerialMerge(RAIIn first, RAIIn mid, RAIIn last, RAIOut out,
ComparisonFunction comparison) {
RAIIn save_mid = mid;
while ((first != save_mid) && (mid != last)) {
if (comparison(*first, *mid)) {
*out = *first;
++out;
++first;
} else {
*out = *mid;
++out;
++mid;
}
}
while (first != save_mid) {
*out = *first;
++out;
++first;
}
while(mid != last) {
*out = *mid;
++out;
++mid;
}
}
};
} // namespace internal
template<typename RAI, typename RAITemp, typename ComparisonFunction>
void MergeSort(
RAI first,
RAI last,
RAITemp temporary_first,
ComparisonFunction comparison,
const ExecutionPolicy& policy,
size_t block_size
) {
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
embb::mtapi::Node &node = embb::mtapi::Node::GetInstance();
difference_type distance = last - first;
assert(distance >= 0);
assert(block_size == 0); // TODO(Georgios Christodoulou):
// Take block size into account
if (block_size == 0) {
block_size= (static_cast<size_t>(distance) / node.GetCoreCount());
if (block_size == 0)
block_size = 1;
}
if (((distance/block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) {
EMBB_THROW(embb::base::ErrorException,
"Not enough MTAPI tasks available to perform the merge sort");
}
internal::MergeSortFunctor<RAI, RAITemp, ComparisonFunction> functor(
first, last, temporary_first, comparison, policy, block_size, first, 0);
mtapi::Task task = node.Spawn(mtapi::Action(base::MakeFunction(functor,
&internal::MergeSortFunctor<RAI, RAITemp, ComparisonFunction>::Action),
policy.GetAffinity()), policy.GetPriority());
task.Wait(MTAPI_INFINITE);
}
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_INTERNAL_MERGE_SORT_INL_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_INTERNAL_PARTITION_INL_H_
#define EMBB_ALGORITHMS_INTERNAL_PARTITION_INL_H_
namespace embb {
namespace algorithms {
namespace internal {
template<typename ForwardIterator>
ChunkDescriptor<ForwardIterator>::ChunkDescriptor(ForwardIterator first,
ForwardIterator last) :
first(first), last(last) {
}
template<typename ForwardIterator>
ForwardIterator ChunkDescriptor<ForwardIterator>::GetFirst() const {
return first;
}
template<typename ForwardIterator>
ForwardIterator ChunkDescriptor<ForwardIterator>::GetLast() const {
return last;
}
template<typename ForwardIterator>
BlockSizePartitioner<ForwardIterator>::BlockSizePartitioner(
ForwardIterator first, ForwardIterator last, size_t chunkSize) :
first(first), last(last), chunkSize(chunkSize) {
elements_count = static_cast<size_t>(std::distance(first, last));
chunks = elements_count / chunkSize;
if (elements_count % chunkSize != 0)
chunks++;
}
template<typename ForwardIterator>
size_t BlockSizePartitioner<ForwardIterator>::Size() {
return chunks;
}
template<typename ForwardIterator>
const ChunkDescriptor<ForwardIterator>
BlockSizePartitioner<ForwardIterator>::operator[](
size_t const& index) const {
ForwardIterator first_new = first;
std::advance(first_new, index * chunkSize);
ForwardIterator last_new = first_new;
if (index == elements_count / chunkSize) {
std::advance(last_new, elements_count % chunkSize);
} else {
std::advance(last_new, chunkSize);
}
return ChunkDescriptor<ForwardIterator>(first_new, last_new);
}
template<typename ForwardIterator>
size_t ChunkPartitioner<ForwardIterator>::Size() {
return size;
}
template<typename ForwardIterator>
ChunkPartitioner<ForwardIterator>::ChunkPartitioner(ForwardIterator first,
ForwardIterator last, size_t amountChunks) :
first(first), last(last) {
if (amountChunks > 0) {
size = amountChunks;
} else {
// if no concrete chunk size was given, use number of cores...
mtapi::Node& node = mtapi::Node::GetInstance();
size = node.GetCoreCount();
}
elements_count = static_cast<size_t>(std::distance(first, last));
if (size > elements_count) {
// if we want to make more chunks than we have elements, correct
// the number of chunks
size = elements_count;
}
standard_chunk_size = elements_count / size;
bigger_chunk_count = elements_count % size;
}
template<typename ForwardIterator>
const ChunkDescriptor<ForwardIterator>
ChunkPartitioner<ForwardIterator>::operator[](
size_t const& index) const {
typedef typename std::iterator_traits<ForwardIterator>::difference_type
difference_type;
size_t prec_elements_count = 0;
if (index <= bigger_chunk_count) {
prec_elements_count = index * (standard_chunk_size + 1);
} else {
prec_elements_count = (standard_chunk_size + 1) * bigger_chunk_count
+ standard_chunk_size * (index - bigger_chunk_count);
}
size_t cur_elements_count =
(index < bigger_chunk_count) ?
(standard_chunk_size + 1) : standard_chunk_size;
ForwardIterator first_new = first;
std::advance(first_new, prec_elements_count);
first_new = first + static_cast<difference_type>(prec_elements_count);
ForwardIterator last_new = first_new;
std::advance(last_new, cur_elements_count);
return ChunkDescriptor<ForwardIterator>(first_new, last_new);
}
} // namespace internal
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_INTERNAL_PARTITION_INL_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_INTERNAL_PARTITION_H_
#define EMBB_ALGORITHMS_INTERNAL_PARTITION_H_
#include <embb/mtapi/mtapi.h>
namespace embb {
namespace algorithms {
namespace internal {
/**
* A chunk descriptor.
*
* Describes a single partition of a 1-dimensional
* partitioning, using first and last iterator.
*
* \tparam ForwardIterator Type of the iterator.
*/
template<typename ForwardIterator>
class ChunkDescriptor {
private:
ForwardIterator first;
ForwardIterator last;
public:
/**
* Constructor.
*
* \param first The first iterator.
* \param last The last iterator
*/
ChunkDescriptor(ForwardIterator first, ForwardIterator last);
/**
* Gets the first iterator.
*
* \return The first iterator.
*
* \waitfree
*/
ForwardIterator GetFirst() const;
/**
* Gets the last iterator.
*
* \return The last iterator.
*
* \waitfree
*/
ForwardIterator GetLast() const;
};
/**
* Partitioner Interface.
*
* Describes the interface for accessing a 1-dimensional partitioning.
*
* \tparam ForwardIterator Type of the iterator.
*/
template<typename ForwardIterator>
class IPartitioner {
public:
virtual ~IPartitioner() {}
private:
/**
* Gets the amount of partitions.
*
* \return A size_t.
*
* \waitfree
*/
virtual size_t Size() = 0;
/**
* Gets a single partition.
*
* \param index Zero-based index of the partitioner. Range: [0;Size()-1]
*
* \return The indexed value.
*
* \waitfree
*/
virtual const ChunkDescriptor<ForwardIterator> operator[](
size_t const& index) const = 0;
};
/**
* A block size partitioner.
*
* Partitions a 1-dim. collection of elements with total order that provides a
* forward iterator into partitions of size chunkSize. If no chunkSize is given,
* chunkSize is set to 1.
*
* Example:
*
* int A[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13 };
* const int N = (sizeof(A) / sizeof(int) );
* embb::algorithms::ChunkPartitioner< int* > partitioner(A, A + N, 5);
*
* With that, the array is partitioned into chunks of size 5. We therefore
* have following partitions:
* 1: [1,2,3,4,5]
* 2: [6,7,8,9,10]
* 3: [11,12,13]
*
* \tparam ForwardIterator Type of the iterator.
*/
template<typename ForwardIterator>
class BlockSizePartitioner : IPartitioner < ForwardIterator > {
private:
ForwardIterator first;
ForwardIterator last;
size_t chunkSize;
size_t elements_count;
size_t chunks;
public:
/**
* Constructor.
*
*
* \param first The first iterator of the collection.
* \param last The last iterator of the collection.
* \param chunkSize (Optional) size of the chunk.
*/
BlockSizePartitioner(
ForwardIterator first, ForwardIterator last, size_t chunkSize = 1);
/**
* See IPartitioner
*
* \waitfree
*/
virtual size_t Size();
/**
* See IPartitioner
*
* \waitfree
*/
virtual const ChunkDescriptor<ForwardIterator> operator[](
size_t const& index) const;
};
/**
* A chunk partitioner.
*
* Partitions a 1-dim. collection of elements with total order that provides a
* forward iterator into amountChunks partitions. If no amountChunks is given,
* the collection is split into number of cores partitions.
*
* It is avoided to have unbalanced partitions, so they are equally "filled" up.
* With that, we have at most two partition sizes: basic_size and basic_size+1.
* The partitions with basic_size+1 are the ones at the firstning.
*
* If a higher number of chunks shall be produced, is more than contained elements,
* the number of chunks is reduced to the number of elements.
*
* Example:
*
* int A[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13 };
* const int N = (sizeof(A) / sizeof(int) );
* embb::algorithms::ChunkPartitioner< int* > partitioner(A, A + N, 5);
*
* With that, the array is partitioned into chunks of size 5. We therefore
* have following partitions:
* 1: [1,2,3]
* 2: [3,5,6]
* 3: [7,8,9]
* 4: [10,11]
* 5: [12,13]
*
* \tparam ForwardIterator Type of the iterator.
*/
template<typename ForwardIterator>
class ChunkPartitioner : IPartitioner < ForwardIterator > {
private:
size_t size;
size_t elements_count;
ForwardIterator first;
ForwardIterator last;
size_t standard_chunk_size;
size_t bigger_chunk_count;
public:
/**
* See IPartitioner
*
* \waitfree
*/
virtual size_t Size();
/**
* Constructor.
*
* See class documentation.
*
* \waitfree
*
* \param first The first.
* \param last The last.
* \param amountChunks (Optional) the amount chunks.
*/
ChunkPartitioner(ForwardIterator first, ForwardIterator last,
size_t amountChunks = 0);
/**
* See IPartitioner
*
* \waitfree
*/
virtual const ChunkDescriptor<ForwardIterator> operator[](
size_t const& index) const;
};
} // namespace internal
} // namespace algorithms
} // namespace embb
#include <embb/algorithms/internal/partition-inl.h>
#endif // EMBB_ALGORITHMS_INTERNAL_PARTITION_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_INTERNAL_QUICK_SORT_INL_H_
#define EMBB_ALGORITHMS_INTERNAL_QUICK_SORT_INL_H_
#include <cassert>
#include <iterator>
#include <algorithm>
#include <functional>
#include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h>
#include <embb/algorithms/internal/partition.h>
namespace embb {
namespace algorithms {
namespace internal {
template <typename RAI, typename ComparisonFunction>
class QuickSortFunctor {
public:
/**
* Constructs a functor.
*/
QuickSortFunctor(RAI first, RAI last, ComparisonFunction comparison,
const ExecutionPolicy& policy, size_t block_size)
: first_(first), last_(last), comparison_(comparison), policy_(policy),
block_size_(block_size) {
}
/**
* MTAPI action function and starting point of the parallel quick sort.
*/
void Action(mtapi::TaskContext&) {
Difference distance = last_ - first_;
if (distance <= 1) {
return;
} else {
Difference pivot = MedianOfNine(first_, last_);
RAI mid = first_ + pivot;
mid = SerialPartition(first_, last_, mid);
if (distance <= static_cast<Difference>(block_size_)) {
SerialQuickSort(first_, mid);
SerialQuickSort(mid, last_);
} else {
mtapi::Node& node = mtapi::Node::GetInstance();
QuickSortFunctor functor_l(first_, mid, comparison_, policy_,
block_size_);
mtapi::Task task_l = node.Spawn(mtapi::Action(base::MakeFunction(
functor_l, &QuickSortFunctor::Action)));
QuickSortFunctor functor_r(mid, last_, comparison_, policy_,
block_size_);
mtapi::Task task_r = node.Spawn(mtapi::Action(base::MakeFunction(
functor_r, &QuickSortFunctor::Action)));
task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
}
}
}
private:
RAI first_;
RAI last_;
ComparisonFunction comparison_;
const ExecutionPolicy& policy_;
size_t block_size_;
typedef typename std::iterator_traits<RAI>::difference_type Difference;
/**
* Computes the pseudo-median of nine by using MedianOfThree().
*/
Difference MedianOfNine(RAI first, RAI last) {
Difference distance = last - first;
Difference offset = distance / static_cast<Difference>(8);
if (offset == 0) {
return distance / 2;
}
Difference pseudo_median_of_nine = MedianOfThree(
first,
MedianOfThree(first, static_cast<Difference>(0), offset, offset * 2),
MedianOfThree(first, offset * 3, offset * 4, offset * 5),
MedianOfThree(first, offset * 6, offset * 7, distance - 1));
return pseudo_median_of_nine;
}
/**
* Computes the median of three.
*/
Difference MedianOfThree(RAI first, Difference left, Difference mid,
Difference right) {
if (comparison_(*(first + left), *(first + mid))) {
if (comparison_(*(first + mid), *(first + right))) {
return mid;
} else {
if (comparison_(*(first + left), *(first + right)))
return right;
else
return left;
}
} else {
if (comparison_(*(first + right), *(first + mid))) {
return mid;
} else {
if (comparison_(*(first + right), *(first + left)))
return right;
else
return left;
}
}
}
/**
* Performs a quick sort partitioning as serial computation.
*/
RAI SerialPartition(RAI first, RAI last, RAI pivot) {
while (first != last) {
while (comparison_(*first, *pivot)) {
++first;
if (first == last)
return first;
}
do {
--last;
if (first == last) return first;
} while (comparison_(*pivot, *last));
std::swap(*first, *last);
if(pivot == first) {
pivot = last;
} else if (pivot == last) {
pivot = first;
}
++first;
}
return first;
}
/**
* Performs the quick sort algorithm as serial computation.
*/
void SerialQuickSort(RAI first, RAI last) {
if (last - first <= 1) {
return;
} else {
Difference pivot = MedianOfNine(first, last);
RAI mid = first + pivot;
mid = SerialPartition(first, last, mid);
SerialQuickSort(first, mid);
SerialQuickSort(mid, last);
}
}
/**
* Disables assignment.
*/
QuickSortFunctor& operator=(const QuickSortFunctor&);
/**
* Disables Copying.
*/
QuickSortFunctor(const QuickSortFunctor&);
};
} // namespace internal
template <typename RAI, typename ComparisonFunction>
void QuickSort(RAI first, RAI last, ComparisonFunction comparison,
const ExecutionPolicy& policy, size_t block_size) {
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
typename std::iterator_traits<RAI>::difference_type distance = last - first;
assert(distance > 0);
if (block_size == 0) {
block_size= (static_cast<size_t>(distance) / node.GetCoreCount());
if (block_size == 0)
block_size = 1;
}
if (((distance / block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) {
EMBB_THROW(embb::base::ErrorException,
"Not enough MTAPI tasks available for performing quick sort");
}
internal::QuickSortFunctor<RAI, ComparisonFunction> functor(
first, last, comparison, policy, block_size);
mtapi::Task task = node.Spawn(mtapi::Action(base::MakeFunction(
functor, &internal::QuickSortFunctor<RAI, ComparisonFunction>::Action)));
task.Wait(MTAPI_INFINITE);
}
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_INTERNAL_QUICK_SORT_INL_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_
#define EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_
#include <embb/mtapi/mtapi.h>
#include <embb/algorithms/internal/partition.h>
#include <functional>
#include <embb/base/exceptions.h>
#include <cassert>
namespace embb {
namespace algorithms {
namespace internal {
template<typename RAI, typename ReturnType, typename ReductionFunction,
typename TransformationFunction>
class ReduceFunctor {
public:
ReduceFunctor(RAI first, RAI last, ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const ExecutionPolicy &policy, size_t block_size,
ReturnType& result)
:
first_(first), last_(last), neutral_(neutral), reduction_(reduction),
transformation_(transformation), policy_(policy),
block_size_(block_size), result_(result) {
}
void Action(mtapi::TaskContext&) {
if (first_ == last_) {
return;
}
size_t distance = static_cast<size_t>(std::distance(first_, last_));
if (distance <= block_size_) { // leaf case -> do work
ReturnType result(neutral_);
for (RAI iter = first_; iter != last_; ++iter) {
result = reduction_(result, transformation_(*iter));
}
result_ = result;
} else { // recurse further
internal::ChunkPartitioner<RAI> partitioner(first_, last_, 2);
ReturnType result_l(neutral_);
ReturnType result_r(neutral_);
ReduceFunctor functor_l(partitioner[0].GetFirst(),
partitioner[0].GetLast(),
neutral_, reduction_, transformation_, policy_,
block_size_, result_l);
ReduceFunctor functor_r(partitioner[1].GetFirst(),
partitioner[1].GetLast(),
neutral_, reduction_, transformation_, policy_,
block_size_, result_r);
mtapi::Node& node = mtapi::Node::GetInstance();
mtapi::Task task_l = node.Spawn(mtapi::Action(base::MakeFunction(
functor_l, &ReduceFunctor::Action), policy_.GetAffinity()),
policy_.GetPriority());
mtapi::Task task_r = node.Spawn(mtapi::Action(base::MakeFunction(
functor_r, &ReduceFunctor::Action), policy_.GetAffinity()),
policy_.GetPriority());
task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
result_ = reduction_(result_l, result_r);
}
}
private:
RAI first_;
RAI last_;
ReturnType neutral_;
ReductionFunction reduction_;
TransformationFunction transformation_;
const ExecutionPolicy& policy_;
size_t block_size_;
ReturnType& result_;
ReduceFunctor& operator=(const ReduceFunctor&);
ReduceFunctor(const ReduceFunctor&);
};
template<typename RAI, typename ReturnType, typename ReductionFunction,
typename TransformationFunction>
ReturnType ReduceRecurcive(RAI first, RAI last, ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last);
assert(distance > 0);
mtapi::Node& node = mtapi::Node::GetInstance();
size_t used_block_size = block_size;
if (used_block_size == 0) {
used_block_size = static_cast<size_t>(distance) / node.GetCoreCount();
if (used_block_size == 0) used_block_size = 1;
}
if (((distance / used_block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) {
EMBB_THROW(embb::base::ErrorException,
"Number of computation tasks required in reduction would "
"exceed MTAPI maximum number of tasks");
}
ReturnType result = neutral;
typedef ReduceFunctor<RAI, ReturnType, ReductionFunction,
TransformationFunction> Functor;
Functor functor(first, last, neutral, reduction, transformation, policy,
used_block_size, result);
mtapi::Task task = node.Spawn(mtapi::Action(base::MakeFunction(
functor, &Functor::Action), policy.GetAffinity()), policy.GetPriority());
task.Wait(MTAPI_INFINITE);
return result;
}
template<typename RAI, typename TransformationFunction,
typename ReductionFunction, typename ReturnType>
ReturnType ReduceIteratorCheck(RAI first, RAI last, ReductionFunction reduction,
TransformationFunction transformation,
ReturnType neutral,
const ExecutionPolicy& policy, size_t block_size,
std::random_access_iterator_tag) {
return ReduceRecurcive(first, last, neutral, reduction, transformation,
policy, block_size);
}
} // namespace internal
template<typename RAI, typename ReturnType, typename ReductionFunction,
typename TransformationFunction >
ReturnType Reduce(RAI first, RAI last, ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const ExecutionPolicy& policy, size_t block_size) {
typename std::iterator_traits<RAI>::iterator_category category;
return internal::ReduceIteratorCheck(first, last, reduction, transformation,
neutral, policy, block_size, category);
}
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_INTERNAL_SCAN_INL_H_
#define EMBB_ALGORITHMS_INTERNAL_SCAN_INL_H_
#include <cassert>
#include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h>
#include <embb/algorithms/execution_policy.h>
#include <embb/algorithms/internal/partition.h>
namespace embb {
namespace algorithms {
namespace internal {
template<typename RAIIn, typename RAIOut, typename ReturnType,
typename ScanFunction, typename TransformationFunction>
class ScanFunctor {
public:
ScanFunctor(RAIIn first, RAIIn last, RAIOut output_iterator,
ReturnType neutral, ScanFunction scan,
TransformationFunction transformation,
const ExecutionPolicy& policy,
size_t block_size, ReturnType* tree_values, size_t node_id,
bool going_down)
: policy_(policy), first_(first), last_(last),
output_iterator_(output_iterator), scan_(scan),
transformation_(transformation),
neutral_(neutral), block_size_(block_size), tree_values_(tree_values),
node_id_(node_id), parent_value_(neutral), is_first_pass_(going_down) {
}
void Action(mtapi::TaskContext&) {
if (first_ == last_) {
return;
}
size_t distance = static_cast<size_t>(std::distance(first_, last_));
if (distance <= block_size_) { // leaf case -> do work
if (is_first_pass_) {
RAIIn iter_in = first_;
RAIOut iter_out = output_iterator_;
ReturnType result = transformation_(*first_);
*iter_out = result;
++iter_in;
++iter_out;
while (iter_in != last_) {
result = scan_(result, transformation_(*iter_in));
*iter_out = result;
++iter_in;
++iter_out;
}
SetTreeValue(result);
} else { // Second pass
RAIIn iter_in = first_;
RAIOut iter_out = output_iterator_;
while (iter_in != last_) {
*iter_out = scan_(parent_value_, *iter_out);
++iter_in;
++iter_out;
}
}
} else {
internal::ChunkPartitioner<RAIIn> partitioner(first_, last_, 2);
ScanFunctor functor_l(partitioner[0].GetFirst(), partitioner[0].GetLast(),
output_iterator_, neutral_, scan_, transformation_,
policy_, block_size_, tree_values_, node_id_,
is_first_pass_);
ScanFunctor functor_r(partitioner[1].GetFirst(), partitioner[1].GetLast(),
output_iterator_, neutral_, scan_, transformation_,
policy_, block_size_, tree_values_, node_id_,
is_first_pass_);
functor_l.SetID(1);
functor_r.SetID(2);
std::advance(functor_r.output_iterator_,
std::distance(functor_l.first_, functor_r.first_));
if (!is_first_pass_) {
functor_l.parent_value_ = parent_value_;
functor_r.parent_value_ = functor_l.GetTreeValue() + parent_value_;
}
mtapi::Node& node = mtapi::Node::GetInstance();
mtapi::Task task_l = node.Spawn(mtapi::Action(base::MakeFunction(
functor_l, &ScanFunctor::Action),
policy_.GetAffinity()),
policy_.GetPriority());
mtapi::Task task_r = node.Spawn(mtapi::Action(base::MakeFunction(
functor_r, &ScanFunctor::Action),
policy_.GetAffinity()),
policy_.GetPriority());
task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
SetTreeValue(scan_(functor_l.GetTreeValue(), functor_r.GetTreeValue()));
}
}
ReturnType GetTreeValue() {
return tree_values_[node_id_];
}
void SetTreeValue(ReturnType value) {
tree_values_[node_id_] = value;
}
private:
const ExecutionPolicy& policy_;
RAIIn first_;
RAIIn last_;
RAIOut output_iterator_;
ScanFunction scan_;
TransformationFunction transformation_;
ReturnType neutral_;
size_t block_size_;
ReturnType* tree_values_;
size_t node_id_;
ReturnType parent_value_;
bool is_first_pass_;
void SetID(int is_left) {
if (is_left == 1) {
node_id_ = 2 * node_id_ + 1;
} else if (is_left == 2) {
node_id_ = 2 * node_id_ + 2;
}
}
/**
* Disables assignment.
*/
ScanFunctor& operator=(const ScanFunctor&);
/**
* Disables copying.
*/
ScanFunctor(const ScanFunctor&);
};
template<typename RAIIn, typename RAIOut, typename ReturnType,
typename ScanFunction, typename TransformationFunction>
void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator,
ReturnType neutral, ScanFunction scan,
TransformationFunction transformation,
const ExecutionPolicy& policy, size_t block_size,
std::random_access_iterator_tag) {
typedef typename std::iterator_traits<RAIIn>::difference_type difference_type;
difference_type distance = std::distance(first, last);
if (distance <= 0) {
return;
}
mtapi::Node& node = mtapi::Node::GetInstance();
ReturnType values[MTAPI_NODE_MAX_TASKS_DEFAULT];
size_t used_block_size = block_size;
if (block_size == 0) {
used_block_size = static_cast<size_t>(distance) / node.GetCoreCount();
if (used_block_size == 0) used_block_size = 1;
}
if (((distance / used_block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) {
EMBB_THROW(embb::base::ErrorException,
"Number of computation tasks required in scan "
"exceeds MTAPI maximum number of tasks");
}
// first pass. Calculates prefix sums for leaves and when recursion returns
// it creates the tree.
typedef ScanFunctor<RAIIn, RAIOut, ReturnType, ScanFunction,
TransformationFunction> Functor;
Functor functor_down(first, last, output_iterator, neutral, scan,
transformation, policy, used_block_size, values, 0,
true);
mtapi::Task task_down = node.Spawn(mtapi::Action(base::MakeFunction(
functor_down, &Functor::Action),
policy.GetAffinity()), policy.GetPriority());
task_down.Wait(MTAPI_INFINITE);
// Second pass. Gives to each leaf the part of the prefix missing
Functor functor_up(first, last, output_iterator, neutral, scan,
transformation, policy, used_block_size, values, 0, false);
mtapi::Task task_up = node.Spawn(mtapi::Action(base::MakeFunction(
functor_up, &Functor::Action),
policy.GetAffinity()), policy.GetPriority());
task_up.Wait(MTAPI_INFINITE);
}
} // namespace internal
template<typename RAIIn, typename RAIOut, typename ReturnType,
typename ScanFunction, typename TransformationFunction>
void Scan(RAIIn first, RAIIn last, RAIOut output_iterator, ReturnType neutral,
ScanFunction scan, TransformationFunction transformation,
const ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAIIn>::iterator_category category;
internal::ScanIteratorCheck(first, last, output_iterator, neutral,
scan, transformation, policy, block_size, category());
}
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_INTERNAL_SCAN_INL_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_MERGE_SORT_H_
#define EMBB_ALGORITHMS_MERGE_SORT_H_
#include <functional>
#include <embb/algorithms/execution_policy.h>
#include <embb/base/memory_allocation.h>
namespace embb {
namespace algorithms {
/**
* \defgroup CPP_ALGORITHMS_SORTING Sorting
* Parallel merge sort and quick sort algorithms
* \ingroup CPP_ALGORITHMS
* \{
*/
#ifdef DOXYGEN
/**
* Sorts a range of elements using a parallel merge sort algorithm with implicit
* allocation of dynamic memory.
*
* The range consists of the elements from \c first to \c last, excluding the
* last element. Since the algorithm does not sort in-place, it requires
* additional memory which is implicitly allocated by the function.
*
* \throws embb::base::ErrorException if not enough MTAPI tasks can be created
* to satisfy the requirements of the algorithm.
* \memory Array with <tt>last-first</tt> elements of type
* <tt>std::iterator_traits<RAI>::value_type</tt>.
* \threadsafe if the elements in the range <tt>[first,last)</tt> are not
* modified by another thread while the algorithm is executed.
* \note No guarantee is given on the execution order of the comparison
operations.
* \see ExecutionPolicy, MergeSort()
* \tparam RAI Random access iterator
* \tparam ComparisonFunction Binary predicate with both arguments of type
* <tt>std::iterator_traits<RAI>::value_type</tt>.
*/
template<typename RAI, typename ComparisonFunction>
void MergeSortAllocate(
RAI first,
/**< [IN] Random access iterator pointing to the first element of the range */
RAI last,
/**< [IN] Random access iterator pointing to the last plus one element of the
range */
ComparisonFunction comparison
= std::less<typename std::iterator_traits<RAI>::value_type>(),
/**< [IN] Binary predicate used to establish the sorting order. An element
\c a appears before an element \c b in the sorted range if
<tt>comparison(a, b) == true</tt>. The default value uses the
less-than relation. */
const ExecutionPolicy& policy = ExecutionPolicy(),
/**< [IN] ExecutionPolicy for the merge sort algorithm */
size_t block_size = 0
/**< [IN] Lower bound for partitioning the range of elements into blocks that
are sorted in parallel. Partitioning of a block stops if its size
is less than or equal to \c block_size. The default value 0 means
that the minimum block size is determined automatically depending on
the number of elements in the range divided by the number of
available cores. */
);
/**
* Sorts a range of elements using a parallel merge sort algorithm without
* implicit allocation of dynamic memory.
*
* The range consists of the elements from \c first to \c last, excluding the
* last element. Since the algorithm does not sort in-place, it requires
* additional memory which must be provided by the user. The range pointed to
* by \c temporary_first must have the same number of elements as the range to
* be sorted, and the elements of both ranges must have the same type.
*
* \throws embb::base::ErrorException if not enough MTAPI tasks can be created
* to satisfy the requirements of the algorithm.
* \threadsafe if the elements in the ranges <tt>[first,last)</tt> and
* <tt>[temporary_first,temporary_first+(last-first)</tt> are not
* modified by another thread while the algorithm is executed.
* \note No guarantee is given on the execution order of the comparison
* operations.
* \see ExecutionPolicy, MergeSortAllocate()
* \tparam RAI Random access iterator
* \tparam RAITemp Random access iterator for temporary memory. Has to have the
* same value type as RAI.
* \tparam ComparisonFunction Binary predicate with both arguments of type
* <tt>std::iterator_traits<RAI>::value_type</tt>.
*/
template<typename RAI, typename RAITemp, typename ComparisonFunction>
void MergeSort(
RAI first,
/**< [IN] Random access iterator pointing to the first element of the range */
RAI last,
/**< [IN] Random access iterator to last plus one element to be sorted */
RAITemp temporary_first,
/**< [IN] Random access iterator pointing to the last plus one element of the
range */
ComparisonFunction comparison
= std::less<typename std::iterator_traits<RAI>::value_type>(),
/**< [IN] Binary predicate used to establish the sorting order. An element
\c a appears before an element \c b in the sorted range if
<tt>comparison(a, b) == true</tt>. The default value uses the
less-than relation. */
const ExecutionPolicy& policy = ExecutionPolicy(),
/**< [IN] ExecutionPolicy for the merge sort algorithm */
size_t block_size = 0
/**< [IN] Lower bound for partitioning the range of elements into blocks that
are sorted in parallel. Partitioning of a block stops if its size
is less than or equal to \c block_size. The default value 0 means
that the minimum block size is determined automatically depending on
the number of elements in the range divided by the number of
available cores. */
);
#else // DOXYGEN
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI>
void MergeSortAllocate(
RAI first,
RAI last
) {
MergeSortAllocate(first, last,
std::less<typename std::iterator_traits<RAI>::value_type>(),
ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename ComparisonFunction>
void MergeSortAllocate(
RAI first,
RAI last,
ComparisonFunction comparison
) {
MergeSortAllocate(first, last, comparison, ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename ComparisonFunction>
void MergeSortAllocate(
RAI first,
RAI last,
ComparisonFunction comparison,
const ExecutionPolicy& policy
) {
MergeSortAllocate(first, last, comparison, policy, 0);
}
/**
* Overload of above described Doxygen dummy.
*/
template<typename RAI, typename ComparisonFunction>
void MergeSortAllocate(
RAI first,
RAI last,
ComparisonFunction comparison,
const ExecutionPolicy& policy,
size_t block_size
) {
typedef base::Allocation Alloc;
typename std::iterator_traits<RAI>::difference_type distance = last - first;
typedef typename std::iterator_traits<RAI>::value_type value_type;
value_type* temporary = static_cast<value_type*>(
Alloc::Allocate(distance * sizeof(value_type)));
MergeSort(first, last, temporary, comparison, policy, block_size);
Alloc::Free(temporary);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename RAITemp>
void MergeSort(
RAI first,
RAI last,
RAITemp temporary_first
) {
MergeSort(first, last, temporary_first,
std::less<typename std::iterator_traits<RAI>::value_type>(),
ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename RAITemp, typename ComparisonFunction>
void MergeSort(
RAI first,
RAI last,
RAITemp temporary_first,
ComparisonFunction comparison
) {
MergeSort(first, last, temporary_first, comparison, ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename RAITemp, typename ComparisonFunction>
void MergeSort(
RAI first,
RAI last,
RAITemp temporary_first,
ComparisonFunction comparison,
const ExecutionPolicy& policy
) {
MergeSort(first, last, temporary_first, comparison, policy, 0);
}
/**
* Overload of above described Doxygen dummy.
*/
template<typename RAI, typename RAITemp, typename ComparisonFunction>
void MergeSort(
const ExecutionPolicy& policy,
RAI first,
RAI last,
RAITemp temporary_first,
ComparisonFunction comparison,
size_t block_size
);
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include<embb/algorithms/internal/merge_sort-inl.h>
#endif // EMBB_ALGORITHMS_MERGE_SORT_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_QUICK_SORT_H_
#define EMBB_ALGORITHMS_QUICK_SORT_H_
#include <functional>
#include <embb/algorithms/execution_policy.h>
namespace embb {
namespace algorithms {
/**
* \ingroup CPP_ALGORITHMS_SORTING
* \{
*/
#ifdef DOXYGEN
/**
* Sorts a range of elements using a parallel quick sort algorithm.
*
* The range consists of the elements from \c first to \c last, excluding the
* last element. The algorithm sorts in-place and requires no additional memory.
* It has, however, a worst-case time complexity of
* <tt>O((last-first)<sup>2</sup>)</tt>.
*
* \throws embb::base::ErrorException if not enough MTAPI tasks can be created
* to satisfy the requirements of the algorithm.
* \threadsafe if the elements in the range <tt>[first,last)</tt> are not
* modified by another thread while the algorithm is executed.
* \note No guarantee is given on the execution order of the comparison
* operations.
* \see ExecutionPolicy, MergeSort()
* \tparam RAI Random access iterator
* \tparam ComparisonFunction Binary predicate with both arguments of type
* <tt>std::iterator_traits<RAI>::value_type</tt>.
*/
template <typename RAI, typename ComparisonFunction>
void QuickSort(
RAI first,
/**< [IN] Random access iterator pointing to the first element of the range */
RAI last,
/**< [IN] Random access iterator pointing to the last plus one element of the
range */
ComparisonFunction comparison
= std::less<typename std::iterator_traits<RAI>::value_type>(),
/**< [IN] Binary predicate used to establish the sorting order. An element
\c a appears before an element \c b in the sorted range if
<tt>comparison(a, b) == true</tt>. The default value uses the
less-than relation. */
const ExecutionPolicy& policy = ExecutionPolicy(),
/**< [IN] ExecutionPolicy for the quick sort algorithm */
size_t block_size = 0
/**< [IN] Lower bound for partitioning the range of elements into blocks that
are sorted in parallel. Partitioning of a block stops if its size
is less than or equal to \c block_size. The default value 0 means
that the minimum block size is determined automatically depending on
the number of elements in the range divided by the number of
available cores. Note that quick sort does not guarantee a
partitioning into evenly sized blocks, as the partitions depend on
the values to be sorted. */
);
#else // DOXYGEN
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template <typename RAI>
void QuickSort(
RAI first,
RAI last
) {
QuickSort(first, last,
std::less<typename std::iterator_traits<RAI>::value_type>(),
ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template <typename RAI, typename ComparisonFunction>
void QuickSort(
RAI first,
RAI last,
ComparisonFunction comparison
) {
QuickSort(first, last, comparison, ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template <typename RAI, typename ComparisonFunction>
void QuickSort(
RAI first,
RAI last,
ComparisonFunction comparison,
const ExecutionPolicy& policy
) {
QuickSort(first, last, comparison, policy, 0);
}
/**
* Overload of above described Doxygen dummy.
*/
template <typename RAI, typename ComparisonFunction>
void QuickSort(
RAI first,
RAI last,
ComparisonFunction comparison,
const ExecutionPolicy& policy,
size_t block_size
);
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include<embb/algorithms/internal/quick_sort-inl.h>
#endif // EMBB_ALGORITHMS_QUICK_SORT_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_REDUCE_H_
#define EMBB_ALGORITHMS_REDUCE_H_
#include <embb/algorithms/execution_policy.h>
#include <embb/algorithms/identity.h>
namespace embb {
namespace algorithms {
/**
* \defgroup CPP_ALGORITHMS_REDUCTION Reduction
* Parallel reduction computation
* \ingroup CPP_ALGORITHMS
* \{
*/
#ifdef DOXYGEN
/**
* Performs a parallel reduction operation on a range of elements.
*
* The range consists of the elements from \c first to \c last, excluding the
* last element. The type of the result (\c ReturnType) is deduced from the
* \c neutral element.
*
* \return
* <tt>reduction(transformation(*first), ..., transformation(*(last-1)))</tt>
* where the reduction function is applied pairwise.
* \throws embb::base::ErrorException if not enough MTAPI tasks can be created
* to satisfy the requirements of the algorithm.
* \threadsafe if the elements in the range are not modified by another thread
* while the algorithm is executed.
* \note No guarantee is given on the order in which the functions \c reduction
* and \c transformation are applied to the elements.\n
* For all \c x of type \c ReturnType it must hold that
* <tt>reduction(x, neutral) == x</tt>. \n
* The reduction operation need not be commutative but must be
* associative, i.e., <tt>reduction(x, reduction(y, z)) ==
* reduction(reduction(x, y), z))</tt> for all \c x, \c y, \c z of type
* \c ReturnType.
* \see ExecutionPolicy, ZipIterator, Identity
* \tparam RAI Random access iterator
* \tparam ReturnType Type of result of reduction operation, deduced from
* \c neutral
* \tparam ReductionFunction Binary reduction function with signature
* <tt>ReturnType ReductionFunction(ReturnType, ReturnType)</tt>.
* \tparam TransformationFunction Unary transformation function with signature
* <tt>ReturnType TransformationFunction(typename
* std::iterator_traits<RAI>::value_type)</tt>
*/
template<typename RAI, typename ReturnType, typename ReductionFunction,
typename TransformationFunction>
ReturnType Reduce(
RAI first,
/**< [IN] Random access iterator pointing to the first element of the range */
RAI last,
/**< [IN] Random access iterator pointing to the last plus one element of the
range */
ReturnType neutral,
/**< [IN] Neutral element of the reduction operation. */
ReductionFunction reduction,
/**< [IN] Reduction operation to be applied to the elements of the range */
TransformationFunction transformation = Identity(),
/**< [IN] Transforms the elements of the range before the reduction operation
is applied */
const ExecutionPolicy& policy = ExecutionPolicy(),
/**< [IN] ExecutionPolicy for the reduction computation */
size_t block_size = 0
/**< [IN] Lower bound for partitioning the range of elements into blocks that
are treated in parallel. Partitioning of a block stops if its size
is less than or equal to \c block_size. The default value 0 means
that the minimum block size is determined automatically depending on
the number of elements in the range divided by the number of
available cores. */
);
#else // DOXYGEN
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename ReturnType, typename ReductionFunction>
ReturnType Reduce(
RAI first,
RAI last,
ReturnType neutral,
ReductionFunction reduction
) {
return Reduce(first, last, neutral, reduction, Identity(), ExecutionPolicy(),
0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename ReturnType, typename ReductionFunction,
typename TransformationFunction>
ReturnType Reduce(
RAI first,
RAI last,
ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation
) {
return Reduce(first, last, neutral, reduction, transformation,
ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAI, typename ReturnType, typename ReductionFunction,
typename TransformationFunction>
ReturnType Reduce(
RAI first,
RAI last,
ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const ExecutionPolicy& policy
) {
return Reduce(first, last, neutral, reduction, transformation, policy, 0);
}
/**
* Overload of above described Doxygen dummy.
*/
template<typename RAI, typename ReturnType, typename ReductionFunction,
typename TransformationFunction>
ReturnType Reduce(
RAI first,
RAI last,
ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const ExecutionPolicy& policy,
size_t block_size
);
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include <embb/algorithms/internal/reduce-inl.h>
#endif // EMBB_ALGORITHMS_REDUCE_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_SCAN_H_
#define EMBB_ALGORITHMS_SCAN_H_
#include <embb/algorithms/execution_policy.h>
#include <embb/algorithms/identity.h>
namespace embb {
namespace algorithms {
/**
* \defgroup CPP_ALGORITHMS_SCAN Scan
* Parallel scan computation
* \ingroup CPP_ALGORITHMS
*
* \{
*/
#ifdef DOXYGEN
/**
* Performs a parallel scan (or prefix) computation on a range of elements.
*
* The algorithm reads an input range and writes its result to a separate output
* range. The input range consists of the elements from \c first to \c last,
* excluding the last element. The output range consists of the elements from
* \c output_first to <tt>output_first + std::difference(last - first)</tt>.
*
* The algorithm performs two runs on the given range. Hence, a performance
* speedup can only be expected on processors with more than two cores.
*
* \throws embb::base::ErrorException if not enough MTAPI tasks can be created
* to satisfy the requirements of the algorithm.
* \threadsafe if the elements in the range are not modified by another thread
* while the algorithm is executed.
* \note No guarantee is given on the order in which the functions \c scan
* and \c transformation are applied to the elements.\n
* For all \c x of type \c ReturnType it must hold that
* <tt>reduction(x, neutral) == x</tt>. \n
* The reduction operation need not be commutative but must be
* associative, i.e., <tt>reduction(x, reduction(y, z)) ==
* reduction(reduction(x, y), z))</tt> for all \c x, \c y, \c z of type
* \c ReturnType.
* \see ExecutionPolicy, Identity, ZipIterator
* \tparam RAIIn Random access iterator type of input range
* \tparam RAIOut Random access iterator type of output range
* \tparam ReturnType Type of output elements of scan operation, deduced from
* \c neutral
* \tparam ScanFunction Binary scan function with signature
* <tt>ReturnType ScanFunction(ReturnType, ReturnType)</tt>
* \tparam TransformationFunction Unary transformation function with signature
* <tt>ReturnType TransformationFunction(typename
* std::iterator_traits<RAIIn>::value_type)</tt>.
*/
template<typename RAIIn, typename RAIOut, typename ReturnType,
typename ScanFunction, typename TransformationFunction>
void Scan(
RAIIn first,
/**< [IN] Random access iterator pointing to the first element of the input
range */
RAIIn last,
/**< [IN] Random access iterator pointing to the last plus one element of the
input range */
RAIOut output_first,
/**< [IN] Random access iterator pointing to the first element of the output
range */
ReturnType neutral,
/**< [IN] Neutral element of the \c scan operation. */
ScanFunction scan,
/**< [IN] Scan operation to be applied to the elements of the input range */
TransformationFunction transformation = Identity(),
/**< [IN] Transforms the elements of the input range before the scan operation
is applied */
const ExecutionPolicy& policy = ExecutionPolicy(),
/**< [IN] ExecutionPolicy for the scan computation */
size_t block_size = 0
/**< [IN] Lower bound for partitioning the range of elements into blocks that
are treated in parallel. Partitioning of a block stops if its size
is less than or equal to \c block_size. The default value 0 means
that the minimum block size is determined automatically depending on
the number of elements in the range divided by the number of
available cores. */
);
#else // DOXYGEN
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAIIn, typename RAIOut, typename ReturnType,
typename ScanFunction>
void Scan(
RAIIn first,
RAIIn last,
RAIOut output_iterator,
ReturnType neutral,
ScanFunction scan
) {
Scan(first, last, output_iterator, neutral, scan, Identity(),
ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAIIn, typename RAIOut, typename ReturnType,
typename ScanFunction, typename TransformationFunction>
void Scan(
RAIIn first,
RAIIn last,
RAIOut output_iterator,
ReturnType neutral,
ScanFunction scan,
TransformationFunction transformation
) {
Scan(first, last, output_iterator, neutral, scan, transformation,
ExecutionPolicy(), 0);
}
/**
* Overload of above described Doxygen dummy with less arguments.
*/
template<typename RAIIn, typename RAIOut, typename ReturnType,
typename ScanFunction, typename TransformationFunction>
void Scan(
RAIIn first,
RAIIn last,
RAIOut output_iterator,
ReturnType neutral,
ScanFunction scan,
TransformationFunction transformation,
const ExecutionPolicy& policy
) {
Scan(first, last, output_iterator, neutral, scan, transformation, policy, 0);
}
/**
* Overload of above described Doxygen dummy.
*/
template<typename RAIIn, typename RAIOut, typename ReturnType,
typename ScanFunction, typename TransformationFunction>
void Scan(
RAIIn first,
RAIIn last,
RAIOut output_iterator,
ReturnType neutral,
ScanFunction scan,
TransformationFunction transformation,
const ExecutionPolicy& policy,
size_t block_size
);
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include <embb/algorithms/internal/scan-inl.h>
#endif // EMBB_ALGORITHMS_SCAN_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_ALGORITHMS_ZIP_ITERATOR_H_
#define EMBB_ALGORITHMS_ZIP_ITERATOR_H_
#include<iterator>
#include <utility>
#include <cassert>
namespace embb {
namespace algorithms {
/**
* \defgroup CPP_ALGORITHMS_ZIP_ITERATOR Zip Iterator
* Zip two iterators
* \ingroup CPP_ALGORITHMS
* \{
*/
/**
* Container for the values of two dereferenced iterators.
* The values contained are of type
* <tt>std::iterator_traits<Iterator>::reference</tt>.
* \notthreadsafe
* \tparam TypeA Type of the first value
* \tparam TypeB Type of the first value
*
*/
template<typename TypeA, typename TypeB>
class ZipPair {
public:
/**
* Constructs a pair from two values.
*/
ZipPair(
TypeA first,
/**< [IN] First value*/
TypeB second
/**< [IN] Second value*/
)
:first_(first), second_(second) {}
/**
* Copies a pair.
*/
ZipPair(
const ZipPair& other
/**< [IN] pair to copy */
)
:first_(other.first_), second_(other.second_) {}
/**
* Returns the first value of the pair.
*
* \return The first value of the pair.
*/
TypeA First() {
return first_;
}
/**
* Returns the second value of the pair.
*
* \return The second value of the pair
*/
TypeB Second() {
return second_;
}
/**
* Returns the first value of the pair.
*
* \return The first value of the pair.
*/
const TypeA First() const {
return first_;
}
/**
* Returns the second value of the pair.
*
* \return The second value of the pair
*/
const TypeB Second() const {
return second_;
}
private:
TypeA first_;
TypeB second_;
/**
* Disable assignment since references cannot be assigned.
*/
ZipPair &operator=(const ZipPair&);
};
/**
* Zip container for two iterators.
* This container allows zipping two iterators together, thus enabling them
* to be used in situations where only one iterator can be used. Any operation
* applied to the zip iterator will subsequently be applied to the contained
* iterators. Dereferencing the iterator will return a ZipPair containing the
* values referenced by the iterators.
* \notthreadsafe
* \note It is required that the two iterators have the same \c difference_type
* or that at least the first iterator's \c difference_type can be implicitly
* converted to the second iterator's \c difference_type. Moreover, when
* calculating the distance between two ZipIterators, the distances between both
* pairs of iterators are equal.
* \see ZipPair
* \tparam IteratorA First iterator
* \tparam IteratorB Second iterator
*/
template<typename IteratorA, typename IteratorB>
class ZipIterator{
public:
/**
* \name Iterator Typedefs
* Necessary typedefs for iterators (std compatibility).
* \{
*/
typedef std::random_access_iterator_tag iterator_category;
typedef typename std::iterator_traits<IteratorA>::difference_type
difference_type;
typedef typename std::iterator_traits<IteratorA>::reference RefA;
typedef typename std::iterator_traits<IteratorB>::reference RefB;
typedef typename std::iterator_traits<IteratorA>::value_type ValueA;
typedef typename std::iterator_traits<IteratorB>::value_type ValueB;
typedef ZipPair<ValueA, ValueB> value_type;
typedef ZipPair<RefA, RefB> reference;
typedef ZipPair<RefA, RefB> pointer;
/**
* \}
*/
/**
* Constructs a zip iterator from two iterators of any type.
*/
ZipIterator(
IteratorA iter_a,
/**< [IN] First iterator*/
IteratorB iter_b
/**< [IN] Second iterator*/
)
:iter_a_(iter_a), iter_b_(iter_b) {}
/**
* Compares two zip iterators for equality.
*
* \return \c true if zip iterators are equal, otherwise \c false
*/
bool operator==(
const ZipIterator &other
/**< [IN] Reference to right-hand side of equality operator */
) const {
return iter_a_ == other.iter_a_ && iter_b_ == other.iter_b_;
}
/**
* Compares two zip iterators for inequality.
*
* \return \c true if any iterator doesn't equal the other, otherwise \c false
*/
bool operator!=(
const ZipIterator &other
/**< [IN] Reference to right-hand side of inequality operator */
) const {
return iter_a_ != other.iter_a_ || iter_b_ != other.iter_b_;
}
/**
* Applies prefix increment on both iterators.
*/
void operator++() {
++iter_a_;
++iter_b_;
}
/**
* Applies prefix decrement on both iterators.
*/
void operator--() {
--iter_a_;
--iter_b_;
}
/**
* Returns an instance of a zip iterator where both iterators have been
* advanced by the specified distance.
*
* \return New zip iterator containing the advanced iterators
*/
ZipIterator<IteratorA, IteratorB> operator+(
difference_type distance
/**< [IN] Number of elements to advance the iterators */
) const {
ZipIterator<IteratorA, IteratorB> new_iterator(*this);
new_iterator.iter_a_ += distance;
new_iterator.iter_b_ += distance;
return new_iterator;
}
/**
* Returns an instance of a zip iterator where both iterators have been
* regressed by the specified distance.
*
* \return New zip iterator containing the regressed iterators
*/
ZipIterator<IteratorA, IteratorB> operator-(
difference_type distance
/**< [IN] Number of elements to regress the iterators */
) const {
ZipIterator<IteratorA, IteratorB> new_iterator(*this);
new_iterator.iter_a_ -= distance;
new_iterator.iter_b_ -= distance;
return new_iterator;
}
/**
* Advances both iterators by the specified distance.
*
* \return Reference to \c *this
*/
ZipIterator<IteratorA, IteratorB>& operator+=(
difference_type distance
/**< [IN] Number of elements to advance the iterators */
) {
iter_a_ += distance;
iter_b_ += distance;
return *this;
}
/**
* Regresses both iterators by the specified distance.
*
* \return Reference to \c *this
*/
ZipIterator<IteratorA, IteratorB>& operator-=(
difference_type distance
/**< [IN] Number of elements to regress the iterators */
) {
iter_a_ -= distance;
iter_b_ -= distance;
return *this;
}
/**
* Computes the distance between two zip iterators.
* It is assumed that both iterator pairs have the same distance.
*
* \return The distance between the zip iterators
*/
difference_type operator-(
const ZipIterator<IteratorA,
IteratorB> &other
/**< [IN] Reference to right-hand side of subtraction operator */
) const {
assert(iter_a_ - other.iter_a_ == iter_b_ - other.iter_b_);
return iter_a_ - other.iter_a_;
}
/**
* Dereferences the zip iterator.
*
* \return ZipPair containing the dereferenced values.
*/
reference operator*() const {
return ZipPair<RefA, RefB>(*iter_a_, *iter_b_);
}
private:
IteratorA iter_a_;
IteratorB iter_b_;
};
/**
* Creates a zip iterator from two iterators.
* This is a convenience function which avoids calling the constructor of the
* templated class.
*
* \return Constructed zip iterator
* \tparam IteratorA Type of first iterator
* \tparam IteratorB Type of second iterator
*/
template<typename IteratorA, typename IteratorB>
ZipIterator<IteratorA, IteratorB> Zip(
IteratorA iter_a,
/**< [IN] First iterator */
IteratorB iter_b
/**< [IN] Second iterator */
) {
return ZipIterator<IteratorA, IteratorB>(iter_a, iter_b);
}
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_ZIP_ITERATOR_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
void dummy_so_that_cmake_can_determinie_linker_language_for_algorithms() {
}
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <embb/algorithms/execution_policy.h>
namespace embb {
namespace algorithms {
ExecutionPolicy::ExecutionPolicy() :
affinity_(), priority_(DefaultPriority) {
}
ExecutionPolicy::ExecutionPolicy(bool initial_affinity, mtapi_uint_t priority)
:affinity_(initial_affinity), priority_(priority) {
}
ExecutionPolicy::ExecutionPolicy(mtapi_uint_t priority)
:affinity_(), priority_(priority) {
}
ExecutionPolicy::ExecutionPolicy(bool initial_affinity)
:affinity_(initial_affinity), priority_(DefaultPriority) {
}
void ExecutionPolicy::AddWorker(mtapi_uint_t worker) {
affinity_.Add(worker);
}
void ExecutionPolicy::RemoveWorker(mtapi_uint_t worker) {
affinity_.Remove(worker);
}
bool ExecutionPolicy::IsSetWorker(mtapi_uint_t worker) {
return affinity_.IsSet(worker);
}
const mtapi::Affinity &ExecutionPolicy::GetAffinity() const {
return affinity_;
}
mtapi_uint_t ExecutionPolicy::GetPriority() const {
return priority_;
}
const mtapi_uint_t ExecutionPolicy::DefaultPriority = 0;
} // namespace algorithms
} // namespace embb
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <count_test.h>
#include <embb/algorithms/count.h>
#include <embb/algorithms/execution_policy.h>
#include <deque>
#include <vector>
#include <functional>
struct IsEven{
bool operator()(int val) {
if (val % 2 == 0)
return true;
else
return false;
}
};
bool IsEvenFunction(int val) {
if (val % 2 == 0)
return true;
else
return false;
}
CountTest::CountTest() {
CreateUnit("Different data structures")
.Add(&CountTest::TestDataStructures, this);
CreateUnit("CountIf").Add(&CountTest::TestCountIf, this);
CreateUnit("Ranges").Add(&CountTest::TestRanges, this);
CreateUnit("Block sizes").Add(&CountTest::TestBlockSizes, this);
CreateUnit("Policies").Add(&CountTest::TestPolicy, this);
CreateUnit("Stress test").Add(&CountTest::StressTest, this);
}
void CountTest::TestDataStructures() {
using embb::algorithms::Count;
const int size =10;
int array[] = {10, 20, 30, 30, 20, 10, 10, 20, 20, 20};
std::vector<int> vector(array, array + size);
std::deque<int> deque(array, array + size);
const std::vector<int> const_vector(array, array + size);
PT_EXPECT_EQ(Count(array, array + size, 10), 3);
PT_EXPECT_EQ(Count(vector.begin(), vector.end(), 10), 3);
PT_EXPECT_EQ(Count(deque.begin(), deque.end(), 10), 3);
PT_EXPECT_EQ(Count(const_vector.begin(), const_vector.end(), 10), 3);
}
void CountTest::TestCountIf() {
using embb::algorithms::CountIf;
const int size =10;
int array[] = {10, 21, 30, 31, 20, 11, 10, 21, 20, 20};
PT_EXPECT_EQ(CountIf(array, array + size, IsEven()), 6);
PT_EXPECT_EQ(CountIf(array, array + size, &IsEvenFunction), 6);
}
void CountTest::TestRanges() {
using embb::algorithms::Count;
size_t count = 4;
std::vector<int> vector(count);
for (size_t i = 0; i < count; i++) {
vector[i] = static_cast<int>(-1);
}
// Ommit first element
PT_EXPECT_EQ(Count(vector.begin() + 1, vector.end(), -1), 3);
// Ommit last element
PT_EXPECT_EQ(Count(vector.begin(), vector.end() - 1, -1), 3);
// Ommit first and last element
PT_EXPECT_EQ(Count(vector.begin() + 1, vector.end() - 1, -1), 2);
// Only do first element
PT_EXPECT_EQ(Count(vector.begin(), vector.begin() + 1, -1), 1);
// Only do last element
PT_EXPECT_EQ(Count(vector.end() - 1, vector.end(), -1), 1);
// Only do second element
PT_EXPECT_EQ(Count(vector.begin() + 1, vector.begin() + 2, -1), 1);
}
void CountTest::TestBlockSizes() {
using embb::algorithms::Count;
size_t count = 4;
std::vector<int> vector(count);
for (size_t i = 0; i < count; i++) {
vector[i] = -1;
}
for (size_t block_size = 1; block_size < count + 2; block_size++) {
PT_EXPECT_EQ(Count(vector.begin(), vector.end(), -1),
static_cast<int>(count));
}
}
void CountTest::TestPolicy() {
using embb::algorithms::Count;
using embb::algorithms::ExecutionPolicy;
int a[] = { 10, 20, 30, 30, 20, 10, 10, 20, 20, 20 };
std::vector<int> vector(a, a + (sizeof a / sizeof a[0]));
PT_EXPECT_EQ(Count(vector.begin(), vector.end(), 10, ExecutionPolicy()), 3);
PT_EXPECT_EQ(Count(vector.begin(), vector.end(), 10, ExecutionPolicy(true)),
3);
PT_EXPECT_EQ(Count(vector.begin(), vector.end(), 10, ExecutionPolicy(false)),
3);
PT_EXPECT_EQ(Count(vector.begin(), vector.end(), 10,
ExecutionPolicy(true, 1)), 3);
}
void CountTest::StressTest() {
using embb::algorithms::Count;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10;
std::vector<int> large_vector(count);
for (size_t i = 0; i < count; i++) {
large_vector[i] = static_cast<int>(0);
}
PT_EXPECT_EQ(Count(large_vector.begin(), large_vector.end(), 0),
static_cast<int>(count));
}
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ALGORITHMS_CPP_TEST_COUNT_TEST_H_
#define ALGORITHMS_CPP_TEST_COUNT_TEST_H_
#include <partest/partest.h>
/**
* Provides tests for the Reduce method.
*/
class CountTest : public partest::TestCase {
public:
/**
* Creates test units.
*/
CountTest();
private:
/**
* Tests the compatibility with different data structures.
*/
void TestDataStructures();
/**
* Tests the count if functionality.
*/
void TestCountIf();
/**
* Tests setting various ranges to be iterated.
*/
void TestRanges();
/**
* Tests various block sizes for the workers.
*/
void TestBlockSizes();
/**
* Tests setting policies (without checking their actual execution).
*/
void TestPolicy();
/**
* Stress tests by giving work for all workers.
*/
void StressTest();
static const size_t kCountSize = 5;
};
#endif // ALGORITHMS_CPP_TEST_COUNT_TEST_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <for_each_test.h>
#include <embb/algorithms/for_each.h>
#include <embb/algorithms/execution_policy.h>
#include <vector>
#include <deque>
#include <sstream>
/**
* Functor to compute the square of a number.
*
* The result overwrites the original number.
*/
struct Square {
template<typename Type>
void operator()(Type& l) {
l = l * l;
}
};
/**
* Free function to compute the square of a number.
*
* The result overwrites the original number.
*/
static void SquareFunction(int &val) {
val = val * val;
}
ForEachTest::ForEachTest() {
CreateUnit("Different data structures")
.Add(&ForEachTest::TestDataStructures, this);
CreateUnit("Function Pointers").Add(&ForEachTest::TestFunctionPointers, this);
CreateUnit("Ranges").Add(&ForEachTest::TestRanges, this);
CreateUnit("Block sizes").Add(&ForEachTest::TestBlockSizes, this);
CreateUnit("Policies").Add(&ForEachTest::TestPolicy, this);
CreateUnit("Stress test").Add(&ForEachTest::StressTest, this);
}
void ForEachTest::TestDataStructures() {
using embb::algorithms::ForEach;
int array[kCountSize];
std::vector<int> vector(kCountSize);
std::deque<int> deque(kCountSize);
for (size_t i = 0; i < kCountSize; i++) {
array[i] = static_cast<int>(i+2);
vector[i] = static_cast<int>(i+2);
deque[i] = static_cast<int>(i+2);
}
ForEach(array, array + kCountSize, Square());
ForEach(vector.begin(), vector.end(), Square());
ForEach(deque.begin(), deque.end(), Square());
for (size_t i = 0; i < kCountSize; i++) {
int expected = static_cast<int>(i+2);
expected = expected * expected;
PT_EXPECT_EQ(expected, array[i]);
PT_EXPECT_EQ(expected, vector[i]);
PT_EXPECT_EQ(expected, deque[i]);
}
}
void ForEachTest::TestFunctionPointers() {
using embb::algorithms::ForEach;
std::vector<int> vector(kCountSize);
for (size_t i = 0; i < kCountSize; i++) {
vector[i] = static_cast<int>(i+2);
}
ForEach(vector.begin(), vector.end(), &SquareFunction);
for (size_t i = 0; i < kCountSize; i++) {
int expected = static_cast<int>(i+2);
expected = expected * expected;
PT_EXPECT_EQ(expected, vector[i]);
}
}
void ForEachTest::TestRanges() {
using embb::algorithms::ForEach;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
for (size_t i = 0; i < count; i++) {
init[i] = static_cast<int>(i+2);
}
// Ommit first element
vector = init;
ForEach(vector.begin() + 1, vector.end(), Square());
PT_EXPECT_EQ(vector[0], init[0]);
for (size_t i = 1; i < count; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]);
}
// Ommit last element
vector = init;
ForEach(vector.begin(), vector.end() - 1, Square());
for (size_t i = 0; i < count - 1; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]);
}
PT_EXPECT_EQ(vector[count - 1], init[count - 1]);
// Ommit first and last element
vector = init;
ForEach(vector.begin() + 1, vector.end() - 1, Square());
PT_EXPECT_EQ(vector[0], init[0]);
for (size_t i = 1; i < count - 1; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]);
}
PT_EXPECT_EQ(vector[count - 1], init[count - 1]);
// Only do first element
vector = init;
ForEach(vector.begin(), vector.begin() + 1, Square());
PT_EXPECT_EQ(vector[0], init[0] * init[0]);
for (size_t i = 1; i < count; i++) {
PT_EXPECT_EQ(vector[i], init[i]);
}
// Only do last element
vector = init;
ForEach(vector.end() - 1, vector.end(), Square());
for (size_t i = 0; i < count - 1; i++) {
PT_EXPECT_EQ(vector[i], init[i]);
}
PT_EXPECT_EQ(vector[count - 1], init[count - 1] * init[count - 1]);
// Only do second element
vector = init;
ForEach(vector.begin() + 1, vector.begin() + 2, Square());
for (size_t i = 1; i < count; i++) {
if (i != 1) {
PT_EXPECT_EQ(vector[i], init[i]);
} else {
PT_EXPECT_EQ(vector[i], init[i] * init[i]);
}
}
}
void ForEachTest::TestBlockSizes() {
using embb::algorithms::ForEach;
using embb::algorithms::ExecutionPolicy;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
for (size_t i = 0; i < count; i++) {
init[i] = static_cast<int>(i+2);
}
for (size_t block_size = 1; block_size < count + 2; block_size++) {
vector = init;
ForEach(vector.begin(), vector.end(), Square(), ExecutionPolicy(),
block_size);
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]);
}
}
}
void ForEachTest::TestPolicy() {
using embb::algorithms::ForEach;
using embb::algorithms::ExecutionPolicy;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
for (size_t i = 0; i < count; i++) {
init[i] = static_cast<int>(i+2);
}
vector = init;
ForEach(vector.begin(), vector.end(), Square(), ExecutionPolicy());
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]);
}
vector = init;
ForEach(vector.begin(), vector.end(), Square(), ExecutionPolicy(true));
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]);
}
vector = init;
ForEach(vector.begin(), vector.end(), Square(), ExecutionPolicy(false));
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]);
}
vector = init;
ForEach(vector.begin(), vector.end(), Square(), ExecutionPolicy(true, 1));
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]);
}
}
void ForEachTest::StressTest() {
using embb::algorithms::ForEach;
using embb::algorithms::ExecutionPolicy;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10;
std::vector<int> large_vector(count);
for (size_t i = 0; i < count; i++) {
large_vector[i] = static_cast<int>((i + 2) % 1000);
}
ForEach(large_vector.begin(), large_vector.end(), Square(), ExecutionPolicy(),
2000);
for (size_t i = 0; i < count; i++) {
int expected = static_cast<int>((i + 2) % 1000);
expected = expected * expected;
PT_EXPECT_EQ(large_vector[i], expected);
}
}
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ALGORITHMS_CPP_TEST_FOR_EACH_TEST_H_
#define ALGORITHMS_CPP_TEST_FOR_EACH_TEST_H_
#include <partest/partest.h>
/**
* Provides tests for the ForEach method.
*/
class ForEachTest : public partest::TestCase {
public:
/**
* Creates test units.
*/
ForEachTest();
private:
/**
* Tests the compatibility with different data structures.
*/
void TestDataStructures();
/**
* Tests the compatibility with function pointers.
*/
void TestFunctionPointers();
/**
* Tests setting various ranges to be iterated.
*/
void TestRanges();
/**
* Tests various block sizes for the workers.
*/
void TestBlockSizes();
/**
* Tests setting policies (without checking their actual execution).
*/
void TestPolicy();
/**
* Stress tests by giving work for all workers.
*/
void StressTest();
static const size_t kCountSize = 5;
};
#endif // ALGORITHMS_CPP_TEST_FOR_EACH_TEST_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <invoke_test.h>
#include <embb/algorithms/invoke.h>
InvokeTest::InvokeTest() {
CreateUnit("Preliminary").Add(&InvokeTest::Test, this);
}
static void Invocable1() {}
static void Invocable2() {}
static void Invocable3() {}
static void Invocable4() {}
static void Invocable5() {}
static void Invocable6() {}
static void Invocable7() {}
static void Invocable8() {}
static void Invocable9() {}
static void Invocable10() {}
void InvokeTest::Test() {
using embb::algorithms::Invoke;
Invoke(&Invocable1);
Invoke(&Invocable1, &Invocable2);
Invoke(&Invocable1, &Invocable2, &Invocable3);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, &Invocable8);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, &Invocable8, &Invocable9);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, &Invocable8, &Invocable9);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, &Invocable8, &Invocable9, &Invocable10);
}
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ALGORITHMS_CPP_TEST_INVOKE_TEST_H_
#define ALGORITHMS_CPP_TEST_INVOKE_TEST_H_
#include <partest/partest.h>
/**
* Provides tests for the Invoke method.
*/
class InvokeTest : public partest::TestCase {
public:
/**
* Creates test units.
*/
InvokeTest();
private:
/**
* Tests ...
*/
void Test();
};
#endif // ALGORITHMS_CPP_TEST_INVOKE_TEST_H_
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <partest/partest.h>
#include <embb/mtapi/mtapi.h>
#include <iostream>
#include <sstream>
#include <for_each_test.h>
#include <reduce_test.h>
#include <scan_test.h>
#include <count_test.h>
#include <partitioner_test.h>
#include <zip_iterator_test.h>
#include <quick_sort_test.h>
#include <merge_sort_test.h>
#include <invoke_test.h>
#include<embb/algorithms/merge_sort.h>
#include <vector>
#include <time.h>
#include <functional>
#define THIS_DOMAIN_ID 1
#define THIS_NODE_ID 1
int compute2_(int a) {
return a * 2;
}
int compute1_() {
return 5;
}
::std::string float_to_string(float val) {
std::stringstream s;
s << "Float: " << val;
return std::string(s.str());
}
PT_MAIN("Algorithms") {
embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
PT_RUN(PartitionerTest);
PT_RUN(ForEachTest);
PT_RUN(ReduceTest);
PT_RUN(ScanTest);
PT_RUN(CountTest);
PT_RUN(ZipIteratorTest);
PT_RUN(QuickSortTest);
PT_RUN(MergeSortTest);
PT_RUN(InvokeTest);
embb::mtapi::Node::Finalize();
// std::cout << "please press return to continue..." << std::endl;
// std::cin.get();
}
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <merge_sort_test.h>
#include <embb/algorithms/merge_sort.h>
#include <embb/algorithms/execution_policy.h>
#include <vector>
#include <deque>
#include <sstream>
#include <algorithm>
#include <functional>
static bool DescendingComparisonFunction(double lhs, double rhs) {
return lhs < rhs ? true : false;
}
MergeSortTest::MergeSortTest() {
CreateUnit("Different data structures")
.Add(&MergeSortTest::TestDataStructures, this);
CreateUnit("Function Pointers").Add(&MergeSortTest::TestFunctionPointers,
this);
CreateUnit("Ranges").Add(&MergeSortTest::TestRanges, this);
//CreateUnit("Block sizes").Add(&MergeSortTest::TestBlockSizes, this);
CreateUnit("Policies").Add(&MergeSortTest::TestPolicy, this);
CreateUnit("Stress test").Add(&MergeSortTest::StressTest, this);
}
void MergeSortTest::TestDataStructures() {
using embb::algorithms::MergeSortAllocate;
using embb::algorithms::ExecutionPolicy;
int array[kCountSize];
std::vector<int> vector(kCountSize);
std::deque<int> deque(kCountSize);
for (size_t i = 0; i < kCountSize; i++) {
array[i] = static_cast<int>(i+2);
vector[i] = static_cast<int>(i+2);
deque[i] = static_cast<int>(i+2);
}
std::vector<int> vector_copy(vector);
std::sort(vector_copy.begin(), vector_copy.end());
MergeSortAllocate(array, array + kCountSize);
MergeSortAllocate(vector.begin(), vector.end());
MergeSortAllocate(array, array + kCountSize, std::less<int>(),
ExecutionPolicy(), 0);
MergeSortAllocate(deque.begin(), deque.end());
for (size_t i = 0; i < kCountSize; i++) {
PT_EXPECT_EQ(vector_copy[i], array[i]);
PT_EXPECT_EQ(vector_copy[i], vector[i]);
PT_EXPECT_EQ(vector_copy[i], deque[i]);
}
}
void MergeSortTest::TestFunctionPointers() {
using embb::algorithms::MergeSortAllocate;
using embb::algorithms::ExecutionPolicy;
std::vector<int> vector(kCountSize);
for (size_t i = kCountSize - 1; i > 0; i--) {
vector[i] = static_cast<int>(i + 2);
}
std::vector<int> vector_copy(vector);
std::sort(vector_copy.begin(), vector_copy.end(),
&DescendingComparisonFunction);
MergeSortAllocate(vector.begin(), vector.end(),
&DescendingComparisonFunction);
for (size_t i = 0; i < kCountSize; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
}
void MergeSortTest::TestRanges() {
using embb::algorithms::MergeSortAllocate;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
std::vector<int> vector_copy(count);
for (size_t i = count - 1; i > 0; i--) {
init[i] = static_cast<int>(i+2);
}
// Ommit first element
vector = init;
vector_copy = init;
std::sort(vector_copy.begin() + 1, vector_copy.end());
MergeSortAllocate(vector.begin() + 1, vector.end());
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
// Ommit last element
vector = init;
vector_copy = init;
std::sort(vector_copy.begin(), vector_copy.end() - 1);
MergeSortAllocate(vector.begin(), vector.end() - 1);
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
// Ommit first and last element
vector = init;
vector_copy = init;
std::sort(vector_copy.begin() + 1, vector_copy.end() - 1);
MergeSortAllocate(vector.begin() + 1, vector.end() - 1);
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
// Only do first two elements
vector = init;
vector_copy = init;
std::sort(vector_copy.begin(), vector_copy.begin() + 2);
MergeSortAllocate(vector.begin(), vector.begin() + 2);
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
// Only do last two elements
vector = init;
vector_copy = init;
std::sort(vector_copy.end() - 2, vector_copy.end());
MergeSortAllocate(vector.end() - 2, vector.end());
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
// Only do second & third elements
vector = init;
vector_copy = init;
std::sort(vector_copy.begin() + 1, vector_copy.begin() + 3);
MergeSortAllocate(vector.begin() + 1, vector.begin() + 3);
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
}
//void MergeSortTest::TestBlockSizes() {
// using embb::algorithms::MergeSortAllocate;
// using embb::algorithms::ExecutionPolicy;
// size_t count = 4;
// std::vector<int> init(count);
// std::vector<int> vector(count);
// std::vector<int> vector_copy(count);
// for (size_t i = count - 1; i > 0; i--) {
// init[i] = static_cast<int>(i+2);
// }
// vector_copy = init;
// std::sort(vector_copy.begin(), vector_copy.end());
//
// for (size_t block_size = 1; block_size < count + 2; block_size++) {
// vector = init;
// MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
// ExecutionPolicy(), block_size);
// for (size_t i = 0; i < count; i++) {
// PT_EXPECT_EQ(vector[i], vector_copy[i]);
// }
// }
//}
void MergeSortTest::TestPolicy() {
using embb::algorithms::MergeSortAllocate;
using embb::algorithms::ExecutionPolicy;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
std::vector<int> vector_copy(count);
for (size_t i = count - 1; i > 0; i--) {
init[i] = static_cast<int>(i+2);
}
vector = init;
vector_copy = init;
std::sort(vector_copy.begin(), vector_copy.end());
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy());
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
vector = init;
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(true));
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
vector = init;
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(false));
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
vector = init;
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(true, 1));
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
}
void MergeSortTest::StressTest() {
using embb::algorithms::MergeSortAllocate;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count);
std::vector<int> vector_copy(count);
for (size_t i = count - 1; i > 0; i--) {
large_vector[i] = static_cast<int>((i + 2) % 1000);
}
vector_copy = large_vector;
std::sort(vector_copy.begin(), vector_copy.end());
MergeSortAllocate(large_vector.begin(), large_vector.end());
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(large_vector[i], vector_copy[i]);
}
}
/*
* Copyright (c) 2014, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ALGORITHMS_CPP_TEST_MERGE_SORT_TEST_H_
#define ALGORITHMS_CPP_TEST_MERGE_SORT_TEST_H_
#include <partest/partest.h>
/**
* Provides tests for the QuickSort method.
*/
class MergeSortTest : public partest::TestCase {
public:
/**
* Creates test units.
*/
MergeSortTest();
private:
/**
* Tests the compatibility with different data structures.
*/
void TestDataStructures();
/**
* Tests the compatibility with function pointers.
*/
void TestFunctionPointers();
/**
* Tests setting various ranges to be iterated.
*/
void TestRanges();
/**
* Tests various block sizes for the workers.
*/
//void TestBlockSizes();
/**
* Tests setting policies (without checking their actual execution).
*/
void TestPolicy();
/**
* Stress tests by giving work for all workers.
*/
void StressTest();
static const size_t kCountSize = 5;
};
#endif // ALGORITHMS_CPP_TEST_MERGE_SORT_TEST_H_
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment