Commit dd88ea03 by Michael Schmid

first commit

parents
# Copyright (c) 2014-2016, 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-2016, 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
)
add_custom_command(
TARGET ${bin}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${bin}> ${destination}
)
endfunction()
# Copyright (c) 2014-2016, 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()
FILE(WRITE ${CMAKE_BINARY_DIR}/doxygen_makefile.cmake "
MESSAGE(STATUS \"Running Doxygen\")
EXECUTE_PROCESS(
COMMAND \${EXE} \${IN}
ERROR_VARIABLE DOXYGEN_OUT_ERR
RESULT_VARIABLE DOXYGEN_OUT_RESULT)
STRING(LENGTH \"\${DOXYGEN_OUT_ERR}\" LENGTH_ERR)
IF ( NOT \${LENGTH_ERR} STREQUAL \"0\" )
MESSAGE (WARNING \"Doxygen produced following warnings and or/errors: \${DOXYGEN_OUT_ERR}\")
IF ( \${WARNINGS_ARE_ERRORS} STREQUAL ON OR NOT \${DOXYGEN_OUT_RESULT} STREQUAL \"0\" )
MESSAGE (FATAL_ERROR \"Exiting doxygen generation due to errors (or warnings, if WARNINGS_ARE_ERRORS is enabled)\")
ENDIF ()
ENDIF ()
")
add_custom_target(doxygen)
add_custom_command(
TARGET doxygen
COMMAND ${CMAKE_COMMAND}
-DEXE=${DOXYGEN_EXECUTABLE}
-DIN=${PROJECT_BINARY_DIR}/Doxyfile
-DWARNINGS_ARE_ERRORS=${WARNINGS_ARE_ERRORS}
-P ${CMAKE_BINARY_DIR}/doxygen_makefile.cmake)
endif()
endif()
endfunction()
# Taken from CMake Version 3.2.1, modified to work on older versions
#.rst:
# FindOpenCL
# ----------
#
# Try to find OpenCL
#
# Once done this will define::
#
# OpenCL_FOUND - True if OpenCL was found
# OpenCL_INCLUDE_DIRS - include directories for OpenCL
# OpenCL_LIBRARIES - link against this library to use OpenCL
# OpenCL_VERSION_STRING - Highest supported OpenCL version (eg. 1.2)
# OpenCL_VERSION_MAJOR - The major version of the OpenCL implementation
# OpenCL_VERSION_MINOR - The minor version of the OpenCL implementation
#
# The module will also define two cache variables::
#
# OpenCL_INCLUDE_DIR - the OpenCL include directory
# OpenCL_LIBRARY - the path to the OpenCL library
#
#=============================================================================
# Copyright 2014 Matthaeus G. Chajdas
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
function(_FIND_OPENCL_VERSION)
include(CheckSymbolExists)
include(CMakePushCheckState)
set(CMAKE_REQUIRED_QUIET ${OpenCL_FIND_QUIETLY})
CMAKE_PUSH_CHECK_STATE()
foreach(VERSION "2_0" "1_2" "1_1" "1_0")
set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}")
if(APPLE)
CHECK_SYMBOL_EXISTS(
CL_VERSION_${VERSION}
"${OpenCL_INCLUDE_DIR}/OpenCL/cl.h"
OPENCL_VERSION_${VERSION})
else()
CHECK_SYMBOL_EXISTS(
CL_VERSION_${VERSION}
"${OpenCL_INCLUDE_DIR}/CL/cl.h"
OPENCL_VERSION_${VERSION})
endif()
if(OPENCL_VERSION_${VERSION})
string(REPLACE "_" "." VERSION "${VERSION}")
set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE)
string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}")
list(GET version_components 0 major_version)
list(GET version_components 1 minor_version)
set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE)
set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE)
break()
endif()
endforeach()
CMAKE_POP_CHECK_STATE()
endfunction()
find_path(OpenCL_INCLUDE_DIR
NAMES
CL/cl.h OpenCL/cl.h
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV INTELOCLSDKROOT
ENV NVSDKCOMPUTE_ROOT
ENV CUDA_PATH
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
include
OpenCL/common/inc
"AMD APP/include")
_FIND_OPENCL_VERSION()
if(WIN32)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
find_library(OpenCL_LIBRARY
NAMES OpenCL
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV INTELOCLSDKROOT
ENV CUDA_PATH
ENV NVSDKCOMPUTE_ROOT
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
"AMD APP/lib/x86"
lib/x86
lib/Win32
OpenCL/common/lib/Win32)
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
find_library(OpenCL_LIBRARY
NAMES OpenCL
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV INTELOCLSDKROOT
ENV CUDA_PATH
ENV NVSDKCOMPUTE_ROOT
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
"AMD APP/lib/x86_64"
lib/x86_64
lib/x64
OpenCL/common/lib/x64)
endif()
else()
find_library(OpenCL_LIBRARY
NAMES OpenCL)
endif()
set(OpenCL_LIBRARIES ${OpenCL_LIBRARY})
set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR})
#find_package_handle_standard_args not available in older CMake versions...
#include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
#find_package_handle_standard_args(
# OpenCL
# FOUND_VAR OpenCL_FOUND
# REQUIRED_VARS OpenCL_LIBRARY OpenCL_INCLUDE_DIR
# VERSION_VAR OpenCL_VERSION_STRING)
#mark_as_advanced(
# OpenCL_INCLUDE_DIR
# OpenCL_LIBRARY)
# This replaces FindPackageHandleStandardArgs.cmake, which is not available in older
# CMake versions
if( OpenCL_LIBRARIES AND OpenCL_INCLUDE_DIRS )
set(OpenCL_FOUND 1)
else()
set(OpenCL_FOUND 0)
endif()
# Copyright (c) 2014-2016, 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-2016, 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)
set(CMAKE_C_FLAGS_COVERAGE
"${CMAKE_C_FLAGS_COVERAGE} -O0 -fprofile-arcs -ftest-coverage"
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)
set(CMAKE_CXX_FLAGS_COVERAGE
"${CMAKE_CXX_FLAGS_COVERAGE} -O0 -fprofile-arcs -ftest-coverage"
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.
#
# VS 2015 specific warnings:
# 5026 -> Move constructor was implicitly defined as deleted
# 5027 -> Move assignment operator was implicitly defined as deleted
#
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()
string(FIND "${CMAKE_GENERATOR}" "Visual Studio 14 2015" vs2015_state)
if (vs2015_state EQUAL 0)
set(warning_flags "${warning_flags} /wd5026 /wd5027")
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-2016, 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(WIN32)
if (DEFINED INSTALL_PREFIX)
# User given install path given when calling cmake as "-DINSTALL_PREFIX=...".
set(CMAKE_INSTALL_PREFIX ${INSTALL_PREFIX})
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}")
endif()
set(INSTALL_PREFIX_DOCS "${CMAKE_INSTALL_PREFIX}/doc")
#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} )
else()
if (DEFINED INSTALL_PREFIX)
# User given install path given when calling cmake as "-DINSTALL_PREFIX=...".
set(CMAKE_INSTALL_PREFIX ${INSTALL_PREFIX})
else()
set(CMAKE_INSTALL_PREFIX "/usr/local")
endif()
set(INSTALL_PREFIX_DOCS "${CMAKE_INSTALL_PREFIX}/share/doc/${CMAKE_PROJECT_NAME}-${EMBB_BASE_VERSION_MAJOR}.${EMBB_BASE_VERSION_MINOR}.${EMBB_BASE_VERSION_PATCH}")
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-2016, 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 4)
set (EMBB_BASE_VERSION_PATCH 0)
# Fix compilation for CMake versions >= 3.1
#
# New Policy 0054:
# CMake 3.1 and above no longer implicitly dereference variables
# or interpret keywords in an if() command argument when it is a
# Quoted Argument.
# See http://www.cmake.org/cmake/help/v3.1/policy/CMP0054.html
#
# New Policy 0053:
# CMake 3.1 introduced faster implementation of evaluation of the
# Variable References and Escape Sequences. This breaks compilation
# here.
# See http://www.cmake.org/cmake/help/v3.1/policy/CMP0053.html
#
# Set those policies to be treated the legacy (CMake < 3.1) way.
if(POLICY CMP0054)
cmake_policy(SET CMP0054 OLD)
endif(POLICY CMP0054)
if(POLICY CMP0053)
cmake_policy(SET CMP0053 OLD)
endif(POLICY CMP0053)
# give the user the possibility, to append compiler flags
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CMAKE_CXX_FLAGS}")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CMAKE_C_FLAGS}")
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build, options are: Debug Release
RelWithDebInfo MinSizeRel Coverage." FORCE)
endif(NOT CMAKE_BUILD_TYPE)
# Check for clang, masquerade it as GNU
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_COMPILER_IS_GNUCC true)
endif ()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_COMPILER_IS_GNUCXX true)
endif()
## 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)
option(USE_AUTOMATIC_INITIALIZATION "Specify whether the MTAPI C++ interface, algorithms and dataflow should automatically intialize the MTAPI node if no explicit initialization is present" ON)
option(BUILD_OPENCL_PLUGIN "Specify whether the MTAPI OpenCL plugin should be built" 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)")
if (USE_AUTOMATIC_INITIALIZATION STREQUAL ON)
message("-- MTAPI/Tasks automatic initialization enabled (default)")
else()
message("-- MTAPI/Tasks automatic initialization disabled")
endif()
message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=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)")
# these are the test executables, we expect to be generated.
set(EXPECTED_EMBB_TEST_EXECUTABLES "embb_algorithms_cpp_test"
"embb_base_c_test"
"embb_base_cpp_test"
"embb_containers_cpp_test"
"embb_dataflow_cpp_test"
"embb_mtapi_c_test"
"embb_mtapi_cpp_test"
"embb_mtapi_network_c_test"
"embb_tasks_cpp_test"
)
# if opencl is there, we also expect the mtapi opencl test to be generated
if(BUILD_OPENCL_PLUGIN STREQUAL ON)
list(APPEND EXPECTED_EMBB_TEST_EXECUTABLES "embb_mtapi_opencl_c_test")
endif()
## 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_unix.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()
CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/scripts/${test_script_in}.cmake 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_plugins_c/mtapi_network_c)
if(BUILD_OPENCL_PLUGIN STREQUAL ON)
add_subdirectory(mtapi_plugins_c/mtapi_opencl_c)
endif()
add_subdirectory(tasks_cpp)
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
#
if(EXISTS "${EMBB_SOURCE_DIR}/doc/reference/Doxyfile.in")
include(CMakeCommon/CreateDoxygenDocumentationTarget.cmake)
CreateDoxygenDocumentationTarget()
endif()
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 one is important
SET(CMAKE_SYSTEM_NAME Generic)
#this one not so much
SET(CMAKE_SYSTEM_VERSION 1)
SET(CMAKE_SYSTEM_PROCESSOR TriCore)
# specify the cross compiler
SET(CMAKE_C_COMPILER C:/HighTec/toolchains/tricore/v4.6.6.0-infineon-1.1/bin/tricore-gcc.exe)
SET(CMAKE_CXX_COMPILER C:/HighTec/toolchains/tricore/v4.6.6.0-infineon-1.1/bin/tricore-g++.exe)
# where is the target environment
SET(CMAKE_FIND_ROOT_PATH C:/HighTec/toolchains/tricore/v4.6.6.0-infineon-1.1)
# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
\ No newline at end of file
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(${CMAKE_SOURCE_DIR}/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}/../tasks_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../tasks_cpp/include)
add_library(embb_algorithms_cpp ${EMBB_ALGORITHMS_CPP_SOURCES}
${EMBB_ALGORITHMS_CPP_HEADERS})
target_link_libraries(embb_algorithms_cpp embb_tasks_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_tasks_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-2016, 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/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-2016, 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/tasks/execution_policy.h>
#include <iterator>
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(), embb::mtapi::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 embb::mtapi::ExecutionPolicy& policy = embb::mtapi::ExecutionPolicy(),
/**< [IN] embb::mtapi::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(), embb::mtapi::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 embb::mtapi::ExecutionPolicy& policy = embb::mtapi::ExecutionPolicy(),
/**< [IN] embb::mtapi::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.
*/
template<typename RAI, typename ValueType>
typename std::iterator_traits<RAI>::difference_type Count(
RAI first,
RAI last,
const ValueType& value,
const embb::tasks::ExecutionPolicy& policy,
size_t block_size
);
/**
* 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, embb::tasks::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 embb::tasks::ExecutionPolicy& policy
) {
return Count(first, last, value, 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 embb::tasks::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, embb::tasks::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 embb::tasks::ExecutionPolicy& policy
) {
return CountIf(first, last, comparison, policy, 0);
}
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include <embb/algorithms/internal/count-inl.h>
#endif // EMBB_ALGORITHMS_COUNT_H_
/*
* Copyright (c) 2014-2016, 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/tasks/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 embb::mtapi::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 embb::mtapi::ExecutionPolicy& policy = embb::mtapi::ExecutionPolicy(),
/**< [IN] embb::mtapi::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.
*/
template<typename RAI, typename Function>
void ForEach(
RAI first,
RAI last,
Function unary,
const embb::tasks::ExecutionPolicy& policy,
size_t block_size
);
/**
* 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, embb::tasks::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 embb::tasks::ExecutionPolicy& policy
) {
ForEach(first, last, unary, policy, 0);
}
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include <embb/algorithms/internal/for_each-inl.h>
#endif // EMBB_ALGORITHMS_FOR_EACH_H_
/*
* Copyright (c) 2014-2016, 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
*/
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-2016, 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 embb::tasks::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 embb::tasks::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-2016, 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/tasks/tasks.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(size_t chunk_first, size_t chunk_last, Function unary,
const embb::tasks::ExecutionPolicy& policy,
const BlockSizePartitioner<RAI>& partitioner)
: chunk_first_(chunk_first), chunk_last_(chunk_last),
unary_(unary), policy_(policy), partitioner_(partitioner) {
}
void Action(embb::tasks::TaskContext&) {
if (chunk_first_ == chunk_last_) {
// Leaf case, recursed to single chunk. Do work on chunk:
ChunkDescriptor<RAI> chunk = partitioner_[chunk_first_];
RAI first = chunk.GetFirst();
RAI last = chunk.GetLast();
for (RAI it = first; it != last; ++it) {
unary_(*it);
}
} else {
// Recurse further:
size_t chunk_split_index = (chunk_first_ + chunk_last_) / 2;
// Split chunks into left / right branches:
self_t functor_l(chunk_first_,
chunk_split_index,
unary_, policy_, partitioner_);
self_t functor_r(chunk_split_index + 1,
chunk_last_,
unary_, policy_, partitioner_);
embb::tasks::Task task_l = embb::tasks::Node::GetInstance().Spawn(
embb::tasks::Action(
base::MakeFunction(functor_l, &self_t::Action),
policy_));
embb::tasks::Task task_r = embb::tasks::Node::GetInstance().Spawn(
embb::tasks::Action(
base::MakeFunction(functor_r, &self_t::Action),
policy_));
task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
}
}
private:
typedef ForEachFunctor<RAI, Function> self_t;
private:
size_t chunk_first_;
size_t chunk_last_;
Function unary_;
const embb::tasks::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_;
/**
* Disables assignment.
*/
ForEachFunctor& operator=(const ForEachFunctor&);
};
template<typename RAI, typename Function>
void ForEachRecursive(RAI first, RAI last, Function unary,
const embb::tasks::ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last);
if (distance == 0) {
return;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for ForEach");
}
unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) {
EMBB_THROW(embb::base::ErrorException, "No cores in execution policy");
}
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
// Determine actually used block size
if (block_size == 0) {
block_size = (static_cast<size_t>(distance) / num_cores);
if (block_size == 0) {
block_size = 1;
}
}
// Check task number sufficiency
if (((distance / block_size) * 2) + 1 > MTAPI_NODE_MAX_TASKS_DEFAULT) {
EMBB_THROW(embb::base::ErrorException,
"Not enough MTAPI tasks available for parallel foreach");
}
BlockSizePartitioner<RAI> partitioner(first, last, block_size);
ForEachFunctor<RAI, Function> functor(0,
partitioner.Size() - 1,
unary, policy, partitioner);
embb::tasks::Task task = node.Spawn(embb::tasks::Action(
base::MakeFunction(functor,
&ForEachFunctor<RAI, Function>::Action),
policy));
task.Wait(MTAPI_INFINITE);
}
template<typename RAI, typename Function>
void ForEachIteratorCheck(RAI first, RAI last, Function unary,
const embb::tasks::ExecutionPolicy& policy, size_t block_size,
std::random_access_iterator_tag) {
return ForEachRecursive(first, last, unary, policy, block_size);
}
} // namespace internal
template<typename RAI, typename Function>
void ForEach(RAI first, const RAI last, Function unary,
const embb::tasks::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-2016, 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 RAI>
ChunkDescriptor<RAI>::ChunkDescriptor(
RAI first, RAI last) :
first_(first), last_(last) {
}
template<typename RAI>
RAI ChunkDescriptor<RAI>::GetFirst() const {
return first_;
}
template<typename RAI>
RAI ChunkDescriptor<RAI>::GetLast() const {
return last_;
}
template<typename RAI>
BlockSizePartitioner<RAI>::BlockSizePartitioner(
RAI first, RAI last, size_t chunkSize) :
first_(first), last_(last), chunk_size_(chunkSize) {
elements_count_ = static_cast<size_t>(std::distance(first_, last_));
chunks_ = elements_count_ / chunk_size_;
if (elements_count_ % chunk_size_ != 0) {
chunks_++;
}
}
template<typename RAI>
size_t BlockSizePartitioner<RAI>::Size() {
return chunks_;
}
template<typename RAI>
const ChunkDescriptor<RAI>
BlockSizePartitioner<RAI>::operator[](
size_t const & index) const {
typedef typename std::iterator_traits<RAI>::difference_type
difference_type;
RAI first_new(first_);
first_new += static_cast<difference_type>(chunk_size_ * index);
RAI last_new(first_new);
if (index >= chunks_ - 1) {
last_new = last_;
} else {
last_new += static_cast<difference_type>(chunk_size_);
}
return ChunkDescriptor<RAI>(first_new, last_new);
}
template<typename RAI>
size_t ChunkPartitioner<RAI>::Size() {
return size_;
}
template<typename RAI>
ChunkPartitioner<RAI>::ChunkPartitioner(
RAI first, RAI 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
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
size_ = node.GetWorkerThreadCount();
}
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 RAI>
const ChunkDescriptor<RAI>
ChunkPartitioner<RAI>::operator[](
size_t const& index) const {
typedef typename std::iterator_traits<RAI>::difference_type
difference_type;
// Number of element preceding elements in the given chunk
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_;
RAI first_new(first_);
first_new += static_cast<difference_type>(prec_elements_count);
RAI last_new(first_new);
last_new += static_cast<difference_type>(cur_elements_count);
return ChunkDescriptor<RAI>(first_new, last_new);
}
} // namespace internal
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_INTERNAL_PARTITION_INL_H_
/*
* Copyright (c) 2014-2016, 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/tasks/tasks.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 RAI Type of the iterator.
*/
template<typename RAI>
class ChunkDescriptor {
private:
RAI first_;
RAI last_;
public:
/**
* Constructor.
*
* \param first The first iterator.
* \param last The last iterator
*/
ChunkDescriptor(RAI first, RAI last);
/**
* Gets the first iterator.
*
* \return The first iterator.
*
* \waitfree
*/
RAI GetFirst() const;
/**
* Gets the last iterator.
*
* \return The last iterator.
*
* \waitfree
*/
RAI GetLast() const;
};
/**
* Partitioner Interface.
*
* Describes the interface for accessing a 1-dimensional partitioning.
*
* \tparam RAI Type of the iterator.
*/
template<typename RAI>
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<RAI> 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 RAI Type of the iterator.
*/
template<typename RAI>
class BlockSizePartitioner : IPartitioner < RAI > {
private:
RAI first_;
RAI last_;
size_t chunk_size_;
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(
RAI first, RAI last, size_t chunkSize = 1);
/**
* See IPartitioner
*
* \waitfree
*/
virtual size_t Size();
/**
* See IPartitioner
*
* \waitfree
*/
virtual const ChunkDescriptor<RAI> 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 RAI Type of the iterator.
*/
template<typename RAI>
class ChunkPartitioner : IPartitioner < RAI > {
private:
size_t size_;
size_t elements_count_;
RAI first_;
RAI 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(RAI first, RAI last,
size_t amountChunks = 0);
/**
* See IPartitioner
*
* \waitfree
*/
virtual const ChunkDescriptor<RAI> 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-2016, 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/tasks/tasks.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 embb::tasks::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(embb::tasks::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 {
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
QuickSortFunctor functor_l(first_, mid, comparison_, policy_,
block_size_);
embb::tasks::Task task_l = node.Spawn(embb::tasks::Action(
base::MakeFunction(functor_l, &QuickSortFunctor::Action)));
QuickSortFunctor functor_r(mid, last_, comparison_, policy_,
block_size_);
embb::tasks::Task task_r = node.Spawn(embb::tasks::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 embb::tasks::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&);
};
template <typename RAI, typename ComparisonFunction>
void QuickSortIteratorCheck(RAI first, RAI last,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy,
size_t block_size,
std::random_access_iterator_tag) {
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last);
if (distance == 0) {
return;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for QuickSort");
}
unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) {
EMBB_THROW(embb::base::ErrorException, "No cores in execution policy");
}
if (block_size == 0) {
block_size = (static_cast<size_t>(distance) / num_cores);
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");
}
QuickSortFunctor<RAI, ComparisonFunction> functor(
first, last, comparison, policy, block_size);
embb::tasks::Task task = node.Spawn(embb::tasks::Action(base::MakeFunction(
functor, &QuickSortFunctor<RAI, ComparisonFunction>::Action)));
task.Wait(MTAPI_INFINITE);
}
} // namespace internal
template <typename RAI, typename ComparisonFunction>
void QuickSort(RAI first, RAI last, ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::iterator_category category;
internal::QuickSortIteratorCheck(first, last, comparison,
policy, block_size, category());
}
} // namespace algorithms
} // namespace embb
#endif // EMBB_ALGORITHMS_INTERNAL_QUICK_SORT_INL_H_
/*
* Copyright (c) 2014-2016, 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/tasks/tasks.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(size_t chunk_first, size_t chunk_last,
ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
const BlockSizePartitioner<RAI>& partitioner,
ReturnType& result)
: chunk_first_(chunk_first), chunk_last_(chunk_last), neutral_(neutral),
reduction_(reduction), transformation_(transformation), policy_(policy),
partitioner_(partitioner), result_(result) {
}
void Action(embb::tasks::TaskContext&) {
if (chunk_first_ == chunk_last_) {
// Leaf case, recursed to single chunk. Do work on chunk:
ChunkDescriptor<RAI> chunk = partitioner_[chunk_first_];
RAI first = chunk.GetFirst();
RAI last = chunk.GetLast();
ReturnType result(neutral_);
for (RAI it = first; it != last; ++it) {
result = reduction_(result, transformation_(*it));
}
result_ = result;
} else {
// Recurse further:
size_t chunk_split_index = (chunk_first_ + chunk_last_) / 2;
// Split chunks into left / right branches:
ReturnType result_l(neutral_);
ReturnType result_r(neutral_);
self_t functor_l(chunk_first_,
chunk_split_index,
neutral_, reduction_, transformation_, policy_,
partitioner_,
result_l);
self_t functor_r(chunk_split_index + 1,
chunk_last_,
neutral_, reduction_, transformation_, policy_,
partitioner_,
result_r);
embb::tasks::Task task_l = embb::tasks::Node::GetInstance().Spawn(
embb::tasks::Action(
base::MakeFunction(
functor_l, &self_t::Action),
policy_));
embb::tasks::Task task_r = embb::tasks::Node::GetInstance().Spawn(
embb::tasks::Action(
base::MakeFunction(
functor_r, &self_t::Action),
policy_));
task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE);
result_ = reduction_(result_l, result_r);
}
}
private:
typedef ReduceFunctor<RAI, ReturnType,
ReductionFunction,
TransformationFunction> self_t;
private:
size_t chunk_first_;
size_t chunk_last_;
ReturnType neutral_;
ReductionFunction reduction_;
TransformationFunction transformation_;
const embb::tasks::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_;
ReturnType& result_;
/**
* Disables assignment and copy-construction.
*/
ReduceFunctor& operator=(const ReduceFunctor&);
ReduceFunctor(const ReduceFunctor&);
};
template<typename RAI, typename ReturnType, typename ReductionFunction,
typename TransformationFunction>
ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last);
if (distance == 0) {
return neutral;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for Reduce");
}
unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) {
EMBB_THROW(embb::base::ErrorException, "No cores in execution policy");
}
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
// Determine actually used block size
if (block_size == 0) {
block_size = (static_cast<size_t>(distance) / num_cores);
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,
"Number of computation tasks required in reduction would "
"exceed MTAPI maximum number of tasks");
}
typedef ReduceFunctor<RAI, ReturnType, ReductionFunction,
TransformationFunction> Functor;
BlockSizePartitioner<RAI> partitioner(first, last, block_size);
ReturnType result = neutral;
Functor functor(0,
partitioner.Size() - 1,
neutral,
reduction, transformation,
policy,
partitioner,
result);
embb::tasks::Task task = node.Spawn(
embb::tasks::Action(base::MakeFunction(
functor, &Functor::Action), policy));
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 embb::tasks::ExecutionPolicy& policy,
size_t block_size,
std::random_access_iterator_tag) {
return ReduceRecursive(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 embb::tasks::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-2016, 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/tasks/tasks.h>
#include <embb/tasks/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(size_t chunk_first, size_t chunk_last, RAIOut output_iterator,
ReturnType neutral, ScanFunction scan,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
const BlockSizePartitioner<RAIIn>& partitioner,
ReturnType* tree_values, size_t node_id,
bool going_down)
: policy_(policy), chunk_first_(chunk_first), chunk_last_(chunk_last),
output_iterator_(output_iterator), scan_(scan),
transformation_(transformation),
neutral_(neutral), partitioner_(partitioner), tree_values_(tree_values),
node_id_(node_id), parent_value_(neutral), is_first_pass_(going_down) {
}
void Action(embb::tasks::TaskContext&) {
if (chunk_first_ == chunk_last_) {
ChunkDescriptor<RAIIn> chunk = partitioner_[chunk_first_];
RAIIn iter_in = chunk.GetFirst();
RAIIn last_in = chunk.GetLast();
RAIOut iter_out = output_iterator_;
// leaf case -> do work
if (is_first_pass_) {
ReturnType result = transformation_(*iter_in);
*iter_out = result;
++iter_in;
++iter_out;
for (; iter_in != last_in; ++iter_in, ++iter_out) {
result = scan_(result, transformation_(*iter_in));
*iter_out = result;
}
SetTreeValue(result);
} else {
// Second pass
for (; iter_in != last_in; ++iter_in, ++iter_out) {
*iter_out = scan_(parent_value_, *iter_out);
}
}
} else {
// recurse further
size_t chunk_split_index = (chunk_first_ + chunk_last_) / 2;
// Split chunks into left / right branches:
ScanFunctor functor_l(
chunk_first_, chunk_split_index,
output_iterator_, neutral_, scan_, transformation_,
policy_, partitioner_, tree_values_, node_id_,
is_first_pass_);
ScanFunctor functor_r(
chunk_split_index + 1, chunk_last_,
output_iterator_, neutral_, scan_, transformation_,
policy_, partitioner_, tree_values_, node_id_,
is_first_pass_);
functor_l.SetID(LEFT);
functor_r.SetID(RIGHT);
// Advance output iterator of right branch:
ChunkDescriptor<RAIIn> chunk_left = partitioner_[chunk_first_];
ChunkDescriptor<RAIIn> chunk_right = partitioner_[chunk_split_index + 1];
std::advance(functor_r.output_iterator_,
std::distance(chunk_left.GetFirst(), chunk_right.GetFirst()));
if (!is_first_pass_) {
functor_l.parent_value_ = parent_value_;
functor_r.parent_value_ = functor_l.GetTreeValue() + parent_value_;
}
// Spawn tasks to recurse:
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
embb::tasks::Task task_l = node.Spawn(
embb::tasks::Action(
base::MakeFunction(functor_l, &ScanFunctor::Action),
policy_));
embb::tasks::Task task_r = node.Spawn(
embb::tasks::Action(
base::MakeFunction(functor_r, &ScanFunctor::Action),
policy_));
// Wait for tasks to complete:
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:
static const int LEFT = 1;
static const int RIGHT = 2;
const embb::tasks::ExecutionPolicy& policy_;
size_t chunk_first_;
size_t chunk_last_;
RAIOut output_iterator_;
ScanFunction scan_;
TransformationFunction transformation_;
ReturnType neutral_;
const BlockSizePartitioner<RAIIn>& partitioner_;
ReturnType* tree_values_;
size_t node_id_;
ReturnType parent_value_;
bool is_first_pass_;
void SetID(int branch) {
if (branch == LEFT) {
node_id_ = 2 * node_id_ + 1;
} else if (branch == RIGHT) {
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 embb::tasks::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;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for Scan");
}
unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) {
EMBB_THROW(embb::base::ErrorException, "No cores in execution policy");
}
ReturnType values[MTAPI_NODE_MAX_TASKS_DEFAULT];
if (block_size == 0) {
block_size = static_cast<size_t>(distance) / num_cores;
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 parallel scan");
}
// first pass. Calculates prefix sums for leaves and when recursion returns
// it creates the tree.
typedef ScanFunctor<RAIIn, RAIOut, ReturnType, ScanFunction,
TransformationFunction> Functor;
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
BlockSizePartitioner<RAIIn> partitioner_down(first, last, block_size);
Functor functor_down(0, partitioner_down.Size() - 1, output_iterator,
neutral, scan, transformation, policy, partitioner_down,
values, 0, true);
embb::tasks::Task task_down = node.Spawn(embb::tasks::Action(
base::MakeFunction(functor_down, &Functor::Action), policy));
task_down.Wait(MTAPI_INFINITE);
// Second pass. Gives to each leaf the part of the prefix missing
BlockSizePartitioner<RAIIn> partitioner_up(first, last, block_size);
Functor functor_up(0, partitioner_up.Size() - 1, output_iterator,
neutral, scan, transformation, policy, partitioner_up,
values, 0, false);
embb::tasks::Task task_up = node.Spawn(embb::tasks::Action(
base::MakeFunction(functor_up, &Functor::Action), policy));
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 embb::tasks::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-2016, 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/tasks/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 embb::mtapi::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 embb::tasks::ExecutionPolicy& policy = embb::tasks::ExecutionPolicy(),
/**< [IN] embb::mtapi::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.
*/
template <typename RAI, typename ComparisonFunction>
void QuickSort(
RAI first,
RAI last,
ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy,
size_t block_size
);
/**
* 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>(),
embb::tasks::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, embb::tasks::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 embb::tasks::ExecutionPolicy& policy
) {
QuickSort(first, last, comparison, policy, 0);
}
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include<embb/algorithms/internal/quick_sort-inl.h>
#endif // EMBB_ALGORITHMS_QUICK_SORT_H_
/*
* Copyright (c) 2014-2016, 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/tasks/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 embb::mtapi::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 object with signature
* <tt>ReturnType ReductionFunction(ReturnType, ReturnType)</tt>.
* \tparam TransformationFunction Unary transformation function object 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 embb::mtapi::ExecutionPolicy& policy = embb::mtapi::ExecutionPolicy(),
/**< [IN] embb::mtapi::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.
*/
template<typename RAI, typename ReturnType, typename ReductionFunction,
typename TransformationFunction>
ReturnType Reduce(
RAI first,
RAI last,
ReturnType neutral,
ReductionFunction reduction,
TransformationFunction transformation,
const embb::tasks::ExecutionPolicy& policy,
size_t block_size
);
/**
* 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(),
embb::tasks::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,
embb::tasks::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 embb::tasks::ExecutionPolicy& policy
) {
return Reduce(first, last, neutral, reduction, transformation, policy, 0);
}
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include <embb/algorithms/internal/reduce-inl.h>
#endif // EMBB_ALGORITHMS_REDUCE_H_
/*
* Copyright (c) 2014-2016, 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/tasks/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 embb::mtapi::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 object with signature
* <tt>ReturnType ScanFunction(ReturnType, ReturnType)</tt>
* \tparam TransformationFunction Unary transformation function object 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 embb::mtapi::ExecutionPolicy& policy = embb::mtapi::ExecutionPolicy(),
/**< [IN] embb::mtapi::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.
*/
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 embb::tasks::ExecutionPolicy& policy,
size_t block_size
);
/**
* 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(),
embb::tasks::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,
embb::tasks::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 embb::tasks::ExecutionPolicy& policy
) {
Scan(first, last, output_iterator, neutral, scan, transformation, policy, 0);
}
#endif // else DOXYGEN
/**
* \}
*/
} // namespace algorithms
} // namespace embb
#include <embb/algorithms/internal/scan-inl.h>
#endif // EMBB_ALGORITHMS_SCAN_H_
/*
* Copyright (c) 2014-2016, 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-2016, 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-2016, 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/tasks/execution_policy.h>
#include <deque>
#include <vector>
#include <functional>
struct IsEven{
bool operator()(int val) const {
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::tasks::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(true, 1)), 3);
}
void CountTest::StressTest() {
using embb::algorithms::Count;
size_t count = embb::tasks::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-2016, 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-2016, 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/tasks/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) const {
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::tasks::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::tasks::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(true, 1));
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]);
}
// ForEach on empty list should not throw:
ForEach(vector.begin(), vector.begin(), Square());
#ifdef EMBB_USE_EXCEPTIONS
bool empty_core_set_thrown = false;
try {
ForEach(vector.begin(), vector.end(), Square(), ExecutionPolicy(false));
}
catch (embb::base::ErrorException &) {
empty_core_set_thrown = true;
}
PT_EXPECT_MSG(empty_core_set_thrown,
"Empty core set should throw ErrorException");
bool negative_range_thrown = false;
try {
std::vector<int>::iterator second = vector.begin() + 1;
ForEach(second, vector.begin(), Square());
}
catch (embb::base::ErrorException &) {
negative_range_thrown = true;
}
PT_EXPECT_MSG(negative_range_thrown,
"Negative range should throw ErrorException");
#endif
}
void ForEachTest::StressTest() {
using embb::algorithms::ForEach;
using embb::tasks::ExecutionPolicy;
size_t count = embb::tasks::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-2016, 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-2016, 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, &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);
embb::tasks::ExecutionPolicy policy;
Invoke(&Invocable1, &Invocable2, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, &Invocable8, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, &Invocable8, &Invocable9, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, &Invocable8, &Invocable9, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, &Invocable8, &Invocable9, &Invocable10,
policy);
}
/*
* Copyright (c) 2014-2016, 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-2016, 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/tasks/tasks.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>
#include <embb/base/c/memory_allocation.h>
#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::tasks::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::tasks::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0);
// std::cout << "please press return to continue..." << std::endl;
// std::cin.get();
}
/*
* Copyright (c) 2014-2016, 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/tasks/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::tasks::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(), 2);
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::tasks::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::tasks::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::tasks::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(true, 1));
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
// MergeSort on empty list should not throw:
MergeSortAllocate(vector.begin(), vector.begin(), std::less<int>());
#ifdef EMBB_USE_EXCEPTIONS
bool empty_core_set_thrown = false;
try {
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(false));
}
catch (embb::base::ErrorException &) {
empty_core_set_thrown = true;
}
PT_EXPECT_MSG(empty_core_set_thrown,
"Empty core set should throw ErrorException");
bool negative_range_thrown = false;
try {
std::vector<int>::iterator second = vector.begin() + 1;
MergeSortAllocate(second, vector.begin(), std::less<int>());
}
catch (embb::base::ErrorException &) {
negative_range_thrown = true;
}
PT_EXPECT_MSG(negative_range_thrown,
"Negative range should throw ErrorException");
#endif
}
void MergeSortTest::StressTest() {
using embb::algorithms::MergeSortAllocate;
size_t count = embb::tasks::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-2016, 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_
/*
* Copyright (c) 2014-2016, 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 <iostream>
#include <partitioner_test.h>
#include <embb/algorithms/internal/partition.h>
#include <vector>
#include <list>
PartitionerTest::PartitionerTest()
: partitioned_array_size_(16384) {
// Size of array to be partitioned should be power of 2
CreateUnit("TestBasic")
.Add(&PartitionerTest::TestBasic, this);
CreateUnit("TestLargeRange")
.Pre(&PartitionerTest::TestLargeRangePre, this)
.Add(&PartitionerTest::TestLargeRange, this)
.Post(&PartitionerTest::TestLargeRangePost, this);
}
void PartitionerTest::TestBasic() {
int A[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
const int N = (sizeof(A) / sizeof(int) );
embb::algorithms::internal::ChunkPartitioner< int* >
partitioner(A, A + N, 5);
PT_EXPECT_EQ_MSG(*(partitioner[0].GetFirst()), 1, "Get start iterator");
PT_EXPECT_EQ_MSG(*(partitioner[0].GetLast()-1), 3, "Get end iterator");
PT_EXPECT_EQ_MSG(*(partitioner[1].GetFirst()), 4, "Get start iterator");
PT_EXPECT_EQ_MSG(*(partitioner[1].GetLast()-1), 6, "Get end iterator");
PT_EXPECT_EQ_MSG(*(partitioner[2].GetFirst()), 7, "Get start iterator");
PT_EXPECT_EQ_MSG(*(partitioner[2].GetLast()-1), 9, "Get end iterator");
PT_EXPECT_EQ_MSG(*(partitioner[3].GetFirst()), 10, "Get start iterator");
PT_EXPECT_EQ_MSG(*(partitioner[3].GetLast()-1), 11, "Get end iterator");
PT_EXPECT_EQ_MSG(*(partitioner[4].GetFirst()), 12, "Get start iterator");
PT_EXPECT_EQ_MSG(*(partitioner[4].GetLast()-1), 13, "Get end iterator");
PT_EXPECT_EQ_MSG(partitioner.Size(), size_t(5), "Check count of partitions");
embb::algorithms::internal::BlockSizePartitioner< int* >
partitioner2(A, A + N, 5);
PT_EXPECT_EQ_MSG(*(partitioner2[0].GetFirst()), 1, "Get start iterator");
PT_EXPECT_EQ_MSG(*(partitioner2[0].GetLast() - 1), 5, "Get end iterator");
PT_EXPECT_EQ_MSG(*(partitioner2[1].GetFirst()), 6, "Get start iterator");
PT_EXPECT_EQ_MSG(*(partitioner2[1].GetLast() - 1), 10, "Get end iterator");
PT_EXPECT_EQ_MSG(*(partitioner2[2].GetFirst()), 11, "Get start iterator");
PT_EXPECT_EQ_MSG(*(partitioner2[2].GetLast() - 1), 13, "Get end iterator");
PT_EXPECT_EQ_MSG(partitioner2.Size(), size_t(3), "Check count of partitions");
}
void PartitionerTest::TestLargeRangePre() {
partitioned_array_ = new int[partitioned_array_size_];
for (size_t i = 0; i < partitioned_array_size_; ++i) {
partitioned_array_[i] = static_cast<int>(i);
}
}
void PartitionerTest::TestLargeRangePost() {
delete[] partitioned_array_;
}
void PartitionerTest::TestLargeRange() {
// Test chunk partitioner with increasing number of chunks:
for (size_t num_chunks = 2;
num_chunks < partitioned_array_size_;
num_chunks *= 2) {
embb::algorithms::internal::ChunkPartitioner<int *>
chunk_partitioner(
partitioned_array_,
partitioned_array_ + partitioned_array_size_,
num_chunks);
int last_value_prev = -1;
PT_EXPECT_EQ(num_chunks, chunk_partitioner.Size());
// Iterate over chunks in partition:
for (size_t chunk = 0; chunk < chunk_partitioner.Size(); ++chunk) {
int first_value = *(chunk_partitioner[chunk].GetFirst());
int last_value = *(chunk_partitioner[chunk].GetLast() - 1);
PT_EXPECT_LT(first_value, last_value);
// Test seams between chunks: chunk[i].last + 1 == chunk[i+1].first
PT_EXPECT_EQ((last_value_prev + 1), first_value);
last_value_prev = last_value;
}
}
// Test block size partitioner with increasing chunk size:
for (size_t block_size = 1;
block_size < partitioned_array_size_;
block_size *= 2) {
embb::algorithms::internal::BlockSizePartitioner<int *>
chunk_partitioner(
partitioned_array_,
partitioned_array_ + partitioned_array_size_,
block_size);
int last_value_prev = -1;
// Iterate over chunks in partition:
for (size_t chunk = 0; chunk < chunk_partitioner.Size(); ++chunk) {
int first_value = *(chunk_partitioner[chunk].GetFirst());
int last_value = *(chunk_partitioner[chunk].GetLast() - 1);
if (block_size == 1) {
PT_EXPECT_EQ(first_value, last_value);
} else {
PT_EXPECT_LT(first_value, last_value);
}
// Test seams between chunks: chunk[i].last + 1 == chunk[i+1].first
PT_EXPECT_EQ((last_value_prev + 1), first_value);
last_value_prev = last_value;
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
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