Initial PSTL commit

The initial commit of the Parallel STL upstream (under LLVM umbrella) based on
Parallel STL 20181204 open source release, which is available by
https://github.com/intel/parallelstl

Author: Mikhail Dvorskiy <mikhail.dvorskiy@intel.com>

Differential Revision: https://reviews.llvm.org/D55889

llvm-svn: 349653
This commit is contained in:
JF Bastien 2018-12-19 17:45:32 +00:00
parent 5d409b2278
commit e637637ae4
101 changed files with 18755 additions and 0 deletions

4
pstl/.arcconfig Normal file
View File

@ -0,0 +1,4 @@
{
"repository.callsign" : "PSTL",
"conduit_uri" : "https://reviews.llvm.org/"
}

17
pstl/.clang-format Normal file
View File

@ -0,0 +1,17 @@
BasedOnStyle: LLVM
Language: Cpp
Standard: Cpp11
IndentWidth: 4
ColumnLimit: 120
AlwaysBreakTemplateDeclarations: true
AlwaysBreakAfterReturnType: All
PointerAlignment: Left
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBraces: Allman
# Disable formatting options which may break tests.
SortIncludes: false
ReflowComments: false

71
pstl/CMakeLists.txt Normal file
View File

@ -0,0 +1,71 @@
#===-- CMakeLists.txt ----------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
cmake_minimum_required(VERSION 3.1)
set(PARALLELSTL_VERSION_FILE "include/pstl/internal/pstl_config.h")
file(STRINGS "${PARALLELSTL_VERSION_FILE}" PARALLELSTL_VERSION_SOURCE REGEX "#define PSTL_VERSION .*$")
string(REGEX MATCH "#define PSTL_VERSION (.*)$" PARALLELSTL_VERSION_SOURCE "${PARALLELSTL_VERSION_SOURCE}")
math(EXPR VERSION_MAJOR "${PARALLELSTL_VERSION_SOURCE} / 100")
math(EXPR VERSION_MINOR "${PARALLELSTL_VERSION_SOURCE} % 100")
project(ParallelSTL VERSION ${VERSION_MAJOR}.${VERSION_MINOR} LANGUAGES CXX)
option(PARALLELSTL_USE_PARALLEL_POLICIES "Enable parallel policies" ON)
set(PARALLELSTL_BACKEND "tbb" CACHE STRING "Threading backend; defaults to TBB")
include(CMakePackageConfigHelpers)
if (NOT TBB_DIR)
get_filename_component(PSTL_DIR_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
string(REPLACE pstl tbb TBB_DIR_NAME ${PSTL_DIR_NAME})
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../${TBB_DIR_NAME}/cmake")
get_filename_component(TBB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${TBB_DIR_NAME}/cmake" ABSOLUTE)
endif()
endif()
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
add_library(ParallelSTL INTERFACE)
add_library(pstl::ParallelSTL ALIAS ParallelSTL)
if (PARALLELSTL_USE_PARALLEL_POLICIES)
if (PARALLELSTL_BACKEND STREQUAL "tbb")
find_package(TBB 2018 REQUIRED tbb OPTIONAL_COMPONENTS tbbmalloc)
message(STATUS "Parallel STL uses TBB ${TBB_VERSION} (interface version: ${TBB_INTERFACE_VERSION})")
target_link_libraries(ParallelSTL INTERFACE TBB::tbb)
else()
if (TARGET ${PARALLELSTL_BACKEND})
target_link_libraries(ParallelSTL INTERFACE ${PARALLELSTL_BACKEND})
else()
find_package(${PARALLELSTL_BACKEND} REQUIRED)
target_link_libraries(ParallelSTL INTERFACE ${${PARALLELSTL_BACKEND}_IMPORTED_TARGETS})
endif()
endif()
else()
target_add_definitions(ParallelSTL INTERFACE PSTL_USE_PARALLEL_POLICIES=0)
endif()
target_include_directories(ParallelSTL
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/>
$<INSTALL_INTERFACE:include>)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/ParallelSTLConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion)
configure_file(
ParallelSTLConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/ParallelSTLConfig.cmake
@ONLY)
export(TARGETS ParallelSTL NAMESPACE pstl:: FILE ParallelSTLTargets.cmake)
export(PACKAGE ParallelSTL)

17
pstl/CREDITS.txt Normal file
View File

@ -0,0 +1,17 @@
This file is a partial list of people who have contributed to the LLVM/pstl
(Parallel STL) project. If you have contributed a patch or made some other
contribution to LLVM/pstl, please submit a patch to this file to add yourself,
and it will be done!
The list is sorted by surname and formatted to allow easy grepping and
beautification by scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
(S).
N: Intel Corporation
W: http://www.intel.com
D: Created the initial implementation.
N: Thomas Rodgers
E: trodgers@redhat.com
D: Identifier name transformation for inclusion in a Standard C++ library.

70
pstl/LICENSE.txt Normal file
View File

@ -0,0 +1,70 @@
==============================================================================
The software contained in this directory tree is dual licensed under both the
University of Illinois "BSD-Like" license and the MIT license. As a user of
this code you may choose to use it under either license. As a contributor,
you agree to allow your code to be used under both.
Full text of the relevant licenses is included below.
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2017-2018 by the contributors listed in CREDITS.TXT
All rights reserved.
Developed by:
Threading Runtimes Team
Intel Corporation
http://www.intel.com
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of Intel Corporation Threading Runtimes Team nor the
names of its contributors may be used to endorse or promote products
derived from this Software without specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.
==============================================================================
Copyright (c) 2017-2018 by the contributors listed in CREDITS.TXT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,18 @@
#===-- ParallelSTLConfig.cmake.in ----------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
include(CMakeFindDependencyMacro)
set(PARALLELSTL_BACKEND "@PARALLELSTL_BACKEND@")
if(PARALLELSTL_BACKEND STREQUAL "tbb")
find_dependency(TBB 2018 REQUIRED tbb)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/ParallelSTLTargets.cmake")

40
pstl/README.md Normal file
View File

@ -0,0 +1,40 @@
# Parallel STL
Parallel STL is an implementation of the C++ standard library algorithms with support for execution policies,
as specified in ISO/IEC 14882:2017 standard, commonly called C++17. The implementation also supports the unsequenced
execution policy specified in Parallelism TS version 2 and proposed for the next version of the C++ standard in the
C++ working group paper P1001R1.
Parallel STL offers efficient support for both parallel and vectorized execution of algorithms. For sequential
execution, it relies on an available implementation of the C++ standard library.
## Prerequisites
To use Parallel STL, you must have the following software installed:
* C++ compiler with:
* Support for C++11
* Support for OpenMP* 4.0 SIMD constructs
* Threading Building Blocks (TBB) which is available to download in the GitHub [repository](https://github.com/01org/tbb/)
## Known Issues or limitations
unseq and par_unseq policies only have effect with compilers that
support '#pragma omp simd' or '#pragma simd'.
Parallel and vector execution is only supported for the algorithms
if random access iterators are provided, while for other iterator
types the execution will remain serial.
The following algorithms do not allow efficient SIMD execution:
includes, inplace_merge, merge, nth_element, partial_sort,
partial_sort_copy, set_difference, set_intersection,
set_symmetric_difference, set_union, sort, stable_partition,
stable_sort, unique.
The initial value type for exclusive_scan, inclusive_scan,
transform_exclusive_scan, transform_inclusive_scan shall satisfy
the DefaultConstructible requirements. A default constructed-instance
of the initial value type shall be the identity element for binary_op.
For max_element, min_element, minmax_element, partial_sort,
partial_sort_copy, sort, stable_sort the dereferenced value type of
the provided iterators shall be DefaultConstructible.
For remove, remove_if, unique the dereferenced value type of the provided
iterators shall be MoveConstructible.
The following algorithms require additional O(n) memory space for parallel
execution: copy_if, inplace_merge, partial_sort, partial_sort_copy,
partition_copy, remove, remove_if, rotate, sort, stable_sort, unique,
unique_copy.

102
pstl/build/Makefile Normal file
View File

@ -0,0 +1,102 @@
#===-- Makefile ----------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
#------------------------------------------------------------------------------
# Define rules for making the Parallel STL library.
#------------------------------------------------------------------------------
proj_root ?= $(CURDIR)/..
include $(proj_root)/build/Makefile.common
CPLUS := $(compiler) $(COMPILER_NOLOGO_KEY) $(USE_SHARED_CPPRUNTIME_KEY)
.SECONDARY:
.PHONY: clean clean_all clean_pstl bench
VPATH = $(proj_root)/test
CPLUS_FLAGS += -I$(proj_root)
PSTL_MAKEFILE = $(proj_root)/build/Makefile.pstl
BENCH_MAKEFILE = $(proj_root)/build/Makefile.bench
test_hdr = $(wildcard $(proj_root)/test/*.h)
test_src = $(wildcard $(proj_root)/test/test_*.cpp)
test_bin = $(notdir $(test_src:.cpp=.exe))
all: $(test_bin)
test_%.offload.exe: test_%.offload$(OBJ_SFX) exception_list.offload$(OBJ_SFX)
$(CPLUS) $(CPLUS_FLAGS) $^ $(FKEY)o$@ $(LDFLAGS)
$(PSTL_LIB_NAME):
$(MAKE) -f $(PSTL_MAKEFILE) backend=$(backend) cfg=$(cfg)
test_%.exe: test_%$(OBJ_SFX) $(PSTL_LIB_NAME)
$(LD) $< $(LD_OUT_KEY)$@ $(LDFLAGS) $(DYN_LDFLAGS) $(PSTL_LIB_LINK)
test_%: test_%.exe
$(run_cmd) $(RUN_CMD)test_$*.exe
test_%$(OBJ_SFX): test_%.cpp $(test_hdr) $(proj_root)/build/Makefile
$(CPLUS) $(CPLUS_FLAGS) -c $< $(FKEY)o$@
# This definition intentionally consists of two blank lines
define eol
endef
test: $(test_bin)
$(foreach test, $(test_bin), $(run_cmd) $(RUN_CMD)$(test) $(args) $(eol))
%.s: %.cpp $(proj_root)/build/Makefile
$(CPLUS) $(CPLUS_FLAGS) -S $< $(FKEY)o$@
%.E: %.cpp
$(CPLUS) $(CPLUS_FLAGS) -E $< >$@
TEMPLATE_FILES=$(wildcard $(proj_root)/bench/*.*tmpl)
BENCH_COMMON_FILES=$(wildcard $(proj_root)/bench/*.h) $(wildcard $(proj_root)/bench/*.cpp)
$(BENCH_MAKEFILE): $(proj_root)/bench/algorithm.json $(proj_root)/bench/gen.py $(TEMPLATE_FILES)
$(PYTHON) $(proj_root)/bench/gen.py $(proj_root)/bench/algorithm.json
bench : $(BENCH_MAKEFILE) $(BENCH_COMMON_FILES) $(PSTL_LIB_NAME)
@echo TEMPLATE_FILES=$(TEMPLATE_FILES)
@echo proj_root=$(proj_root)
ls -la $(proj_root)/bench/gen.py
$(MAKE) -f $(BENCH_MAKEFILE)
clean_bench:
$(DEL_CMD) $(BENCH_MAKEFILE)
$(DEL_CMD) batch.py
$(DEL_CMD) $(proj_root)/build/bench/*.*
clean:
$(DEL_CMD) *$(OBJ_SFX) *.exe *.E *.s *.asm *.d *.pdb *.pdb *.suo *.ilk
clean_pstl:
$(MAKE) -f $(PSTL_MAKEFILE) clean
clean_all: clean clean_pstl clean_bench
info:
@echo OS = $(os_name)
@echo proj_root = "$(proj_root)"
@echo $(CURDIR)
@echo VPATH = $(VPATH)
@echo LIBRARY_PATH = $(LIBRARY_PATH)
@echo backend = $(backend)
@echo compiler = $(compiler)
-include *.d

113
pstl/build/Makefile.common Normal file
View File

@ -0,0 +1,113 @@
#===-- Makefile.common ---------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
#------------------------------------------------------------------------------
# Define common parts for Parallel STL
#------------------------------------------------------------------------------
.SUFFIXES:
goals = $(or $(MAKECMDGOALS),all)
ifneq (, $(filter-out clean clean_all,$(goals)))
ifeq (, $(filter $(backend), tbb))
$(info Threading backend was not specified; using TBB)
backend=tbb
endif
endif
ifndef os_name
# Windows sets environment variable OS; for other systems, ask uname
ifeq ($(OS),)
OS:=$(shell uname)
ifeq ($(OS),)
$(error "Cannot detect operating system")
endif
os_name=$(OS)
endif
ifeq ($(OS), Windows_NT)
os_name=windows
endif
ifeq ($(OS), Linux)
os_name=linux
endif
ifeq ($(OS), Darwin)
os_name=macos
endif
endif # !os_name
cfg ?= release
stdver ?= c++11
override INCLUDES += -I$(proj_root)/include -I$(proj_root)/test
TEST_MACRO += -D__PSTL_TEST_SUCCESSFUL_KEYWORD=1
ifeq ($(backend), tbb)
BACKEND_MACRO += -D__PSTL_PAR_BACKEND_TBB
endif
target ?= $(os_name)
#OS specific keys
ifeq ($(target),windows)
ifneq (, $(filter $(compiler), gcc g++))
include $(proj_root)/build/mingw.inc
else
include $(proj_root)/build/windows.inc
endif
else
include $(proj_root)/build/unix.inc
ifneq (,$(wildcard $(proj_root)/build/$(target).inc))
include $(proj_root)/build/$(target).inc
$(info included additional file $(proj_root)/build/$(target).inc)
endif
endif
# compiler specific keys
ifneq (, $(filter $(compiler), gcc g++))
include $(proj_root)/build/gcc.inc
endif
ifneq (, $(filter $(compiler), clang clang++))
include $(proj_root)/build/clang.inc
endif
ifneq (, $(filter $(compiler), icc icpc icx))
include $(proj_root)/build/icc.inc
endif
ifneq (, $(filter $(compiler), icl))
include $(proj_root)/build/icl.inc
endif
OPTIMIZATION_ENABLED_FLAGS += $(XHOST_FLAG)
OPTIMIZATION_DISABLED_FLAGS += $(XHOST_FLAG)
ifeq ($(cfg), debug)
TBB_LIB_NAME = tbb_debug
BACKEND_MACRO += -DTBB_USE_DEBUG=1
DEBUG_MACRO += -DPSTL_USE_DEBUG
OPTIMIZATION_KEYS = $(OPTIMIZATION_DISABLED_FLAGS)
else
OPTIMIZATION_KEYS = $(OPTIMIZATION_ENABLED_FLAGS)
endif
DYN_LDFLAGS += $(PSTL_ARCH)
CPLUS_FLAGS += $(TEST_MACRO)
CPLUS_FLAGS += $(INCLUDES)
CPLUS_FLAGS += $(BACKEND_MACRO)
CPLUS_FLAGS += $(DEBUG_MACRO)
CPLUS_FLAGS += $(CXXFLAGS)
CPLUS_FLAGS += $(OPTIMIZATION_KEYS)
CPLUS_FLAGS += $(DISABLED_WARNINGS)
CPLUS_FLAGS += $(PSTL_ARCH)

47
pstl/build/Makefile.pstl Normal file
View File

@ -0,0 +1,47 @@
#===-- Makefile.pstl -----------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
#------------------------------------------------------------------------------
# Define rules for making the Parallel STL library.
#------------------------------------------------------------------------------
proj_root ?= $(CURDIR)/..
include $(proj_root)/build/Makefile.common
.PHONY: clean
VPATH = $(proj_root)/src
lib_src = $(wildcard $(proj_root)/src/*.cpp)
lib_obj = $(notdir $(lib_src:.cpp=$(OBJ_SFX)))
all: pstl
pstl: $(PSTL_LIB_NAME)
%$(OBJ_SFX): %.cpp $(proj_root)/build/Makefile.pstl
$(CPLUS) $(CPLUS_FLAGS) -c $< $(FKEY)o$@
%.s: %.cpp $(proj_root)/build/Makefile
$(CPLUS) $(CPLUS_FLAGS) -S $< $(FKEY)o$@
%.E: %.cpp
$(CPLUS) $(CPLUS_FLAGS) -E $< >$@
clean:
$(DEL_CMD) *$(OBJ_SFX) *.lib *.dll *.so *.exp *$(PSTL_LIB_NAME)*
info:
@echo OS = $(os_name)
@echo proj_root = "$(proj_root)"
@echo $(CURDIR)
@echo VPATH=$(VPATH)
-include *.d

48
pstl/build/android.inc Normal file
View File

@ -0,0 +1,48 @@
#===-- android.inc -------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
PSTL_ARCH=
PIE_FLAGS = -pie -fPIE -fPIC
SDL_FLAGS = -fstack-protector -Wformat -Wformat-security
CPLUS_FLAGS += $(TARGET_CFLAGS) $(PIE_FLAGS) $(SDL_FLAGS)
# Paths to the NDK prebuilt tools and libraries
ifeq (,$(findstring $(ndk_version), $(foreach v, 7 8 9 10 11 12 13 14 15,r$(v) r$(v)b r$(v)c r$(v)d r$(v)e)))
ifeq (clang,$(compiler))
# Since Android* NDK r16 another sysroot and isystem paths have to be specified
CPLUS_FLAGS += --sysroot=$(NDK_ROOT)/sysroot -isystem $(NDK_ROOT)/sysroot/usr/include/$(TRIPLE)
# Android* version flag required since r16
CPLUS_FLAGS += -D__ANDROID_API__=$(API_LEVEL)
else
CPLUS_FLAGS += --sysroot=$(SYSROOT)
endif
else
CPLUS_FLAGS += --sysroot=$(SYSROOT)
endif
LDFLAGS += --sysroot=$(SYSROOT) $(TARGET_CFLAGS)
PSTL_LIB_LINK += -lc++abi -L$(CPLUS_LIB_PATH) -lc++_shared
ifeq (arm,$(arch))
PSTL_LIB_LINK += -lunwind
endif
# TARGET_CXX cames from NDK
override CPLUS:=$(TARGET_CXX) $(USE_SHARED_CPPRUNTIME_KEY)
LD = $(CPLUS) $(TARGET_CFLAGS) $(PIE_FLAGS) $(SDL_FLAGS)
run_cmd ?= -sh $(proj_root)/build/android.linux.launcher.sh $(largs)
# TBB_LIBRARIES := $(foreach dir,$(LIBRARY_PATH),$(wildcard $(dir)/libtbb*so))
TBB_LIBRARIES := $(foreach dir,$(LIBRARY_PATH),$(wildcard $(dir)/*))
LIB_STL_ANDROID += $(TBB_LIBRARIES)
$(warning LIB_STL_ANDROID=$(LIB_STL_ANDROID))
$(warning TBB_LIBRARIES=$(TBB_LIBRARIES))
$(warning LIBRARY_PATH=$(LIBRARY_PATH))

View File

@ -0,0 +1,149 @@
#!/bin/sh
#===-- android.linux.launcher.sh -----------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
#
#
# Usage:
# android.linux.launcher.sh [-v] [-q] [-s] [-r <repeats>] [-u] [-l <library>] <executable> <arg1> <arg2> <argN>
# where: -v enables verbose output
# where: -q enables quiet mode
# where: -s runs the test in stress mode (until non-zero exit code or ctrl-c pressed)
# where: -r <repeats> specifies number of times to repeat execution
# where: -u is ignored on Android
# where: -l <library> specifies the library name to be assigned to LD_PRELOAD
#
# Libs and executable necessary for testing should be present in the current directory before running.
# ANDROID_SERIAL must be set to the connected Android target device name for file transfer and test runs.
# ANDROID_TEST_DIRECTORY may be set to the directory used for testing on the Android target device; otherwise,
# the default directory used is "/data/local/tmp/$(basename $PWD)".
# Note: Do not remove the redirections to '/dev/null' in the script, otherwise the nightly test system will fail.
do_cleanup() #
{ #
adb pull $targetdir/events.txt events.txt > /dev/null 2>&1 #
# Remove target directory on the device
adb shell "rm -r ${targetdir}; mkdir -p ${targetdir}" > /dev/null 2>&1 #
} #
do_trap_cleanup() #
{ #
do_cleanup #
exit -1 #
} #
while getopts "qvsr:ul:" flag #
do case $flag in #
s ) # Stress testing mode
echo Doing stress testing. Press Ctrl-C to terminate
run_env='stressed() { while $*; do :; done; }; ' #
run_prefix="stressed $run_prefix" ;; #
r ) # Repeats test n times
run_env="repeated() { for i in $(seq -s ' ' 1 $OPTARG) ; do echo \$i of $OPTARG:; \$*; done; }; " #
run_prefix="repeated $run_prefix" ;; #
l ) # Additional library
ldpreload="$OPTARG " ;; #
u ) # Stack limit
;; #
q ) # Quiet mode, removes 'done' but prepends any other output by test name
OUTPUT='2>&1 | sed -e "s/done//;/^[[:space:]]*$/d;s!^!$exename: !"' ;; #
v ) # Verbose mode
SUPPRESS='' #
verbose=1 ;; #
esac done #
shift `expr $OPTIND - 1` #
[ -z "$OUTPUT" ] && OUTPUT='| sed -e "s/\\r$//"' #
[ $verbose ] || SUPPRESS='>/dev/null' #
# Collect the executable name
exename=$(basename $1) #
shift #
# Prepare the target directory on the device
currentdir=$(basename $PWD) #
targetdir=${ANDROID_TEST_DIRECTORY:-/data/local/tmp/$currentdir} #
do_cleanup #
trap do_trap_cleanup INT # if someone hits control-c, cleanup the device
# Collect the list of files to transfer to the target device, starting with executable itself.
fnamelist="$exename" #
# Add the C++ standard library from the NDK, which is required for all tests on Android.
if [ ! -z "${LIB_STL_ANDROID}" ]; then #
fnamelist="$fnamelist ${LIB_STL_ANDROID}" #
else #
fnamelist="$fnamelist libc++_shared.so" #
fi #
# Find the TBB libraries and add them to the list.
OLD_SEP=$IFS
IFS=':'
for dir in $LD_LIBRARY_PATH; do #
found="`ls $dir/lib*.so 2>/dev/null` "||: #
fnamelist+="$fnamelist $found"
done #
IFS=$OLD_SEP
files="$(ls libtbb* 2> /dev/null)" #
[ -z "$files" ] || fnamelist="$fnamelist $files" #
# Add any libraries built for specific tests.
exeroot=${exename%\.*} #
files="$(ls ${exeroot}*.so ${exeroot}*.so.* 2> /dev/null)" #
[ -z "$files" ] || fnamelist="$fnamelist $files" #
# Transfer collected executable and library files to the target device.
transfers_ok=1 #
for fullname in $fnamelist; do { #
if [ -r $fullname ]; then { #
# Transfer the executable and libraries to top-level target directory
if [ "$OS" = 'Windows_NT' ]; then #
fullname=`cygpath -m "$fullname"` #
fi #
[ $verbose ] && echo -n "Pushing $fullname: " #
eval "adb push $fullname ${targetdir}/$(basename $fullname) $SUPPRESS 2>&1" #
}; else { #
echo "Error: required file ${currentdir}/${fullname} for test $exename not available for transfer." #
transfers_ok=0 #
}; fi #
}; done #
if [ "${transfers_ok}" = "0" ]; then { #
do_cleanup #
exit -1 #
}; fi #
# Transfer input files used by example codes by scanning the executable argument list.
for fullname in "$@"; do { #
if [ -r $fullname ]; then { #
directory=$(dirname $fullname) #
filename=$(basename $fullname) #
# strip leading "." from fullname if present
if [ "$directory" = "\." ]; then { #
directory="" #
fullname=$filename #
}; fi #
# Create the target directory to hold input file if necessary
if [ ! -z $directory ]; then { #
eval "adb shell 'mkdir $directory' $SUPPRESS 2>&1" #
}; fi #
# Transfer the input file to corresponding directory on target device
[ $verbose ] && echo -n "Pushing $fullname: " #
eval "adb push $fullname ${targetdir}/$fullname $SUPPRESS 2>&1" #
}; fi #
}; done #
# Set LD_PRELOAD if necessary
[ -z "$ldpreload" ] || run_prefix="LD_PRELOAD='$ldpreload' $run_prefix" #
[ $verbose ] && echo Running $run_prefix ./$exename $* #
run_env="$run_env cd $targetdir; export LD_LIBRARY_PATH=." #
[ -z "$VIRTUAL_MACHINE" ] || run_env="$run_env; export VIRTUAL_MACHINE=$VIRTUAL_MACHINE" #
# The return_code file is the best way found to return the status of the test execution when using adb shell.
eval 'adb shell "$run_env; $run_prefix ./$exename $* || echo -n \$? >error_code"' "${OUTPUT}" #
# Capture the return code string and remove the trailing \r from the return_code file contents
err=`adb shell "cat $targetdir/error_code 2>/dev/null"` #
[ -z $err ] || echo $exename: exited with error $err #
do_cleanup #
# Return the exit code of the test.
exit $err #

22
pstl/build/clang.inc Normal file
View File

@ -0,0 +1,22 @@
#===-- clang.inc ---------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
override compiler:=clang++
ifneq ($(target),android)
PSTL_ARCH += $(KEY)march=native
endif
XHOST_FLAG = -fno-vectorize
CPLUS_FLAGS += $(FQKEY)std=$(stdver)
# XHOST_FLAG = $(KEY)mavx2 -fno-vectorize
# XHOST_FLAG = $(KEY)mavx512f -fno-vectorize
# DYN_LDFLAGS += $(LINK_KEY)c++
# CPLUS_FLAGS += -stdlib=libc++
# CPLUS_FLAGS += -fopenmp-simd //it will be supported in he future version

28
pstl/build/gcc.inc Normal file
View File

@ -0,0 +1,28 @@
#===-- gcc.inc -----------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
override compiler:=g++
XHOST_FLAG = $(KEY)march=native -fno-tree-vectorize
# XHOST_FLAG = $(KEY)mavx2 -fno-tree-vectorize
# XHOST_FLAG = $(KEY)mavx512f -fno-tree-vectorize
DYN_LDFLAGS += $(LINK_KEY)stdc++
# GCC 4.8.5 and early doesn't support -fopenmp-simd; GCC 4.9 supports OpenMP 4.0 for C/C++
ifneq (, $(shell gcc -dumpversion | egrep "^4\.9\.[0-9]"))
CPLUS_FLAGS += -fopenmp-simd
endif
ifneq (, $(shell gcc -dumpversion | egrep "^[5-9]\.[0-9]\.[0-9]"))
CPLUS_FLAGS += -fopenmp-simd
# CPLUS_FLAGS += -fdump-rtl-loop2 #use this option to enable optimization report
endif
CPLUS_FLAGS += $(FQKEY)std=$(stdver)
ifeq ($(os_name),windows)
DISABLED_WARNINGS = $(KEY)Wno-attributes #disable MinGW warnings about extended alignment
endif

24
pstl/build/icc.inc Normal file
View File

@ -0,0 +1,24 @@
#===-- icc.inc -----------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
vecreport ?= 0 #may be set to [0..7], see https://software.intel.com/en-us/node/522949 for details
XHOST_FLAG = $(KEY)xHOST -no-vec
CPLUS_FLAGS += $(QKEY)opt-assume-safe-padding
# XHOST_FLAG = $(KEY)xCORE-AVX2 -no-vec
# XHOST_FLAG = $(KEY)xSSE4.1 -no-vec
# XHOST_FLAG = $(KEY)xMIC-AVX512 -no-vec
CPLUS_FLAGS += $(QKEY)openmp-simd
CPLUS_FLAGS += $(FQKEY)MMD
CPLUS_FLAGS += $(FQKEY)std=$(stdver)
CPLUS_FLAGS += $(QKEY)opt-report=$(vecreport) $(QKEY)opt-report-phase vec
OPTIMIZATION_DISABLED_FLAGS += $(KEY)debug inline-debug-info

23
pstl/build/icl.inc Normal file
View File

@ -0,0 +1,23 @@
#===-- icl.inc -----------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
vecreport ?= 0 #may be set to [0..7], see https://software.intel.com/en-us/node/522949 for details
XHOST_FLAG = $(QKEY)xHOST
XHOST_FLAG = $(QKEY)vec-
# XHOST_FLAG = $(QKEY)xCORE-AVX2
# XHOST_FLAG = $(QKEY)xSSE4.1
# XHOST_FLAG = $(QKEY)xMIC-AVX512
CPLUS_FLAGS += $(QKEY)opt-assume-safe-padding
CPLUS_FLAGS += $(QKEY)openmp-simd
CPLUS_FLAGS += $(FQKEY)MMD
CPLUS_FLAGS += $(FQKEY)std=$(stdver)
CPLUS_FLAGS += $(QKEY)opt-report:$(vecreport) $(QKEY)opt-report-phase:vec $(QKEY)opt-report-phase:loop
DISABLED_WARNINGS = $(QKEY)diag-disable:2586 #use comma-separated values to specify multiple entries

54
pstl/build/jni/Android.mk Normal file
View File

@ -0,0 +1,54 @@
#===-- Android.mk --------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
export proj_root?=$(NDK_PROJECT_PATH)/..
ifeq (armeabi-v7a,$(APP_ABI))
export SYSROOT:=$(NDK_ROOT)/platforms/$(APP_PLATFORM)/arch-arm
else ifeq (arm64-v8a,$(APP_ABI))
export SYSROOT:=$(NDK_ROOT)/platforms/$(APP_PLATFORM)/arch-arm64
else
export SYSROOT:=$(NDK_ROOT)/platforms/$(APP_PLATFORM)/arch-$(APP_ABI)
endif
ifeq (windows,$(os_name))
export CPATH_SEPARATOR :=;
else
export CPATH_SEPARATOR :=:
endif
export ANDROID_NDK_ROOT:=$(NDK_ROOT)
export ndk_version:=$(lastword $(subst -, ,$(ANDROID_NDK_ROOT)))
ndk_version:= $(firstword $(subst /, ,$(ndk_version)))
ndk_version:= $(firstword $(subst \, ,$(ndk_version)))
ifeq (clang,$(compiler))
# "TBB_RTL :=llvm-libc++/libcxx" should be used for ndk_version r13 r13b r14.
TBB_RTL :=llvm-libc++
TBB_RTL_LIB :=llvm-libc++
TBB_RTL_FILE :=libc++_shared.so
else
TBB_RTL :=gnu-libstdc++/$(NDK_TOOLCHAIN_VERSION)
TBB_RTL_LIB :=$(TBB_RTL)
TBB_RTL_FILE :=libgnustl_shared.so
endif
export CPATH := $(INCLUDE)$(CPATH_SEPARATOR)$(SYSROOT)/usr/include$(CPATH_SEPARATOR)$(NDK_ROOT)/sources/cxx-stl/$(TBB_RTL)/include$(CPATH_SEPARATOR)$(NDK_ROOT)/sources/cxx-stl/$(TBB_RTL)/libs/$(APP_ABI)/include$(CPATH_SEPARATOR)$(NDK_ROOT)/sources/android/support/include
LIB_STL_ANDROID_DIR := $(NDK_ROOT)/sources/cxx-stl/$(TBB_RTL_LIB)/libs/$(APP_ABI)
#LIB_STL_ANDROID is required to be set up for copying Android specific library to a device next to test
export LIB_STL_ANDROID := $(LIB_STL_ANDROID_DIR)/$(TBB_RTL_FILE)
export CPLUS_LIB_PATH := $(SYSROOT)/usr/lib -L$(LIB_STL_ANDROID_DIR)
export target_os_version:=$(APP_PLATFORM)
export tbb_tool_prefix:=$(TOOLCHAIN_PREFIX)
export TARGET_CXX
export TARGET_CC
export TARGET_CFLAGS
include $(proj_root)/build/Makefile

View File

@ -0,0 +1,61 @@
#===-- Application.mk ----------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
ifndef os_name
# Windows sets environment variable OS; for other systems, ask uname
ifeq ($(OS),)
OS:=$(shell uname)
ifeq ($(OS),)
$(error "Cannot detect operating system")
endif
export os_name=$(OS)
endif
ifeq ($(OS), Windows_NT)
export os_name=windows
endif
ifeq ($(OS), Linux)
export os_name=linux
endif
ifeq ($(OS), Darwin)
export os_name=macos
endif
endif
export compiler?=clang
export arch?=ia32
export target?=android
ifeq (ia32,$(arch))
APP_ABI:=x86
export TRIPLE:=i686-linux-android
else ifeq (intel64,$(arch))
APP_ABI:=x86_64
export TRIPLE:=x86_64-linux-android
else ifeq (arm,$(arch))
APP_ABI:=armeabi-v7a
export TRIPLE:=arm-linux-androideabi
else ifeq (arm64,$(arch))
APP_ABI:=arm64-v8a
export TRIPLE:=aarch64-linux-android
else
APP_ABI:=$(arch)
endif
api_version?=21
export API_LEVEL:=$(api_version)
APP_PLATFORM:=android-$(api_version)
ifeq (clang,$(compiler))
NDK_TOOLCHAIN_VERSION:=clang
APP_STL:=c++_shared
else
NDK_TOOLCHAIN_VERSION:=4.9
endif

10
pstl/build/macos.inc Normal file
View File

@ -0,0 +1,10 @@
#===-- macos.inc ---------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
DYN_LDFLAGS += -Wl,-rpath,$(TBBROOT)/lib

50
pstl/build/mingw.inc Normal file
View File

@ -0,0 +1,50 @@
#===-- mingw.inc ---------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
PYTHON = python
KEY = -
QKEY = $(KEY)q
FKEY = $(KEY)
FQKEY = $(KEY)
MACHINE_KEY = $(KEY)m
OBJ_SFX = .o
DEL_CMD = del /F
RUN_CMD =
COMMAND_SEPARATOR = &
compiler ?= gcc
COMPILER_NOLOGO_KEY =
OPTIMIZATION_DISABLED_FLAGS = $(KEY)Og $(KEY)g
OPTIMIZATION_ENABLED_FLAGS += $(KEY)O2
TBB_LIB_NAME = tbb
CPLUS = $(compiler)
LD = $(CPLUS)
USE_SHARED_CPPRUNTIME_KEY =
LINK_KEY = $(KEY)l
LD_OUT_KEY = $(KEY)o
DYN_LDFLAGS += -L. -L$(proj_root)/build
ifneq ($(PSTL_LIB_NAME), )
PSTL_LIB_LINK += $(LINK_KEY)$(PSTL_LIB_NAME)$(PSTL_LIB_EXT)
endif
ifeq ($(backend),tbb)
DYN_LDFLAGS += $(LINK_KEY)$(TBB_LIB_NAME)
endif
ifeq ($(arch),intel64)
PSTL_ARCH = $(MACHINE_KEY)64
else ifeq ($(arch),ia32)
PSTL_ARCH = $(MACHINE_KEY)32
else ifeq ($(arch),)
$(info arch=native by default)
else
PSTL_ARCH = $(MACHINE_KEY)$(arch)
endif

51
pstl/build/unix.inc Normal file
View File

@ -0,0 +1,51 @@
#===-- unix.inc ----------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
PYTHON = python
KEY = -
QKEY = $(KEY)q
FKEY = $(KEY)
FQKEY = $(KEY)
MACHINE_KEY = $(KEY)m
OBJ_SFX = .o
DEL_CMD = rm $(KEY)f
RUN_CMD = ./
COMMAND_SEPARATOR = ;
compiler ?= icc
COMPILER_NOLOGO_KEY =
OPTIMIZATION_DISABLED_FLAGS = $(KEY)O0 $(KEY)g
OPTIMIZATION_ENABLED_FLAGS += $(KEY)O2
TBB_LIB_NAME = tbb
CPLUS = $(compiler)
LD = $(CPLUS)
USE_SHARED_CPPRUNTIME_KEY =
LINK_KEY = $(KEY)l
LD_OUT_KEY = $(KEY)o
DYN_LDFLAGS += -L. -L$(proj_root)/build
ifneq ($(PSTL_LIB_NAME), )
PSTL_LIB_LINK += $(LINK_KEY)$(PSTL_LIB_NAME)$(PSTL_LIB_EXT)
endif
ifeq ($(backend), tbb)
DYN_LDFLAGS += $(LINK_KEY)$(TBB_LIB_NAME)
endif
ifeq ($(arch),intel64)
PSTL_ARCH = $(MACHINE_KEY)64
else ifeq ($(arch),ia32)
PSTL_ARCH = $(MACHINE_KEY)32
else ifeq ($(arch),)
$(info arch=native by default)
else
PSTL_ARCH = $(MACHINE_KEY)$(arch)
endif

54
pstl/build/windows.inc Normal file
View File

@ -0,0 +1,54 @@
#===-- windows.inc -------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
PYTHON = python
compiler ?= icl
LD = LINK
KEY = /
LINK_KEY =
QKEY = $(KEY)Q
FKEY = $(KEY)F
FQKEY = $(QKEY)
MACHINE_KEY = $(QKEY)
OBJ_SFX = .obj
DEL_CMD = del $(KEY)F
RUN_CMD =
COMMAND_SEPARATOR = &
COMPILER_NOLOGO_KEY = $(KEY)nologo
OPTIMIZATION_DISABLED_FLAGS = $(KEY)Od $(KEY)Zi $(KEY)DEBUG $(KEY)Fd"$*.pdb"
OPTIMIZATION_ENABLED_FLAGS = $(KEY)O2 $(KEY)DNDEBUG
LD_OUT_KEY = $(KEY)OUT:
ifneq ($(PSTL_LIB_NAME), )
PSTL_LIB_EXT = .lib
PSTL_LIB_LINK += $(LINK_KEY)$(PSTL_LIB_NAME)$(PSTL_LIB_EXT)
endif
# Do not update LDFLAGS with corresponding TBB_LIB_NAME here, because of
# implicit linkage capability of TBB library
ifeq ($(cfg),debug)
LINK_KEY += $(KEY)debug
USE_SHARED_CPPRUNTIME_KEY += $(KEY)MDd $(KEY)EHsc
BACKEND_MACRO += -DTBB_USE_DEBUG=1
else
USE_SHARED_CPPRUNTIME_KEY += $(KEY)MD $(KEY)EHsc
endif
ifneq (, $(filter $(compiler), cl icl))
CPLUS_FLAGS += $(KEY)bigobj
endif
DYN_LDFLAGS += $(LINK_KEY)
ifneq (,$(filter uwp,$(target_app) $(target_ui)))
CPLUS_FLAGS += /ZW:nostdlib /D "_UNICODE" /D "UNICODE" /D "WINAPI_FAMILY=WINAPI_FAMILY_APP"
_WIN32_WINNT = 0x0A00
DYN_LDFLAGS += /NODEFAULTLIB:"kernel32.lib" OneCore.lib
endif

78
pstl/cmake/FindTBB.cmake Normal file
View File

@ -0,0 +1,78 @@
#===-- FindTBB.cmake -----------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===##
include(FindPackageHandleStandardArgs)
# Firstly search for TBB in config mode (i.e. search for TBBConfig.cmake).
find_package(TBB QUIET CONFIG)
if (TBB_FOUND)
find_package_handle_standard_args(TBB
REQUIRED_VARS TBB_IMPORTED_TARGETS
HANDLE_COMPONENTS
VERSION_VAR TBB_VERSION
CONFIG_MODE)
return()
endif()
if (NOT TBB_FIND_COMPONENTS)
set(TBB_FIND_COMPONENTS tbb tbbmalloc)
foreach (_tbb_component ${TBB_FIND_COMPONENTS})
set(TBB_FIND_REQUIRED_${_tbb_component} 1)
endforeach()
endif()
find_path(_tbb_include_dir tbb/tbb.h)
if (_tbb_include_dir)
file(READ "${_tbb_include_dir}/tbb/tbb_stddef.h" _tbb_stddef LIMIT 2048)
string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" _tbb_ver_major "${_tbb_stddef}")
string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" _tbb_ver_minor "${_tbb_stddef}")
string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_tbb_stddef}")
set(TBB_VERSION "${_tbb_ver_major}.${_tbb_ver_minor}")
unset(_tbb_stddef)
unset(_tbb_ver_major)
unset(_tbb_ver_minor)
foreach (_tbb_component ${TBB_FIND_COMPONENTS})
find_library(_tbb_release_lib ${_tbb_component})
if (_tbb_release_lib)
set(TBB_${_tbb_component}_FOUND 1)
add_library(TBB::${_tbb_component} SHARED IMPORTED)
list(APPEND TBB_IMPORTED_TARGETS TBB::${_tbb_component})
set(_tbb_lib_suffix)
if (UNIX AND NOT APPLE)
set(_tbb_lib_suffix ".2")
endif()
set_target_properties(TBB::${_tbb_component} PROPERTIES
IMPORTED_CONFIGURATIONS "RELEASE"
IMPORTED_LOCATION_RELEASE "${_tbb_release_lib}${_tbb_lib_suffix}"
INTERFACE_INCLUDE_DIRECTORIES "${_tbb_include_dir}")
find_library(_tbb_debug_lib ${_tbb_component}_debug)
if (_tbb_debug_lib)
set_target_properties(TBB::${_tbb_component} PROPERTIES
IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
IMPORTED_LOCATION_DEBUG "${_tbb_debug_lib}${_tbb_lib_suffix}")
endif()
unset(_tbb_debug_lib CACHE)
unset(_tbb_lib_suffix)
endif()
unset(_tbb_release_lib CACHE)
endforeach()
endif()
unset(_tbb_include_dir CACHE)
find_package_handle_standard_args(TBB
REQUIRED_VARS TBB_IMPORTED_TARGETS
HANDLE_COMPONENTS
VERSION_VAR TBB_VERSION)

View File

@ -0,0 +1,25 @@
// -*- C++ -*-
//===-- algorithm ---------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_algorithm
#define __PSTL_algorithm
#include "internal/pstl_config.h"
#if __PSTL_EXECUTION_POLICIES_DEFINED
// If <execution> has already been included, pull in implementations
#include "internal/glue_algorithm_impl.h"
#else
// Otherwise just pull in forward declarations
#include "internal/glue_algorithm_defs.h"
#define __PSTL_ALGORITHM_FORWARD_DECLARED 1
#endif
#endif /* __PSTL_algorithm */

View File

@ -0,0 +1,49 @@
// -*- C++ -*-
//===-- execution ---------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_execution
#define __PSTL_execution
#include "internal/pstl_config.h"
#include "internal/execution_defs.h"
#define __PSTL_EXECUTION_POLICIES_DEFINED 1
#if __PSTL_ALGORITHM_FORWARD_DECLARED
#include "internal/glue_algorithm_impl.h"
#endif
#if __PSTL_MEMORY_FORWARD_DECLARED
#include "internal/glue_memory_impl.h"
#endif
#if __PSTL_NUMERIC_FORWARD_DECLARED
#include "internal/glue_numeric_impl.h"
#endif
#if __PSTL_CPP17_EXECUTION_POLICIES_PRESENT
__PSTL_PRAGMA_MESSAGE_POLICIES("The <Parallel STL> execution policies are defined in the namespace __pstl::execution")
#else
#include "internal/glue_execution_defs.h"
__PSTL_PRAGMA_MESSAGE_POLICIES(
"The <Parallel STL> execution policies are injected into the standard namespace std::execution")
#endif
//TODO: __pstl::execution namespace is injected into the pstl::execution namespace when the implementation is not a part of
// standard C++ library
namespace pstl
{
namespace execution
{
using namespace __pstl::execution;
}
}
#endif /* __PSTL_execution */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,163 @@
// -*- C++ -*-
//===-- execution_defs.h --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_execution_policy_defs_H
#define __PSTL_execution_policy_defs_H
#include <type_traits>
namespace __pstl
{
namespace execution
{
inline namespace v1
{
// 2.4, Sequential execution policy
class sequenced_policy
{
public:
// For internal use only
static constexpr std::false_type
__allow_unsequenced()
{
return std::false_type{};
}
static constexpr std::false_type
__allow_vector()
{
return std::false_type{};
}
static constexpr std::false_type
__allow_parallel()
{
return std::false_type{};
}
};
#if __PSTL_USE_PAR_POLICIES
// 2.5, Parallel execution policy
class parallel_policy
{
public:
// For internal use only
static constexpr std::false_type
__allow_unsequenced()
{
return std::false_type{};
}
static constexpr std::false_type
__allow_vector()
{
return std::false_type{};
}
static constexpr std::true_type
__allow_parallel()
{
return std::true_type{};
}
};
// 2.6, Parallel+Vector execution policy
class parallel_unsequenced_policy
{
public:
// For internal use only
static constexpr std::true_type
__allow_unsequenced()
{
return std::true_type{};
}
static constexpr std::true_type
__allow_vector()
{
return std::true_type{};
}
static constexpr std::true_type
__allow_parallel()
{
return std::true_type{};
}
};
#endif
class unsequenced_policy
{
public:
// For internal use only
static constexpr std::true_type
__allow_unsequenced()
{
return std::true_type{};
}
static constexpr std::true_type
__allow_vector()
{
return std::true_type{};
}
static constexpr std::false_type
__allow_parallel()
{
return std::false_type{};
}
};
// 2.8, Execution policy objects
constexpr sequenced_policy seq{};
#if __PSTL_USE_PAR_POLICIES
constexpr parallel_policy par{};
constexpr parallel_unsequenced_policy par_unseq{};
#endif
constexpr unsequenced_policy unseq{};
// 2.3, Execution policy type trait
template <class T>
struct is_execution_policy : std::false_type
{
};
template <>
struct is_execution_policy<sequenced_policy> : std::true_type
{
};
#if __PSTL_USE_PAR_POLICIES
template <>
struct is_execution_policy<parallel_policy> : std::true_type
{
};
template <>
struct is_execution_policy<parallel_unsequenced_policy> : std::true_type
{
};
#endif
template <>
struct is_execution_policy<unsequenced_policy> : std::true_type
{
};
#if __PSTL_CPP14_VARIABLE_TEMPLATES_PRESENT
template <class T>
constexpr bool is_execution_policy_v = is_execution_policy<T>::value;
#endif
} // namespace v1
} // namespace execution
namespace internal
{
template <class ExecPolicy, class T>
using enable_if_execution_policy =
typename std::enable_if<__pstl::execution::is_execution_policy<typename std::decay<ExecPolicy>::type>::value,
T>::type;
} // namespace internal
} // namespace __pstl
#endif /* __PSTL_execution_policy_defs_H */

View File

@ -0,0 +1,156 @@
// -*- C++ -*-
//===-- execution_impl.h --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_execution_impl_H
#define __PSTL_execution_impl_H
#include <iterator>
#include <type_traits>
#include "execution_defs.h"
namespace __pstl
{
namespace internal
{
using namespace __pstl::execution;
/* predicate */
template <typename _Tp>
std::false_type lazy_and(_Tp, std::false_type)
{
return std::false_type{};
};
template <typename _Tp>
inline _Tp
lazy_and(_Tp __a, std::true_type)
{
return __a;
}
template <typename _Tp>
std::true_type lazy_or(_Tp, std::true_type)
{
return std::true_type{};
};
template <typename _Tp>
inline _Tp
lazy_or(_Tp __a, std::false_type)
{
return __a;
}
/* iterator */
template <typename _IteratorType, typename... _OtherIteratorTypes>
struct is_random_access_iterator
{
static constexpr bool value =
is_random_access_iterator<_IteratorType>::value && is_random_access_iterator<_OtherIteratorTypes...>::value;
typedef std::integral_constant<bool, value> type;
};
template <typename _IteratorType>
struct is_random_access_iterator<_IteratorType>
: std::is_same<typename std::iterator_traits<_IteratorType>::iterator_category, std::random_access_iterator_tag>
{
};
/* policy */
template <typename Policy>
struct policy_traits
{
};
template <>
struct policy_traits<sequenced_policy>
{
typedef std::false_type allow_parallel;
typedef std::false_type allow_unsequenced;
typedef std::false_type allow_vector;
};
template <>
struct policy_traits<unsequenced_policy>
{
typedef std::false_type allow_parallel;
typedef std::true_type allow_unsequenced;
typedef std::true_type allow_vector;
};
#if __PSTL_USE_PAR_POLICIES
template <>
struct policy_traits<parallel_policy>
{
typedef std::true_type allow_parallel;
typedef std::false_type allow_unsequenced;
typedef std::false_type allow_vector;
};
template <>
struct policy_traits<parallel_unsequenced_policy>
{
typedef std::true_type allow_parallel;
typedef std::true_type allow_unsequenced;
typedef std::true_type allow_vector;
};
#endif
template <typename _ExecutionPolicy>
using collector_t = typename policy_traits<typename std::decay<_ExecutionPolicy>::type>::collector_type;
template <typename _ExecutionPolicy>
using allow_vector = typename internal::policy_traits<typename std::decay<_ExecutionPolicy>::type>::allow_vector;
template <typename _ExecutionPolicy>
using allow_unsequenced =
typename internal::policy_traits<typename std::decay<_ExecutionPolicy>::type>::allow_unsequenced;
template <typename _ExecutionPolicy>
using allow_parallel = typename internal::policy_traits<typename std::decay<_ExecutionPolicy>::type>::allow_parallel;
template <typename _ExecutionPolicy, typename... _IteratorTypes>
auto
is_vectorization_preferred(_ExecutionPolicy&& __exec)
-> decltype(lazy_and(__exec.__allow_vector(), typename is_random_access_iterator<_IteratorTypes...>::type()))
{
return internal::lazy_and(__exec.__allow_vector(), typename is_random_access_iterator<_IteratorTypes...>::type());
}
template <typename _ExecutionPolicy, typename... _IteratorTypes>
auto
is_parallelization_preferred(_ExecutionPolicy&& __exec)
-> decltype(lazy_and(__exec.__allow_parallel(), typename is_random_access_iterator<_IteratorTypes...>::type()))
{
return internal::lazy_and(__exec.__allow_parallel(), typename is_random_access_iterator<_IteratorTypes...>::type());
}
template <typename policy, typename... _IteratorTypes>
struct prefer_unsequenced_tag
{
static constexpr bool value =
allow_unsequenced<policy>::value && is_random_access_iterator<_IteratorTypes...>::value;
typedef std::integral_constant<bool, value> type;
};
template <typename policy, typename... _IteratorTypes>
struct prefer_parallel_tag
{
static constexpr bool value = allow_parallel<policy>::value && is_random_access_iterator<_IteratorTypes...>::value;
typedef std::integral_constant<bool, value> type;
};
} // namespace internal
} // namespace __pstl
#endif /* __PSTL_execution_impl_H */

View File

@ -0,0 +1,552 @@
// -*- C++ -*-
//===-- glue_algorithm_defs.h ---------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_glue_algorithm_defs_H
#define __PSTL_glue_algorithm_defs_H
#include <functional>
#include "execution_defs.h"
namespace std
{
// [alg.any_of]
template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
any_of(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred);
// [alg.all_of]
template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
all_of(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred);
// [alg.none_of]
template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
none_of(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred);
// [alg.foreach]
template <class _ExecutionPolicy, class _ForwardIterator, class _Function>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
for_each(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Function __f);
template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Function>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
for_each_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n, _Function __f);
// [alg.find]
template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
find_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
find_if_not(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
find(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value);
// [alg.find.end]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator1>
find_end(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __s_first,
_ForwardIterator2 __s_last, _BinaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator1>
find_end(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __s_first,
_ForwardIterator2 __s_last);
// [alg.find_first_of]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator1>
find_first_of(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __s_first, _ForwardIterator2 __s_last, _BinaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator1>
find_first_of(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __s_first, _ForwardIterator2 __s_last);
// [alg.adjacent_find]
template <class _ExecutionPolicy, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
adjacent_find(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
template <class _ExecutionPolicy, class _ForwardIterator, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
adjacent_find(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred);
// [alg.count]
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy,
typename iterator_traits<_ForwardIterator>::difference_type>
count(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value);
template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy,
typename iterator_traits<_ForwardIterator>::difference_type>
count_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred);
// [alg.search]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator1>
search(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __s_first,
_ForwardIterator2 __s_last, _BinaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator1>
search(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __s_first,
_ForwardIterator2 __s_last);
template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
search_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Size __count,
const _Tp& __value, _BinaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
search_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Size __count,
const _Tp& __value);
// [alg.copy]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
copy(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result);
template <class _ExecutionPolicy, class _ForwardIterator1, class _Size, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
copy_n(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _Size __n, _ForwardIterator2 __result);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
copy_if(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 result,
_Predicate __pred);
// [alg.swap]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
swap_ranges(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2);
// [alg.transform]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _UnaryOperation>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
transform(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result,
_UnaryOperation __op);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator,
class _BinaryOperation>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
transform(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator __result, _BinaryOperation __op);
// [alg.replace]
template <class _ExecutionPolicy, class _ForwardIterator, class _UnaryPredicate, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
replace_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred,
const _Tp& __new_value);
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
replace(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __old_value,
const _Tp& __new_value);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _UnaryPredicate, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
replace_copy_if(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _UnaryPredicate __pred, const _Tp& __new_value);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
replace_copy(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result,
const _Tp& __old_value, const _Tp& __new_value);
// [alg.fill]
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
fill(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value);
template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
fill_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __count, const _Tp& __value);
// [alg.generate]
template <class _ExecutionPolicy, class _ForwardIterator, class _Generator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
generate(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Generator __g);
template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Generator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
generate_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size count, _Generator __g);
// [alg.remove]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
remove_copy_if(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _Predicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
remove_copy(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result,
const _Tp& __value);
template <class _ExecutionPolicy, class _ForwardIterator, class _UnaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
remove_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
remove(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value);
// [alg.unique]
template <class _ExecutionPolicy, class _ForwardIterator, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
unique(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
unique(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
unique_copy(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result,
_BinaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
unique_copy(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result);
// [alg.reverse]
template <class _ExecutionPolicy, class _BidirectionalIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
reverse(_ExecutionPolicy&& __exec, _BidirectionalIterator __first, _BidirectionalIterator __last);
template <class _ExecutionPolicy, class _BidirectionalIterator, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
reverse_copy(_ExecutionPolicy&& __exec, _BidirectionalIterator __first, _BidirectionalIterator __last,
_ForwardIterator __d_first);
// [alg.rotate]
template <class _ExecutionPolicy, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
rotate(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
rotate_copy(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __middle, _ForwardIterator1 __last,
_ForwardIterator2 __result);
// [alg.partitions]
template <class _ExecutionPolicy, class _ForwardIterator, class _UnaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
is_partitioned(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator, class _UnaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
partition(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _UnaryPredicate __pred);
template <class _ExecutionPolicy, class _BidirectionalIterator, class _UnaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _BidirectionalIterator>
stable_partition(_ExecutionPolicy&& __exec, _BidirectionalIterator __first, _BidirectionalIterator __last,
_UnaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator, class _ForwardIterator1, class _ForwardIterator2,
class _UnaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, std::pair<_ForwardIterator1, _ForwardIterator2>>
partition_copy(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last,
_ForwardIterator1 __out_true, _ForwardIterator2 __out_false, _UnaryPredicate __pred);
// [alg.sort]
template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
sort(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _RandomAccessIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
sort(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last);
// [stable.sort]
template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
stable_sort(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _RandomAccessIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
stable_sort(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last);
// [mismatch]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, std::pair<_ForwardIterator1, _ForwardIterator2>>
mismatch(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2, _BinaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, std::pair<_ForwardIterator1, _ForwardIterator2>>
mismatch(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_BinaryPredicate __pred);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, std::pair<_ForwardIterator1, _ForwardIterator2>>
mismatch(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, std::pair<_ForwardIterator1, _ForwardIterator2>>
mismatch(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2);
// [alg.equal]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
equal(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_BinaryPredicate __p);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
equal(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
equal(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2, _BinaryPredicate __p);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
equal(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2);
// [alg.move]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
move(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __d_first);
// [partial.sort]
template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
partial_sort(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __middle,
_RandomAccessIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _RandomAccessIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
partial_sort(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __middle,
_RandomAccessIterator __last);
// [partial.sort.copy]
template <class _ExecutionPolicy, class _ForwardIterator, class _RandomAccessIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _RandomAccessIterator>
partial_sort_copy(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last,
_RandomAccessIterator __d_first, _RandomAccessIterator __d_last, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator, class _RandomAccessIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _RandomAccessIterator>
partial_sort_copy(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last,
_RandomAccessIterator __d_first, _RandomAccessIterator __d_last);
// [is.sorted]
template <class _ExecutionPolicy, class _ForwardIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
is_sorted_until(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
is_sorted_until(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
template <class _ExecutionPolicy, class _ForwardIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
is_sorted(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
is_sorted(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
// [alg.nth.element]
template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
nth_element(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __nth,
_RandomAccessIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _RandomAccessIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
nth_element(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __nth,
_RandomAccessIterator __last);
// [alg.merge]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator,
class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
merge(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2, _ForwardIterator __d_first, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
merge(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2, _ForwardIterator __d_first);
template <class _ExecutionPolicy, class _BidirectionalIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
inplace_merge(_ExecutionPolicy&& __exec, _BidirectionalIterator __first, _BidirectionalIterator __middle,
_BidirectionalIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _BidirectionalIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
inplace_merge(_ExecutionPolicy&& __exec, _BidirectionalIterator __first, _BidirectionalIterator __middle,
_BidirectionalIterator __last);
// [includes]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
includes(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
includes(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2);
// [set.union]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator,
class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
set_union(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2, _ForwardIterator __result, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
set_union(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2, _ForwardIterator __result);
// [set.intersection]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator,
class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
set_intersection(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _ForwardIterator2 __last2, _ForwardIterator __result, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
set_intersection(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _ForwardIterator2 __last2, _ForwardIterator __result);
// [set.difference]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator,
class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
set_difference(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _ForwardIterator2 __last2, _ForwardIterator __result, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
set_difference(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _ForwardIterator2 __last2, _ForwardIterator __result);
// [set.symmetric.difference]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator,
class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
set_symmetric_difference(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _ForwardIterator2 __last2, _ForwardIterator result,
_Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
set_symmetric_difference(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _ForwardIterator2 __last2, _ForwardIterator __result);
// [is.heap]
template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _RandomAccessIterator>
is_heap_until(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _RandomAccessIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _RandomAccessIterator>
is_heap_until(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last);
template <class _ExecutionPolicy, class _RandomAccessIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
is_heap(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _RandomAccessIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
is_heap(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last);
// [alg.min.max]
template <class _ExecutionPolicy, class _ForwardIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
min_element(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
min_element(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
template <class _ExecutionPolicy, class _ForwardIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
max_element(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
max_element(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
template <class _ExecutionPolicy, class _ForwardIterator, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, std::pair<_ForwardIterator, _ForwardIterator>>
minmax_element(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, std::pair<_ForwardIterator, _ForwardIterator>>
minmax_element(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
// [alg.lex.comparison]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Compare>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
lexicographical_compare(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _ForwardIterator2 __last2, _Compare __comp);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
pstl::internal::enable_if_execution_policy<_ExecutionPolicy, bool>
lexicographical_compare(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _ForwardIterator2 __last2);
} // namespace std
#endif /* __PSTL_glue_algorithm_defs_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
// -*- C++ -*-
//===-- glue_execution_defs.h ---------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_glue_execution_defs_H
#define __PSTL_glue_execution_defs_H
#include <type_traits>
#include "execution_defs.h"
namespace std
{
// Type trait
using __pstl::execution::is_execution_policy;
#if __PSTL_CPP14_VARIABLE_TEMPLATES_PRESENT
#if __INTEL_COMPILER
template <class T>
constexpr bool is_execution_policy_v = is_execution_policy<T>::value;
#else
using __pstl::execution::is_execution_policy_v;
#endif
#endif
namespace execution
{
// Standard C++ policy classes
using __pstl::execution::sequenced_policy;
#if __PSTL_USE_PAR_POLICIES
using __pstl::execution::parallel_policy;
using __pstl::execution::parallel_unsequenced_policy;
#endif
// Standard predefined policy instances
using __pstl::execution::seq;
#if __PSTL_USE_PAR_POLICIES
using __pstl::execution::par;
using __pstl::execution::par_unseq;
#endif
// Implementation-defined names
// Unsequenced policy is not yet standard, but for consistency
// we include it into namespace std::execution as well
using __pstl::execution::unseq;
using __pstl::execution::unsequenced_policy;
} // namespace execution
} // namespace std
#endif /* __PSTL_glue_execution_defs_H */

View File

@ -0,0 +1,80 @@
// -*- C++ -*-
//===-- glue_memory_defs.h ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_glue_memory_defs_H
#define __PSTL_glue_memory_defs_H
#include "execution_defs.h"
namespace std
{
// [uninitialized.copy]
template <class _ExecutionPolicy, class _InputIterator, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_copy(_ExecutionPolicy&& __exec, _InputIterator __first, _InputIterator __last, _ForwardIterator __result);
template <class _ExecutionPolicy, class _InputIterator, class _Size, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_copy_n(_ExecutionPolicy&& __exec, _InputIterator __first, _Size __n, _ForwardIterator __result);
// [uninitialized.move]
template <class _ExecutionPolicy, class _InputIterator, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_move(_ExecutionPolicy&& __exec, _InputIterator __first, _InputIterator __last, _ForwardIterator __result);
template <class _ExecutionPolicy, class _InputIterator, class _Size, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_move_n(_ExecutionPolicy&& __exec, _InputIterator __first, _Size __n, _ForwardIterator __result);
// [uninitialized.fill]
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
uninitialized_fill(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value);
template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_fill_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n, const _Tp& __value);
// [specialized.destroy]
template <class _ExecutionPolicy, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
destroy(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
template <class _ExecutionPolicy, class _ForwardIterator, class _Size>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
destroy_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n);
// [uninitialized.construct.default]
template <class _ExecutionPolicy, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
uninitialized_default_construct(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
template <class _ExecutionPolicy, class _ForwardIterator, class _Size>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_default_construct_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n);
// [uninitialized.construct.value]
template <class _ExecutionPolicy, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
uninitialized_value_construct(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
template <class _ExecutionPolicy, class _ForwardIterator, class _Size>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_value_construct_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n);
} // namespace std
#endif /* __PSTL_glue_memory_defs_H */

View File

@ -0,0 +1,357 @@
// -*- C++ -*-
//===-- glue_memory_impl.h ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_glue_memory_impl_H
#define __PSTL_glue_memory_impl_H
#include "utils.h"
#include "algorithm_impl.h"
namespace std
{
// [uninitialized.copy]
template <class _ExecutionPolicy, class _InputIterator, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_copy(_ExecutionPolicy&& __exec, _InputIterator __first, _InputIterator __last, _ForwardIterator __result)
{
typedef typename iterator_traits<_InputIterator>::value_type _ValueType1;
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType2;
typedef typename iterator_traits<_InputIterator>::reference _ReferenceType1;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType2;
using namespace __pstl;
const auto __is_parallel =
internal::is_parallelization_preferred<_ExecutionPolicy, _InputIterator, _ForwardIterator>(__exec);
const auto __is_vector =
internal::is_vectorization_preferred<_ExecutionPolicy, _InputIterator, _ForwardIterator>(__exec);
return internal::invoke_if_else(
std::integral_constant < bool, std::is_trivial<_ValueType1>::value&& std::is_trivial<_ValueType2>::value > (),
[&]() {
return internal::pattern_walk2_brick(
std::forward<_ExecutionPolicy>(__exec), __first, __last, __result,
[__is_vector](_InputIterator __begin, _InputIterator __end, _ForwardIterator __res) {
return internal::brick_copy(__begin, __end, __res, __is_vector);
},
__is_parallel);
},
[&]() {
return internal::pattern_walk2(std::forward<_ExecutionPolicy>(__exec), __first, __last, __result,
[](_ReferenceType1 __val1, _ReferenceType2 __val2) {
::new (std::addressof(__val2)) _ValueType2(__val1);
},
__is_vector, __is_parallel);
});
}
template <class _ExecutionPolicy, class _InputIterator, class _Size, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_copy_n(_ExecutionPolicy&& __exec, _InputIterator __first, _Size __n, _ForwardIterator __result)
{
typedef typename iterator_traits<_InputIterator>::value_type _ValueType1;
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType2;
typedef typename iterator_traits<_InputIterator>::reference _ReferenceType1;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType2;
using namespace __pstl;
const auto __is_parallel =
internal::is_parallelization_preferred<_ExecutionPolicy, _InputIterator, _ForwardIterator>(__exec);
const auto __is_vector =
internal::is_vectorization_preferred<_ExecutionPolicy, _InputIterator, _ForwardIterator>(__exec);
return internal::invoke_if_else(
std::integral_constant < bool, std::is_trivial<_ValueType1>::value&& std::is_trivial<_ValueType2>::value > (),
[&]() {
return internal::pattern_walk2_brick_n(
std::forward<_ExecutionPolicy>(__exec), __first, __n, __result,
[__is_vector](_InputIterator __begin, _Size __sz, _ForwardIterator __res) {
return internal::brick_copy_n(__begin, __sz, __res, __is_vector);
},
__is_parallel);
},
[&]() {
return internal::pattern_walk2_n(std::forward<_ExecutionPolicy>(__exec), __first, __n, __result,
[](_ReferenceType1 __val1, _ReferenceType2 __val2) {
::new (std::addressof(__val2)) _ValueType2(__val1);
},
__is_vector, __is_parallel);
});
}
// [uninitialized.move]
template <class _ExecutionPolicy, class _InputIterator, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_move(_ExecutionPolicy&& __exec, _InputIterator __first, _InputIterator __last, _ForwardIterator __result)
{
typedef typename iterator_traits<_InputIterator>::value_type _ValueType1;
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType2;
typedef typename iterator_traits<_InputIterator>::reference _ReferenceType1;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType2;
using namespace __pstl;
const auto __is_parallel =
internal::is_parallelization_preferred<_ExecutionPolicy, _InputIterator, _ForwardIterator>(__exec);
const auto __is_vector =
internal::is_vectorization_preferred<_ExecutionPolicy, _InputIterator, _ForwardIterator>(__exec);
return internal::invoke_if_else(
std::integral_constant < bool, std::is_trivial<_ValueType1>::value&& std::is_trivial<_ValueType2>::value > (),
[&]() {
return internal::pattern_walk2_brick(
std::forward<_ExecutionPolicy>(__exec), __first, __last, __result,
[__is_vector](_InputIterator __begin, _InputIterator __end, _ForwardIterator __res) {
return internal::brick_copy(__begin, __end, __res, __is_vector);
},
__is_parallel);
},
[&]() {
return internal::pattern_walk2(std::forward<_ExecutionPolicy>(__exec), __first, __last, __result,
[](_ReferenceType1 __val1, _ReferenceType2 __val2) {
::new (std::addressof(__val2)) _ValueType2(std::move(__val1));
},
__is_vector, __is_parallel);
});
}
template <class _ExecutionPolicy, class _InputIterator, class _Size, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_move_n(_ExecutionPolicy&& __exec, _InputIterator __first, _Size __n, _ForwardIterator __result)
{
typedef typename iterator_traits<_InputIterator>::value_type _ValueType1;
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType2;
typedef typename iterator_traits<_InputIterator>::reference _ReferenceType1;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType2;
using namespace __pstl;
const auto __is_parallel =
internal::is_parallelization_preferred<_ExecutionPolicy, _InputIterator, _ForwardIterator>(__exec);
const auto __is_vector =
internal::is_vectorization_preferred<_ExecutionPolicy, _InputIterator, _ForwardIterator>(__exec);
return internal::invoke_if_else(
std::integral_constant < bool, std::is_trivial<_ValueType1>::value&& std::is_trivial<_ValueType2>::value > (),
[&]() {
return internal::pattern_walk2_brick_n(
std::forward<_ExecutionPolicy>(__exec), __first, __n, __result,
[__is_vector](_InputIterator __begin, _Size __sz, _ForwardIterator __res) {
return internal::brick_copy_n(__begin, __sz, __res, __is_vector);
},
__is_parallel);
},
[&]() {
return internal::pattern_walk2_n(std::forward<_ExecutionPolicy>(__exec), __first, __n, __result,
[](_ReferenceType1 __val1, _ReferenceType2 __val2) {
::new (std::addressof(__val2)) _ValueType2(std::move(__val1));
},
__is_vector, __is_parallel);
});
}
// [uninitialized.fill]
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
uninitialized_fill(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value)
{
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType;
using namespace __pstl;
const auto __is_parallel = internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
const auto __is_vector = internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
internal::invoke_if_else(
std::is_arithmetic<_ValueType>(),
[&]() {
internal::pattern_walk_brick(std::forward<_ExecutionPolicy>(__exec), __first, __last,
[&__value, &__is_vector](_ForwardIterator __begin, _ForwardIterator __end) {
internal::brick_fill(__begin, __end, _ValueType(__value), __is_vector);
},
__is_parallel);
},
[&]() {
internal::pattern_walk1(
std::forward<_ExecutionPolicy>(__exec), __first, __last,
[&__value](_ReferenceType __val) { ::new (std::addressof(__val)) _ValueType(__value); }, __is_vector,
__is_parallel);
});
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Size, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_fill_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n, const _Tp& __value)
{
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType;
using namespace __pstl;
const auto __is_parallel = internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
const auto __is_vector = internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
return internal::invoke_if_else(
std::is_arithmetic<_ValueType>(),
[&]() {
return internal::pattern_walk_brick_n(std::forward<_ExecutionPolicy>(__exec), __first, __n,
[&__value, &__is_vector](_ForwardIterator __begin, _Size __count) {
return internal::brick_fill_n(__begin, __count,
_ValueType(__value), __is_vector);
},
__is_parallel);
},
[&]() {
return internal::pattern_walk1_n(
std::forward<_ExecutionPolicy>(__exec), __first, __n,
[&__value](_ReferenceType __val) { ::new (std::addressof(__val)) _ValueType(__value); }, __is_vector,
__is_parallel);
});
}
// [specialized.destroy]
template <class _ExecutionPolicy, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
destroy(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last)
{
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType;
using namespace __pstl;
const auto __is_parallel = internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
const auto __is_vector = internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
internal::invoke_if_not(std::is_trivially_destructible<_ValueType>(), [&]() {
internal::pattern_walk1(std::forward<_ExecutionPolicy>(__exec), __first, __last,
[](_ReferenceType __val) { __val.~_ValueType(); }, __is_vector, __is_parallel);
});
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Size>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
destroy_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n)
{
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType;
using namespace __pstl;
const auto __is_parallel = internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
const auto __is_vector = internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
return internal::invoke_if_else(
std::is_trivially_destructible<_ValueType>(), [&]() { return std::next(__first, __n); },
[&]() {
return internal::pattern_walk1_n(std::forward<_ExecutionPolicy>(__exec), __first, __n,
[](_ReferenceType __val) { __val.~_ValueType(); }, __is_vector,
__is_parallel);
});
}
// [uninitialized.construct.default]
template <class _ExecutionPolicy, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
uninitialized_default_construct(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last)
{
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType;
using namespace __pstl;
const auto __is_parallel = internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
const auto __is_vector = internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
internal::invoke_if_not(std::is_trivial<_ValueType>(), [&]() {
internal::pattern_walk1(std::forward<_ExecutionPolicy>(__exec), __first, __last,
[](_ReferenceType __val) { ::new (std::addressof(__val)) _ValueType; }, __is_vector,
__is_parallel);
});
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Size>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_default_construct_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n)
{
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType;
using namespace __pstl;
const auto __is_parallel = internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
const auto __is_vector = internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
return internal::invoke_if_else(std::is_trivial<_ValueType>(), [&]() { return std::next(__first, __n); },
[&]() {
return internal::pattern_walk1_n(
std::forward<_ExecutionPolicy>(__exec), __first, __n,
[](_ReferenceType __val) { ::new (std::addressof(__val)) _ValueType; },
__is_vector, __is_parallel);
});
}
// [uninitialized.construct.value]
template <class _ExecutionPolicy, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, void>
uninitialized_value_construct(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last)
{
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType;
using namespace __pstl;
const auto __is_parallel = internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
const auto __is_vector = internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
internal::invoke_if_else(
std::is_trivial<_ValueType>(),
[&]() {
internal::pattern_walk_brick(std::forward<_ExecutionPolicy>(__exec), __first, __last,
[__is_vector](_ForwardIterator __begin, _ForwardIterator __end) {
internal::brick_fill(__begin, __end, _ValueType(), __is_vector);
},
__is_parallel);
},
[&]() {
internal::pattern_walk1(std::forward<_ExecutionPolicy>(__exec), __first, __last,
[](_ReferenceType __val) { ::new (std::addressof(__val)) _ValueType(); },
__is_vector, __is_parallel);
});
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Size>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
uninitialized_value_construct_n(_ExecutionPolicy&& __exec, _ForwardIterator __first, _Size __n)
{
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
typedef typename iterator_traits<_ForwardIterator>::reference _ReferenceType;
using namespace __pstl;
const auto __is_parallel = internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
const auto __is_vector = internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec);
return internal::invoke_if_else(
std::is_trivial<_ValueType>(),
[&]() {
return internal::pattern_walk_brick_n(std::forward<_ExecutionPolicy>(__exec), __first, __n,
[__is_vector](_ForwardIterator __begin, _Size __count) {
return internal::brick_fill_n(__begin, __count, _ValueType(),
__is_vector);
},
__is_parallel);
},
[&]() {
return internal::pattern_walk1_n(std::forward<_ExecutionPolicy>(__exec), __first, __n,
[](_ReferenceType __val) { ::new (std::addressof(__val)) _ValueType(); },
__is_vector, __is_parallel);
});
}
} // namespace std
#endif /* __PSTL_glue_memory_imple_H */

View File

@ -0,0 +1,116 @@
// -*- C++ -*-
//===-- glue_numeric_defs.h -----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_glue_numeric_defs_H
#define __PSTL_glue_numeric_defs_H
#include "execution_defs.h"
namespace std
{
// [reduce]
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp, class _BinaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _Tp>
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init,
_BinaryOperation __binary_op);
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _Tp>
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init);
template <class _ExecutionPolicy, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, typename iterator_traits<_ForwardIterator>::value_type>
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _Tp>
transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _Tp __init);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation1,
class _BinaryOperation2>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _Tp>
transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _Tp __init, _BinaryOperation1 __binary_op1,
_BinaryOperation2 __binary_op2);
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _Tp>
transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init,
_BinaryOperation __binary_op, _UnaryOperation __unary_op);
// [exclusive.scan]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
exclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _Tp __init);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation>
_ForwardIterator2
exclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _Tp __init, _BinaryOperation __binary_op);
// [inclusive.scan]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _BinaryOperation __binary_op);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _BinaryOperation __binary_op, _Tp __init);
// [transform.exclusive.scan]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation,
class _UnaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
transform_exclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _Tp __init, _BinaryOperation __binary_op,
_UnaryOperation __unary_op);
// [transform.inclusive.scan]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryOperation,
class _UnaryOperation, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
transform_inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _BinaryOperation __binary_op, _UnaryOperation __unary_op,
_Tp __init);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _UnaryOperation,
class _BinaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
transform_inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _BinaryOperation __binary_op, _UnaryOperation __unary_op);
// [adjacent.difference]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
adjacent_difference(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __d_first, _BinaryOperation op);
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
adjacent_difference(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __d_first);
} // namespace std
#endif /* __PSTL_glue_numeric_defs_H */

View File

@ -0,0 +1,224 @@
// -*- C++ -*-
//===-- glue_numeric_impl.h -----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_glue_numeric_impl_H
#define __PSTL_glue_numeric_impl_H
#include <functional>
#include "utils.h"
#include "numeric_impl.h"
namespace std
{
// [reduce]
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp, class _BinaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _Tp>
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init,
_BinaryOperation __binary_op)
{
return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, __init, __binary_op,
__pstl::internal::no_op());
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _Tp>
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init)
{
return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, __init, std::plus<_Tp>(),
__pstl::internal::no_op());
}
template <class _ExecutionPolicy, class _ForwardIterator>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, typename iterator_traits<_ForwardIterator>::value_type>
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last)
{
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
return transform_reduce(std::forward<_ExecutionPolicy>(__exec), __first, __last, _ValueType{},
std::plus<_ValueType>(), __pstl::internal::no_op());
}
// [transform.reduce]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _Tp>
transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _Tp __init)
{
typedef typename iterator_traits<_ForwardIterator1>::value_type _InputType;
using namespace __pstl;
return internal::pattern_transform_reduce(
std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __first2, __init, std::plus<_InputType>(),
std::multiplies<_InputType>(),
internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator1, _ForwardIterator2>(__exec),
internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator1, _ForwardIterator2>(__exec));
}
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation1,
class _BinaryOperation2>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _Tp>
transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _Tp __init, _BinaryOperation1 __binary_op1, _BinaryOperation2 __binary_op2)
{
using namespace __pstl;
return internal::pattern_transform_reduce(
std::forward<_ExecutionPolicy>(__exec), __first1, __last1, __first2, __init, __binary_op1, __binary_op2,
internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator1, _ForwardIterator2>(__exec),
internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator1, _ForwardIterator2>(__exec));
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _Tp>
transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init,
_BinaryOperation __binary_op, _UnaryOperation __unary_op)
{
using namespace __pstl;
return internal::pattern_transform_reduce(
std::forward<_ExecutionPolicy>(__exec), __first, __last, __init, __binary_op, __unary_op,
internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec),
internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator>(__exec));
}
// [exclusive.scan]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
exclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _Tp __init)
{
return transform_exclusive_scan(std::forward<_ExecutionPolicy>(__exec), __first, __last, __result, __init,
std::plus<_Tp>(), __pstl::internal::no_op());
}
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation>
_ForwardIterator2
exclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _Tp __init, _BinaryOperation __binary_op)
{
return transform_exclusive_scan(std::forward<_ExecutionPolicy>(__exec), __first, __last, __result, __init,
__binary_op, __pstl::internal::no_op());
}
// [inclusive.scan]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result)
{
typedef typename iterator_traits<_ForwardIterator1>::value_type _InputType;
return transform_inclusive_scan(std::forward<_ExecutionPolicy>(__exec), __first, __last, __result,
std::plus<_InputType>(), __pstl::internal::no_op());
}
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _BinaryOperation __binary_op)
{
return transform_inclusive_scan(std::forward<_ExecutionPolicy>(__exec), __first, __last, __result, __binary_op,
__pstl::internal::no_op());
}
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _BinaryOperation __binary_op, _Tp __init)
{
return transform_inclusive_scan(std::forward<_ExecutionPolicy>(__exec), __first, __last, __result, __binary_op,
__pstl::internal::no_op(), __init);
}
// [transform.exclusive.scan]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation,
class _UnaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
transform_exclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _Tp __init, _BinaryOperation __binary_op,
_UnaryOperation __unary_op)
{
using namespace __pstl;
return internal::pattern_transform_scan(
std::forward<_ExecutionPolicy>(__exec), __first, __last, __result, __unary_op, __init, __binary_op,
/*inclusive=*/std::false_type(),
internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator1, _ForwardIterator2>(__exec),
internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator1, _ForwardIterator2>(__exec));
}
// [transform.inclusive.scan]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryOperation,
class _UnaryOperation, class _Tp>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
transform_inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _BinaryOperation __binary_op, _UnaryOperation __unary_op,
_Tp __init)
{
using namespace __pstl;
return internal::pattern_transform_scan(
std::forward<_ExecutionPolicy>(__exec), __first, __last, __result, __unary_op, __init, __binary_op,
/*inclusive=*/std::true_type(),
internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator1, _ForwardIterator2>(__exec),
internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator1, _ForwardIterator2>(__exec));
}
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _UnaryOperation,
class _BinaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
transform_inclusive_scan(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __result, _BinaryOperation __binary_op, _UnaryOperation __unary_op)
{
if (__first != __last)
{
auto __tmp = __unary_op(*__first);
*__result = __tmp;
return transform_inclusive_scan(std::forward<_ExecutionPolicy>(__exec), ++__first, __last, ++__result,
__binary_op, __unary_op, __tmp);
}
else
{
return __result;
}
}
// [adjacent.difference]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryOperation>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
adjacent_difference(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __d_first, _BinaryOperation __op)
{
if (__first == __last)
return __d_first;
using namespace __pstl;
return internal::pattern_adjacent_difference(
std::forward<_ExecutionPolicy>(__exec), __first, __last, __d_first, __op,
internal::is_vectorization_preferred<_ExecutionPolicy, _ForwardIterator1, _ForwardIterator2>(__exec),
internal::is_parallelization_preferred<_ExecutionPolicy, _ForwardIterator1, _ForwardIterator2>(__exec));
}
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
__pstl::internal::enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
adjacent_difference(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __d_first)
{
typedef typename iterator_traits<_ForwardIterator1>::value_type _ValueType;
return adjacent_difference(std::forward<_ExecutionPolicy>(__exec), __first, __last, __d_first,
std::minus<_ValueType>());
}
} // namespace std
#endif /* __PSTL_glue_numeric_impl_H_ */

View File

@ -0,0 +1,57 @@
// -*- C++ -*-
//===-- memory_impl.h -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_memory_impl_H
#define __PSTL_memory_impl_H
#include <iterator>
#include "unseq_backend_simd.h"
namespace __pstl
{
namespace internal
{
//------------------------------------------------------------------------
// uninitialized_move
//------------------------------------------------------------------------
template <class _ForwardIterator, class _OutputIterator>
_OutputIterator
brick_uninitialized_move(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
/*vector=*/std::false_type) noexcept
{
typedef typename std::iterator_traits<_OutputIterator>::value_type _ValueType2;
for (; __first != __last; ++__first, ++__result)
{
::new (std::addressof(*__result)) _ValueType2(std::move(*__first));
}
return __result;
}
template <class _ForwardIterator, class _OutputIterator>
_OutputIterator
brick_uninitialized_move(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
/*vector=*/std::true_type) noexcept
{
typedef typename std::iterator_traits<_OutputIterator>::value_type __ValueType2;
typedef typename std::iterator_traits<_ForwardIterator>::reference _ReferenceType1;
typedef typename std::iterator_traits<_OutputIterator>::reference _ReferenceType2;
return unseq_backend::simd_walk_2(
__first, __last - __first, __result,
[](_ReferenceType1 __x, _ReferenceType2 __y) { ::new (std::addressof(__y)) __ValueType2(std::move(__x)); });
}
} // namespace internal
} // namespace __pstl
#endif /* __PSTL_memory_impl_H */

View File

@ -0,0 +1,359 @@
// -*- C++ -*-
//===-- numeric_impl.h ----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_numeric_impl_H
#define __PSTL_numeric_impl_H
#include <iterator>
#include <type_traits>
#include <numeric>
#include "pstl_config.h"
#include "execution_impl.h"
#include "unseq_backend_simd.h"
#if __PSTL_USE_PAR_POLICIES
#include "parallel_backend.h"
#endif
namespace __pstl
{
namespace internal
{
//------------------------------------------------------------------------
// transform_reduce (version with two binary functions, according to draft N4659)
//------------------------------------------------------------------------
template <class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation1, class _BinaryOperation2>
_Tp
brick_transform_reduce(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _Tp __init,
_BinaryOperation1 __binary_op1, _BinaryOperation2 __binary_op2,
/*is_vector=*/std::false_type) noexcept
{
return std::inner_product(__first1, __last1, __first2, __init, __binary_op1, __binary_op2);
}
template <class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation1, class _BinaryOperation2>
_Tp
brick_transform_reduce(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _Tp __init,
_BinaryOperation1 __binary_op1, _BinaryOperation2 __binary_op2,
/*is_vector=*/std::true_type) noexcept
{
typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferenceType;
return unseq_backend::simd_transform_reduce(
__last1 - __first1, __init, __binary_op1,
[=, &__binary_op2](_DifferenceType __i) { return __binary_op2(__first1[__i], __first2[__i]); });
}
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Tp, class _BinaryOperation1,
class _BinaryOperation2, class _IsVector>
_Tp
pattern_transform_reduce(_ExecutionPolicy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
_ForwardIterator2 __first2, _Tp __init, _BinaryOperation1 __binary_op1,
_BinaryOperation2 __binary_op2, _IsVector __is_vector,
/*is_parallel=*/std::false_type) noexcept
{
return brick_transform_reduce(__first1, __last1, __first2, __init, __binary_op1, __binary_op2, __is_vector);
}
template <class _ExecutionPolicy, class _RandomAccessIterator1, class _RandomAccessIterator2, class _Tp,
class _BinaryOperation1, class _BinaryOperation2, class _IsVector>
_Tp
pattern_transform_reduce(_ExecutionPolicy&& __exec, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2, _Tp __init, _BinaryOperation1 __binary_op1,
_BinaryOperation2 __binary_op2, _IsVector __is_vector, /*is_parallel=*/std::true_type)
{
return internal::except_handler([&]() {
return par_backend::parallel_transform_reduce(
std::forward<_ExecutionPolicy>(__exec), __first1, __last1,
[__first1, __first2, __binary_op2](_RandomAccessIterator1 __i) mutable {
return __binary_op2(*__i, *(__first2 + (__i - __first1)));
},
__init,
__binary_op1, // Combine
[__first1, __first2, __binary_op1, __binary_op2,
__is_vector](_RandomAccessIterator1 __i, _RandomAccessIterator1 __j, _Tp __init) -> _Tp {
return internal::brick_transform_reduce(__i, __j, __first2 + (__i - __first1), __init, __binary_op1,
__binary_op2, __is_vector);
});
});
}
//------------------------------------------------------------------------
// transform_reduce (version with unary and binary functions)
//------------------------------------------------------------------------
template <class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
_Tp
brick_transform_reduce(_ForwardIterator __first, _ForwardIterator __last, _Tp __init, _BinaryOperation __binary_op,
_UnaryOperation __unary_op, /*is_vector=*/std::false_type) noexcept
{
for (; __first != __last; ++__first)
{
__init = __binary_op(__init, __unary_op(*__first));
}
return __init;
}
template <class _ForwardIterator, class _Tp, class _UnaryOperation, class _BinaryOperation>
_Tp
brick_transform_reduce(_ForwardIterator __first, _ForwardIterator __last, _Tp __init, _BinaryOperation __binary_op,
_UnaryOperation __unary_op, /*is_vector=*/std::true_type) noexcept
{
typedef typename std::iterator_traits<_ForwardIterator>::difference_type _DifferenceType;
return unseq_backend::simd_transform_reduce(
__last - __first, __init, __binary_op,
[=, &__unary_op](_DifferenceType __i) { return __unary_op(__first[__i]); });
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation,
class _IsVector>
_Tp
pattern_transform_reduce(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Tp __init,
_BinaryOperation __binary_op, _UnaryOperation __unary_op, _IsVector __is_vector,
/*is_parallel=*/std::false_type) noexcept
{
return brick_transform_reduce(__first, __last, __init, __binary_op, __unary_op, __is_vector);
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation,
class _IsVector>
_Tp
pattern_transform_reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init,
_BinaryOperation __binary_op, _UnaryOperation __unary_op, _IsVector __is_vector,
/*is_parallel=*/std::true_type)
{
return except_handler([&]() {
return par_backend::parallel_transform_reduce(
std::forward<_ExecutionPolicy>(__exec), __first, __last,
[__unary_op](_ForwardIterator __i) mutable { return __unary_op(*__i); }, __init, __binary_op,
[__unary_op, __binary_op, __is_vector](_ForwardIterator __i, _ForwardIterator __j, _Tp __init) {
return brick_transform_reduce(__i, __j, __init, __binary_op, __unary_op, __is_vector);
});
});
}
//------------------------------------------------------------------------
// transform_exclusive_scan
//
// walk3 evaluates f(x,y,z) for (x,y,z) drawn from [first1,last1), [first2,...), [first3,...)
//------------------------------------------------------------------------
// Exclusive form
template <class _ForwardIterator, class _OutputIterator, class _UnaryOperation, class _Tp, class _BinaryOperation>
std::pair<_OutputIterator, _Tp>
brick_transform_scan(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
_UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op,
/*Inclusive*/ std::false_type, /*is_vector=*/std::false_type) noexcept
{
for (; __first != __last; ++__first, ++__result)
{
*__result = __init;
__PSTL_PRAGMA_FORCEINLINE
__init = __binary_op(__init, __unary_op(*__first));
}
return std::make_pair(__result, __init);
}
// Inclusive form
template <class _ForwardIterator, class _OutputIterator, class _UnaryOperation, class _Tp, class _BinaryOperation>
std::pair<_OutputIterator, _Tp>
brick_transform_scan(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
_UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op,
/*Inclusive*/ std::true_type, /*is_vector=*/std::false_type) noexcept
{
for (; __first != __last; ++__first, ++__result)
{
__PSTL_PRAGMA_FORCEINLINE
__init = __binary_op(__init, __unary_op(*__first));
*__result = __init;
}
return std::make_pair(__result, __init);
}
// type is arithmetic and binary operation is a user defined operation.
template <typename _Tp, typename _BinaryOperation>
using is_arithmetic_udop = std::integral_constant<bool, std::is_arithmetic<_Tp>::value &&
!std::is_same<_BinaryOperation, std::plus<_Tp>>::value>;
// [restriction] - T shall be DefaultConstructible.
// [violation] - default ctor of T shall set the identity value for binary_op.
template <class _ForwardIterator, class _OutputIterator, class _UnaryOperation, class _Tp, class _BinaryOperation,
class _Inclusive>
typename std::enable_if<!is_arithmetic_udop<_Tp, _BinaryOperation>::value, std::pair<_OutputIterator, _Tp>>::type
brick_transform_scan(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
_UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op, _Inclusive,
/*is_vector=*/std::true_type) noexcept
{
#if (__PSTL_UDS_PRESENT)
return unseq_backend::simd_scan(__first, __last - __first, __result, __unary_op, __init, __binary_op, _Inclusive());
#else
// We need to call serial brick here to call function for inclusive and exclusive scan that depends on _Inclusive() value
return brick_transform_scan(__first, __last, __result, __unary_op, __init, __binary_op, _Inclusive(),
/*is_vector=*/std::false_type());
#endif
}
template <class _ForwardIterator, class _OutputIterator, class _UnaryOperation, class _Tp, class _BinaryOperation,
class _Inclusive>
typename std::enable_if<is_arithmetic_udop<_Tp, _BinaryOperation>::value, std::pair<_OutputIterator, _Tp>>::type
brick_transform_scan(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
_UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op, _Inclusive,
/*is_vector=*/std::true_type) noexcept
{
return brick_transform_scan(__first, __last, __result, __unary_op, __init, __binary_op, _Inclusive(),
/*is_vector=*/std::false_type());
}
template <class _ExecutionPolicy, class _ForwardIterator, class _OutputIterator, class _UnaryOperation, class _Tp,
class _BinaryOperation, class _Inclusive, class _IsVector>
_OutputIterator
pattern_transform_scan(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _OutputIterator __result,
_UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op, _Inclusive,
_IsVector __is_vector, /*is_parallel=*/std::false_type) noexcept
{
return internal::brick_transform_scan(__first, __last, __result, __unary_op, __init, __binary_op, _Inclusive(),
__is_vector)
.first;
}
template <class _ExecutionPolicy, class _RandomAccessIterator, class _OutputIterator, class _UnaryOperation, class _Tp,
class _BinaryOperation, class _Inclusive, class _IsVector>
typename std::enable_if<!std::is_floating_point<_Tp>::value, _OutputIterator>::type
pattern_transform_scan(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
_OutputIterator __result, _UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op,
_Inclusive, _IsVector __is_vector, /*is_parallel=*/std::true_type)
{
typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _DifferenceType;
return internal::except_handler([&]() {
par_backend::parallel_transform_scan(
std::forward<_ExecutionPolicy>(__exec), __last - __first,
[__first, __unary_op](_DifferenceType __i) mutable { return __unary_op(__first[__i]); }, __init,
__binary_op,
[__first, __unary_op, __binary_op, __is_vector](_DifferenceType __i, _DifferenceType __j, _Tp __init) {
// Execute serial brick_transform_reduce, due to the explicit SIMD vectorization (reduction) requires a commutative operation for the guarantee of correct scan.
return internal::brick_transform_reduce(__first + __i, __first + __j, __init, __binary_op, __unary_op,
/*__is_vector*/ std::false_type());
},
[__first, __unary_op, __binary_op, __result, __is_vector](_DifferenceType __i, _DifferenceType __j,
_Tp __init) {
return internal::brick_transform_scan(__first + __i, __first + __j, __result + __i, __unary_op, __init,
__binary_op, _Inclusive(), __is_vector)
.second;
});
return __result + (__last - __first);
});
}
template <class _ExecutionPolicy, class _RandomAccessIterator, class _OutputIterator, class _UnaryOperation, class _Tp,
class _BinaryOperation, class _Inclusive, class _IsVector>
typename std::enable_if<std::is_floating_point<_Tp>::value, _OutputIterator>::type
pattern_transform_scan(_ExecutionPolicy&& __exec, _RandomAccessIterator __first, _RandomAccessIterator __last,
_OutputIterator __result, _UnaryOperation __unary_op, _Tp __init, _BinaryOperation __binary_op,
_Inclusive, _IsVector __is_vector, /*is_parallel=*/std::true_type)
{
typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _DifferenceType;
_DifferenceType __n = __last - __first;
if (__n <= 0)
{
return __result;
}
return except_handler([&]() {
par_backend::parallel_strict_scan(
std::forward<_ExecutionPolicy>(__exec), __n, __init,
[__first, __unary_op, __binary_op, __result, __is_vector](_DifferenceType __i, _DifferenceType __len) {
return brick_transform_scan(__first + __i, __first + (__i + __len), __result + __i, __unary_op, _Tp{},
__binary_op, _Inclusive(), __is_vector)
.second;
},
__binary_op,
[__result, &__binary_op](_DifferenceType __i, _DifferenceType __len, _Tp __initial) {
return *(std::transform(__result + __i, __result + __i + __len, __result + __i,
[&__initial, &__binary_op](const _Tp& __x) {
__PSTL_PRAGMA_FORCEINLINE
return __binary_op(__initial, __x);
}) -
1);
},
[](_Tp __res) {});
return __result + (__last - __first);
});
}
//------------------------------------------------------------------------
// adjacent_difference
//------------------------------------------------------------------------
template <class _ForwardIterator, class _OutputIterator, class _BinaryOperation>
_OutputIterator
brick_adjacent_difference(_ForwardIterator __first, _ForwardIterator __last, _OutputIterator __d_first,
_BinaryOperation __op, /*is_vector*/ std::false_type) noexcept
{
return std::adjacent_difference(__first, __last, __d_first, __op);
}
template <class _ForwardIterator1, class _ForwardIterator2, class BinaryOperation>
_ForwardIterator2
brick_adjacent_difference(_ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __d_first,
BinaryOperation __op, /*is_vector=*/std::true_type) noexcept
{
assert(__first != __last);
typedef typename std::iterator_traits<_ForwardIterator1>::reference _ReferenceType1;
typedef typename std::iterator_traits<_ForwardIterator2>::reference _ReferenceType2;
auto __n = __last - __first;
*__d_first = *__first;
return unseq_backend::simd_walk_3(
__first + 1, __n - 1, __first, __d_first + 1,
[&__op](_ReferenceType1 __x, _ReferenceType1 __y, _ReferenceType2 __z) { __z = __op(__x, __y); });
}
template <class _ExecutionPolicy, class _ForwardIterator, class _OutputIterator, class _BinaryOperation,
class _IsVector>
_OutputIterator
pattern_adjacent_difference(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last,
_OutputIterator __d_first, _BinaryOperation __op, _IsVector __is_vector,
/*is_parallel*/ std::false_type) noexcept
{
return internal::brick_adjacent_difference(__first, __last, __d_first, __op, __is_vector);
}
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryOperation,
class _IsVector>
_ForwardIterator2
pattern_adjacent_difference(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last,
_ForwardIterator2 __d_first, _BinaryOperation __op, _IsVector __is_vector,
/*is_parallel=*/std::true_type)
{
assert(__first != __last);
typedef typename std::iterator_traits<_ForwardIterator1>::reference _ReferenceType1;
typedef typename std::iterator_traits<_ForwardIterator2>::reference _ReferenceType2;
*__d_first = *__first;
par_backend::parallel_for(std::forward<_ExecutionPolicy>(__exec), __first, __last - 1,
[&__op, __is_vector, __d_first, __first](_ForwardIterator1 __b, _ForwardIterator1 __e) {
_ForwardIterator2 __d_b = __d_first + (__b - __first);
brick_walk3(__b, __e, __b + 1, __d_b + 1,
[&__op](_ReferenceType1 __x, _ReferenceType1 __y, _ReferenceType2 __z) {
__z = __op(__y, __x);
},
__is_vector);
});
return __d_first + (__last - __first);
}
} // namespace internal
} // namespace __pstl
#endif /* __PSTL_numeric_impl_H */

View File

@ -0,0 +1,20 @@
// -*- C++ -*-
//===-- parallel_backend.h ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_parallel_backend_H
#define __PSTL_parallel_backend_H
#if __PSTL_PAR_BACKEND_TBB
#include "parallel_backend_tbb.h"
#else
__PSTL_PRAGMA_MESSAGE("Parallel backend was not specified");
#endif
#endif /* __PSTL_parallel_backend_H */

View File

@ -0,0 +1,656 @@
// -*- C++ -*-
//===-- parallel_backend_tbb.h --------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_parallel_backend_tbb_H
#define __PSTL_parallel_backend_tbb_H
#include <cassert>
#include <algorithm>
#include <type_traits>
#include "parallel_backend_utils.h"
// Bring in minimal required subset of Intel TBB
#include <tbb/blocked_range.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_reduce.h>
#include <tbb/parallel_scan.h>
#include <tbb/parallel_invoke.h>
#include <tbb/task_arena.h>
#include <tbb/tbb_allocator.h>
#if TBB_INTERFACE_VERSION < 10000
#error Intel(R) Threading Building Blocks 2018 is required; older versions are not supported.
#endif
namespace __pstl
{
namespace par_backend
{
//! Raw memory buffer with automatic freeing and no exceptions.
/** Some of our algorithms need to start with raw memory buffer,
not an initialize array, because initialization/destruction
would make the span be at least O(N). */
// tbb::allocator can improve performance in some cases.
template <typename _Tp>
class buffer
{
tbb::tbb_allocator<_Tp> _M_allocator;
_Tp* _M_ptr;
const std::size_t _M_buf_size;
buffer(const buffer&) = delete;
void
operator=(const buffer&) = delete;
public:
//! Try to obtain buffer of given size to store objects of _Tp type
buffer(std::size_t n) : _M_allocator(), _M_ptr(_M_allocator.allocate(n)), _M_buf_size(n) {}
//! True if buffer was successfully obtained, zero otherwise.
operator bool() const { return _M_ptr != NULL; }
//! Return pointer to buffer, or NULL if buffer could not be obtained.
_Tp*
get() const
{
return _M_ptr;
}
//! Destroy buffer
~buffer() { _M_allocator.deallocate(_M_ptr, _M_buf_size); }
};
// Wrapper for tbb::task
inline void
cancel_execution()
{
tbb::task::self().group()->cancel_group_execution();
}
//------------------------------------------------------------------------
// parallel_for
//------------------------------------------------------------------------
template <class _Index, class _RealBody>
class parallel_for_body
{
public:
parallel_for_body(const _RealBody& __body) : _M_body(__body) {}
parallel_for_body(const parallel_for_body& __body) : _M_body(__body._M_body) {}
void
operator()(const tbb::blocked_range<_Index>& __range) const
{
_M_body(__range.begin(), __range.end());
}
private:
_RealBody _M_body;
};
//! Evaluation of brick f[i,j) for each subrange [i,j) of [first,last)
// wrapper over tbb::parallel_for
template <class _ExecutionPolicy, class _Index, class _Fp>
void
parallel_for(_ExecutionPolicy&&, _Index __first, _Index __last, _Fp __f)
{
tbb::this_task_arena::isolate(
[=]() { tbb::parallel_for(tbb::blocked_range<_Index>(__first, __last), parallel_for_body<_Index, _Fp>(__f)); });
}
//! Evaluation of brick f[i,j) for each subrange [i,j) of [first,last)
// wrapper over tbb::parallel_reduce
template <class _ExecutionPolicy, class _Value, class _Index, typename _RealBody, typename _Reduction>
_Value
parallel_reduce(_ExecutionPolicy&&, _Index __first, _Index __last, const _Value& __identity,
const _RealBody& __real_body, const _Reduction& __reduction)
{
return tbb::this_task_arena::isolate([__first, __last, &__identity, &__real_body, &__reduction]() -> _Value {
return tbb::parallel_reduce(
tbb::blocked_range<_Index>(__first, __last), __identity,
[__real_body](const tbb::blocked_range<_Index>& __r, const _Value& __value) -> _Value {
return __real_body(__r.begin(), __r.end(), __value);
},
__reduction);
});
}
//------------------------------------------------------------------------
// parallel_transform_reduce
//
// Notation:
// r(i,j,init) returns reduction of init with reduction over [i,j)
// u(i) returns f(i,i+1,identity) for a hypothetical left identity element of r
// c(x,y) combines values x and y that were the result of r or u
//------------------------------------------------------------------------
template <class _Index, class _Up, class _Tp, class _Cp, class _Rp>
struct par_trans_red_body
{
alignas(_Tp) char _M_sum_storage[sizeof(_Tp)]; // Holds generalized non-commutative sum when has_sum==true
_Rp _M_brick_reduce; // Most likely to have non-empty layout
_Up _M_u;
_Cp _M_combine;
bool _M_has_sum; // Put last to minimize size of class
_Tp&
sum()
{
__TBB_ASSERT(_M_has_sum, "sum expected");
return *(_Tp*)_M_sum_storage;
}
par_trans_red_body(_Up __u, _Tp __init, _Cp __c, _Rp __r)
: _M_brick_reduce(__r), _M_u(__u), _M_combine(__c), _M_has_sum(true)
{
new (_M_sum_storage) _Tp(__init);
}
par_trans_red_body(par_trans_red_body& __left, tbb::split)
: _M_brick_reduce(__left._M_brick_reduce), _M_u(__left._M_u), _M_combine(__left._M_combine), _M_has_sum(false)
{
}
~par_trans_red_body()
{
// 17.6.5.12 tells us to not worry about catching exceptions from destructors.
if (_M_has_sum)
sum().~_Tp();
}
void
join(par_trans_red_body& __rhs)
{
sum() = _M_combine(sum(), __rhs.sum());
}
void
operator()(const tbb::blocked_range<_Index>& __range)
{
_Index __i = __range.begin();
_Index __j = __range.end();
if (!_M_has_sum)
{
__TBB_ASSERT(__range.size() > 1, "there should be at least 2 elements");
new (&_M_sum_storage)
_Tp(_M_combine(_M_u(__i), _M_u(__i + 1))); // The condition i+1 < j is provided by the grain size of 3
_M_has_sum = true;
std::advance(__i, 2);
if (__i == __j)
return;
}
sum() = _M_brick_reduce(__i, __j, sum());
}
};
template <class _ExecutionPolicy, class _Index, class _Up, class _Tp, class _Cp, class _Rp>
_Tp
parallel_transform_reduce(_ExecutionPolicy&&, _Index __first, _Index __last, _Up __u, _Tp __init, _Cp __combine,
_Rp __brick_reduce)
{
par_trans_red_body<_Index, _Up, _Tp, _Cp, _Rp> __body(__u, __init, __combine, __brick_reduce);
// The grain size of 3 is used in order to provide mininum 2 elements for each body
tbb::this_task_arena::isolate(
[__first, __last, &__body]() { tbb::parallel_reduce(tbb::blocked_range<_Index>(__first, __last, 3), __body); });
return __body.sum();
}
//------------------------------------------------------------------------
// parallel_scan
//------------------------------------------------------------------------
template <class _Index, class _Up, class _Tp, class _Cp, class _Rp, class _Sp>
class trans_scan_body
{
alignas(_Tp) char _M_sum_storage[sizeof(_Tp)]; // Holds generalized non-commutative sum when has_sum==true
_Rp _M_brick_reduce; // Most likely to have non-empty layout
_Up _M_u;
_Cp _M_combine;
_Sp _M_scan;
bool _M_has_sum; // Put last to minimize size of class
public:
trans_scan_body(_Up __u, _Tp __init, _Cp __combine, _Rp __reduce, _Sp __scan)
: _M_brick_reduce(__reduce), _M_u(__u), _M_combine(__combine), _M_scan(__scan), _M_has_sum(true)
{
new (_M_sum_storage) _Tp(__init);
}
trans_scan_body(trans_scan_body& __b, tbb::split)
: _M_brick_reduce(__b._M_brick_reduce), _M_u(__b._M_u), _M_combine(__b._M_combine), _M_scan(__b._M_scan),
_M_has_sum(false)
{
}
~trans_scan_body()
{
// 17.6.5.12 tells us to not worry about catching exceptions from destructors.
if (_M_has_sum)
sum().~_Tp();
}
_Tp&
sum() const
{
__TBB_ASSERT(_M_has_sum, "sum expected");
return *(_Tp*)_M_sum_storage;
}
void
operator()(const tbb::blocked_range<_Index>& __range, tbb::pre_scan_tag)
{
_Index __i = __range.begin();
_Index __j = __range.end();
if (!_M_has_sum)
{
new (&_M_sum_storage) _Tp(_M_u(__i));
_M_has_sum = true;
++__i;
if (__i == __j)
return;
}
sum() = _M_brick_reduce(__i, __j, sum());
}
void
operator()(const tbb::blocked_range<_Index>& __range, tbb::final_scan_tag)
{
sum() = _M_scan(__range.begin(), __range.end(), sum());
}
void
reverse_join(trans_scan_body& __a)
{
if (_M_has_sum)
{
sum() = _M_combine(__a.sum(), sum());
}
else
{
new (&_M_sum_storage) _Tp(__a.sum());
_M_has_sum = true;
}
}
void
assign(trans_scan_body& __b)
{
sum() = __b.sum();
}
};
template <typename _Index>
_Index
split(_Index __m)
{
_Index __k = 1;
while (2 * __k < __m)
__k *= 2;
return __k;
}
//------------------------------------------------------------------------
// parallel_strict_scan
//------------------------------------------------------------------------
template <typename _Index, typename _Tp, typename _Rp, typename _Cp>
void
upsweep(_Index __i, _Index __m, _Index __tilesize, _Tp* __r, _Index __lastsize, _Rp __reduce, _Cp __combine)
{
if (__m == 1)
__r[0] = __reduce(__i * __tilesize, __lastsize);
else
{
_Index __k = split(__m);
tbb::parallel_invoke([=] { par_backend::upsweep(__i, __k, __tilesize, __r, __tilesize, __reduce, __combine); },
[=] {
par_backend::upsweep(__i + __k, __m - __k, __tilesize, __r + __k, __lastsize, __reduce,
__combine);
});
if (__m == 2 * __k)
__r[__m - 1] = __combine(__r[__k - 1], __r[__m - 1]);
}
}
template <typename _Index, typename _Tp, typename _Cp, typename _Sp>
void
downsweep(_Index __i, _Index __m, _Index __tilesize, _Tp* __r, _Index __lastsize, _Tp __initial, _Cp __combine,
_Sp __scan)
{
if (__m == 1)
__scan(__i * __tilesize, __lastsize, __initial);
else
{
const _Index __k = par_backend::split(__m);
tbb::parallel_invoke(
[=] { par_backend::downsweep(__i, __k, __tilesize, __r, __tilesize, __initial, __combine, __scan); },
// Assumes that __combine never throws.
//TODO: Consider adding a requirement for user functors to be constant.
[=, &__combine] {
par_backend::downsweep(__i + __k, __m - __k, __tilesize, __r + __k, __lastsize,
__combine(__initial, __r[__k - 1]), __combine, __scan);
});
}
}
// Adapted from Intel(R) Cilk(TM) version from cilkpub.
// Let i:len denote a counted interval of length n starting at i. s denotes a generalized-sum value.
// Expected actions of the functors are:
// reduce(i,len) -> s -- return reduction value of i:len.
// combine(s1,s2) -> s -- return merged sum
// apex(s) -- do any processing necessary between reduce and scan.
// scan(i,len,initial) -- perform scan over i:len starting with initial.
// The initial range 0:n is partitioned into consecutive subranges.
// reduce and scan are each called exactly once per subrange.
// Thus callers can rely upon side effects in reduce.
// combine must not throw an exception.
// apex is called exactly once, after all calls to reduce and before all calls to scan.
// For example, it's useful for allocating a buffer used by scan but whose size is the sum of all reduction values.
// T must have a trivial constructor and destructor.
template <class _ExecutionPolicy, typename _Index, typename _Tp, typename _Rp, typename _Cp, typename _Sp, typename _Ap>
void
parallel_strict_scan(_ExecutionPolicy&&, _Index __n, _Tp __initial, _Rp __reduce, _Cp __combine, _Sp __scan, _Ap __apex)
{
tbb::this_task_arena::isolate([=, &__combine]() {
if (__n > 1)
{
_Index __p = tbb::this_task_arena::max_concurrency();
const _Index __slack = 4;
_Index __tilesize = (__n - 1) / (__slack * __p) + 1;
_Index __m = (__n - 1) / __tilesize;
buffer<_Tp> __buf(__m + 1);
_Tp* __r = __buf.get();
par_backend::upsweep(_Index(0), _Index(__m + 1), __tilesize, __r, __n - __m * __tilesize, __reduce,
__combine);
// When __apex is a no-op and __combine has no side effects, a good optimizer
// should be able to eliminate all code between here and __apex.
// Alternatively, provide a default value for __apex that can be
// recognized by metaprogramming that conditionlly executes the following.
size_t __k = __m + 1;
_Tp __t = __r[__k - 1];
while ((__k &= __k - 1))
__t = __combine(__r[__k - 1], __t);
__apex(__combine(__initial, __t));
par_backend::downsweep(_Index(0), _Index(__m + 1), __tilesize, __r, __n - __m * __tilesize, __initial,
__combine, __scan);
return;
}
// Fewer than 2 elements in sequence, or out of memory. Handle has single block.
_Tp __sum = __initial;
if (__n)
__sum = __combine(__sum, __reduce(_Index(0), __n));
__apex(__sum);
if (__n)
__scan(_Index(0), __n, __initial);
});
}
template <class _ExecutionPolicy, class _Index, class _Up, class _Tp, class _Cp, class _Rp, class _Sp>
_Tp
parallel_transform_scan(_ExecutionPolicy&&, _Index __n, _Up __u, _Tp __init, _Cp __combine, _Rp __brick_reduce,
_Sp __scan)
{
trans_scan_body<_Index, _Up, _Tp, _Cp, _Rp, _Sp> __body(__u, __init, __combine, __brick_reduce, __scan);
auto __range = tbb::blocked_range<_Index>(0, __n);
tbb::this_task_arena::isolate([__range, &__body]() { tbb::parallel_scan(__range, __body); });
return __body.sum();
}
//------------------------------------------------------------------------
// parallel_stable_sort
//------------------------------------------------------------------------
//------------------------------------------------------------------------
// stable_sort utilities
//
// These are used by parallel implementations but do not depend on them.
//------------------------------------------------------------------------
template <typename _RandomAccessIterator1, typename _RandomAccessIterator2, typename _RandomAccessIterator3,
typename _Compare, typename _Cleanup, typename _LeafMerge>
class merge_task : public tbb::task
{
/*override*/ tbb::task*
execute();
_RandomAccessIterator1 _M_xs, _M_xe;
_RandomAccessIterator2 _M_ys, _M_ye;
_RandomAccessIterator3 _M_zs;
_Compare _M_comp;
_Cleanup _M_cleanup;
_LeafMerge _M_leaf_merge;
public:
merge_task(_RandomAccessIterator1 __xs, _RandomAccessIterator1 __xe, _RandomAccessIterator2 __ys,
_RandomAccessIterator2 __ye, _RandomAccessIterator3 __zs, _Compare __comp, _Cleanup __cleanup,
_LeafMerge __leaf_merge)
: _M_xs(__xs), _M_xe(__xe), _M_ys(__ys), _M_ye(__ye), _M_zs(__zs), _M_comp(__comp), _M_cleanup(__cleanup),
_M_leaf_merge(__leaf_merge)
{
}
};
#define __PSTL_MERGE_CUT_OFF 2000
template <typename _RandomAccessIterator1, typename _RandomAccessIterator2, typename _RandomAccessIterator3,
typename __M_Compare, typename _Cleanup, typename _LeafMerge>
tbb::task*
merge_task<_RandomAccessIterator1, _RandomAccessIterator2, _RandomAccessIterator3, __M_Compare, _Cleanup,
_LeafMerge>::execute()
{
typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type _DifferenceType1;
typedef typename std::iterator_traits<_RandomAccessIterator2>::difference_type _DifferenceType2;
typedef typename std::common_type<_DifferenceType1, _DifferenceType2>::type _SizeType;
const _SizeType __n = (_M_xe - _M_xs) + (_M_ye - _M_ys);
const _SizeType __merge_cut_off = __PSTL_MERGE_CUT_OFF;
if (__n <= __merge_cut_off)
{
_M_leaf_merge(_M_xs, _M_xe, _M_ys, _M_ye, _M_zs, _M_comp);
//we clean the buffer one time on last step of the sort
_M_cleanup(_M_xs, _M_xe);
_M_cleanup(_M_ys, _M_ye);
return nullptr;
}
else
{
_RandomAccessIterator1 __xm;
_RandomAccessIterator2 __ym;
if (_M_xe - _M_xs < _M_ye - _M_ys)
{
__ym = _M_ys + (_M_ye - _M_ys) / 2;
__xm = std::upper_bound(_M_xs, _M_xe, *__ym, _M_comp);
}
else
{
__xm = _M_xs + (_M_xe - _M_xs) / 2;
__ym = std::lower_bound(_M_ys, _M_ye, *__xm, _M_comp);
}
const _RandomAccessIterator3 __zm = _M_zs + ((__xm - _M_xs) + (__ym - _M_ys));
tbb::task* __right = new (tbb::task::allocate_additional_child_of(*parent()))
merge_task(__xm, _M_xe, __ym, _M_ye, __zm, _M_comp, _M_cleanup, _M_leaf_merge);
tbb::task::spawn(*__right);
tbb::task::recycle_as_continuation();
_M_xe = __xm;
_M_ye = __ym;
}
return this;
}
template <typename _RandomAccessIterator1, typename _RandomAccessIterator2, typename _Compare, typename _LeafSort>
class stable_sort_task : public tbb::task
{
public:
typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type _DifferenceType1;
typedef typename std::iterator_traits<_RandomAccessIterator2>::difference_type _DifferenceType2;
typedef typename std::common_type<_DifferenceType1, _DifferenceType2>::type _SizeType;
private:
/*override*/ tbb::task*
execute();
_RandomAccessIterator1 _M_xs, _M_xe;
_RandomAccessIterator2 _M_zs;
_Compare _M_comp;
_LeafSort _M_leaf_sort;
int32_t _M_inplace;
_SizeType _M_nsort;
public:
stable_sort_task(_RandomAccessIterator1 __xs, _RandomAccessIterator1 __xe, _RandomAccessIterator2 __zs,
int32_t __inplace, _Compare __comp, _LeafSort __leaf_sort, _SizeType __n)
: _M_xs(__xs), _M_xe(__xe), _M_zs(__zs), _M_inplace(__inplace), _M_comp(__comp), _M_leaf_sort(__leaf_sort),
_M_nsort(__n)
{
}
};
//! Binary operator that does nothing
struct binary_no_op
{
template <typename _T>
void operator()(_T, _T)
{
}
};
#define __PSTL_STABLE_SORT_CUT_OFF 500
template <typename _RandomAccessIterator1, typename _RandomAccessIterator2, typename _Compare, typename _LeafSort>
tbb::task*
stable_sort_task<_RandomAccessIterator1, _RandomAccessIterator2, _Compare, _LeafSort>::execute()
{
const _SizeType __n = _M_xe - _M_xs;
const _SizeType __nmerge = _M_nsort > 0 ? _M_nsort : __n;
const _SizeType __sort_cut_off = __PSTL_STABLE_SORT_CUT_OFF;
if (__n <= __sort_cut_off)
{
_M_leaf_sort(_M_xs, _M_xe, _M_comp);
if (_M_inplace != 2)
init_buf(_M_xs, _M_xe, _M_zs, _M_inplace == 0);
return NULL;
}
else
{
const _RandomAccessIterator1 __xm = _M_xs + __n / 2;
const _RandomAccessIterator2 __zm = _M_zs + (__xm - _M_xs);
const _RandomAccessIterator2 __ze = _M_zs + __n;
task* __m;
auto __move_values = [](_RandomAccessIterator2 __x, _RandomAccessIterator1 __z) { *__z = std::move(*__x); };
auto __move_sequences = [](_RandomAccessIterator2 __first1, _RandomAccessIterator2 __last1,
_RandomAccessIterator1 __first2) { return std::move(__first1, __last1, __first2); };
if (_M_inplace == 2)
__m = new (allocate_continuation())
merge_task<_RandomAccessIterator2, _RandomAccessIterator2, _RandomAccessIterator1, _Compare,
serial_destroy, serial_move_merge<decltype(__move_values), decltype(__move_sequences)>>(
_M_zs, __zm, __zm, __ze, _M_xs, _M_comp, serial_destroy(),
serial_move_merge<decltype(__move_values), decltype(__move_sequences)>(__nmerge, __move_values,
__move_sequences));
else if (_M_inplace)
__m = new (allocate_continuation())
merge_task<_RandomAccessIterator2, _RandomAccessIterator2, _RandomAccessIterator1, _Compare,
binary_no_op, serial_move_merge<decltype(__move_values), decltype(__move_sequences)>>(
_M_zs, __zm, __zm, __ze, _M_xs, _M_comp, binary_no_op(),
serial_move_merge<decltype(__move_values), decltype(__move_sequences)>(__nmerge, __move_values,
__move_sequences));
else
{
auto __move_values = [](_RandomAccessIterator1 __x, _RandomAccessIterator2 __z) { *__z = std::move(*__x); };
auto __move_sequences = [](_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2) {
return std::move(__first1, __last1, __first2);
};
__m = new (allocate_continuation())
merge_task<_RandomAccessIterator1, _RandomAccessIterator1, _RandomAccessIterator2, _Compare,
binary_no_op, serial_move_merge<decltype(__move_values), decltype(__move_sequences)>>(
_M_xs, __xm, __xm, _M_xe, _M_zs, _M_comp, binary_no_op(),
serial_move_merge<decltype(__move_values), decltype(__move_sequences)>(__nmerge, __move_values,
__move_sequences));
}
__m->set_ref_count(2);
task* __right = new (__m->allocate_child())
stable_sort_task(__xm, _M_xe, __zm, !_M_inplace, _M_comp, _M_leaf_sort, __nmerge);
spawn(*__right);
recycle_as_child_of(*__m);
_M_xe = __xm;
_M_inplace = !_M_inplace;
}
return this;
}
template <class _ExecutionPolicy, typename _RandomAccessIterator, typename _Compare, typename _LeafSort>
void
parallel_stable_sort(_ExecutionPolicy&&, _RandomAccessIterator __xs, _RandomAccessIterator __xe, _Compare __comp,
_LeafSort __leaf_sort, std::size_t __nsort = 0)
{
tbb::this_task_arena::isolate([=, &__nsort]() {
//sorting based on task tree and parallel merge
typedef typename std::iterator_traits<_RandomAccessIterator>::value_type _ValueType;
typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type _DifferenceType;
const _DifferenceType __n = __xe - __xs;
if (__nsort == 0)
__nsort = __n;
const _DifferenceType __sort_cut_off = __PSTL_STABLE_SORT_CUT_OFF;
if (__n > __sort_cut_off)
{
assert(__nsort > 0 && __nsort <= __n);
buffer<_ValueType> __buf(__n);
using tbb::task;
task::spawn_root_and_wait(*new (task::allocate_root())
stable_sort_task<_RandomAccessIterator, _ValueType*, _Compare, _LeafSort>(
__xs, __xe, (_ValueType*)__buf.get(), 2, __comp, __leaf_sort, __nsort));
return;
}
//serial sort
__leaf_sort(__xs, __xe, __comp);
});
}
//------------------------------------------------------------------------
// parallel_merge
//------------------------------------------------------------------------
template <class _ExecutionPolicy, typename _RandomAccessIterator1, typename _RandomAccessIterator2,
typename _RandomAccessIterator3, typename _Compare, typename _LeafMerge>
void
parallel_merge(_ExecutionPolicy&&, _RandomAccessIterator1 __xs, _RandomAccessIterator1 __xe,
_RandomAccessIterator2 __ys, _RandomAccessIterator2 __ye, _RandomAccessIterator3 __zs, _Compare __comp,
_LeafMerge __leaf_merge)
{
typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type _DifferenceType1;
typedef typename std::iterator_traits<_RandomAccessIterator2>::difference_type _DifferenceType2;
typedef typename std::common_type<_DifferenceType1, _DifferenceType2>::type _SizeType;
const _SizeType __n = (__xe - __xs) + (__ye - __ys);
const _SizeType __merge_cut_off = __PSTL_MERGE_CUT_OFF;
if (__n <= __merge_cut_off)
{
// Fall back on serial merge
__leaf_merge(__xs, __xe, __ys, __ye, __zs, __comp);
}
else
{
tbb::this_task_arena::isolate([=]() {
typedef merge_task<_RandomAccessIterator1, _RandomAccessIterator2, _RandomAccessIterator3, _Compare,
par_backend::binary_no_op, _LeafMerge>
_TaskType;
tbb::task::spawn_root_and_wait(*new (tbb::task::allocate_root()) _TaskType(
__xs, __xe, __ys, __ye, __zs, __comp, par_backend::binary_no_op(), __leaf_merge));
});
}
}
//------------------------------------------------------------------------
// parallel_invoke
//------------------------------------------------------------------------
template <class _ExecutionPolicy, typename _F1, typename _F2>
void
parallel_invoke(_ExecutionPolicy&&, _F1&& __f1, _F2&& __f2)
{
//TODO: a version of tbb::this_task_arena::isolate with variadic arguments pack should be added in the future
tbb::this_task_arena::isolate([&]() { tbb::parallel_invoke(std::forward<_F1>(__f1), std::forward<_F2>(__f2)); });
}
} // namespace par_backend
} // namespace __pstl
#endif /* __PSTL_parallel_backend_tbb_H */

View File

@ -0,0 +1,195 @@
// -*- C++ -*-
//===-- parallel_backend_utils.h ------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_parallel_backend_utils_H
#define __PSTL_parallel_backend_utils_H
#include <iterator>
#include <utility>
#include "utils.h"
namespace __pstl
{
namespace par_backend
{
//! Destroy sequence [xs,xe)
struct serial_destroy
{
template <typename _RandomAccessIterator>
void
operator()(_RandomAccessIterator __zs, _RandomAccessIterator __ze)
{
typedef typename std::iterator_traits<_RandomAccessIterator>::value_type _ValueType;
while (__zs != __ze)
{
--__ze;
(*__ze).~_ValueType();
}
}
};
//! Merge sequences [__xs,__xe) and [__ys,__ye) to output sequence [__zs,(__xe-__xs)+(__ye-__ys)), using std::move
template <class _MoveValues, class _MoveSequences>
struct serial_move_merge
{
const std::size_t _M_nmerge;
_MoveValues _M_move_values;
_MoveSequences _M_move_sequences;
explicit serial_move_merge(std::size_t __nmerge, _MoveValues __move_values, _MoveSequences __move_sequences)
: _M_nmerge(__nmerge), _M_move_values(__move_values), _M_move_sequences(__move_sequences)
{
}
template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _RandomAccessIterator3, class _Compare>
void
operator()(_RandomAccessIterator1 __xs, _RandomAccessIterator1 __xe, _RandomAccessIterator2 __ys,
_RandomAccessIterator2 __ye, _RandomAccessIterator3 __zs, _Compare __comp)
{
auto __n = _M_nmerge;
assert(__n > 0);
if (__xs != __xe)
{
if (__ys != __ye)
{
for (;;)
{
if (__comp(*__ys, *__xs))
{
_M_move_values(__ys, __zs);
++__zs, --__n;
if (++__ys == __ye)
{
break;
}
else if (__n == 0)
{
__zs = _M_move_sequences(__ys, __ye, __zs);
break;
}
else
{
}
}
else
{
_M_move_values(__xs, __zs);
++__zs, --__n;
if (++__xs == __xe)
{
_M_move_sequences(__ys, __ye, __zs);
return;
}
else if (__n == 0)
{
__zs = _M_move_sequences(__xs, __xe, __zs);
_M_move_sequences(__ys, __ye, __zs);
return;
}
else
{
}
}
}
}
__ys = __xs;
__ye = __xe;
}
_M_move_sequences(__ys, __ye, __zs);
}
};
template <typename _RandomAccessIterator1, typename _OutputIterator>
void
init_buf(_RandomAccessIterator1 __xs, _RandomAccessIterator1 __xe, _OutputIterator __zs, bool __bMove)
{
const _OutputIterator __ze = __zs + (__xe - __xs);
typedef typename std::iterator_traits<_OutputIterator>::value_type _ValueType;
if (__bMove)
{
// Initialize the temporary buffer and move keys to it.
for (; __zs != __ze; ++__xs, ++__zs)
new (&*__zs) _ValueType(std::move(*__xs));
}
else
{
// Initialize the temporary buffer
for (; __zs != __ze; ++__zs)
new (&*__zs) _ValueType;
}
}
template <typename _Buf>
class stack
{
typedef typename std::iterator_traits<decltype(_Buf(0).get())>::value_type _ValueType;
typedef typename std::iterator_traits<_ValueType*>::difference_type _DifferenceType;
_Buf _M_buf;
_ValueType* _M_ptr;
_DifferenceType _M_maxsize;
stack(const stack&) = delete;
void
operator=(const stack&) = delete;
public:
stack(_DifferenceType __max_size) : _M_buf(__max_size), _M_maxsize(__max_size) { _M_ptr = _M_buf.get(); }
~stack()
{
assert(size() <= _M_maxsize);
while (!empty())
pop();
}
const _Buf&
buffer() const
{
return _M_buf;
}
size_t
size() const
{
assert(_M_ptr - _M_buf.get() <= _M_maxsize);
assert(_M_ptr - _M_buf.get() >= 0);
return _M_ptr - _M_buf.get();
}
bool
empty() const
{
assert(_M_ptr >= _M_buf.get());
return _M_ptr == _M_buf.get();
}
void
push(const _ValueType& __v)
{
assert(size() < _M_maxsize);
new (_M_ptr) _ValueType(__v);
++_M_ptr;
}
const _ValueType&
top() const
{
return *(_M_ptr - 1);
}
void
pop()
{
assert(_M_ptr > _M_buf.get());
--_M_ptr;
(*_M_ptr).~_ValueType();
}
};
} // namespace par_backend
} // namespace __pstl
#endif /* __PSTL_parallel_backend_utils_H */

View File

@ -0,0 +1,82 @@
// -*- C++ -*-
//===-- parallel_impl.h ---------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_parallel_impl_H
#define __PSTL_parallel_impl_H
#include <atomic>
// This header defines the minimum set of parallel routines required to support Parallel STL,
// implemented on top of Intel(R) Threading Building Blocks (Intel(R) TBB) library
namespace __pstl
{
namespace internal
{
//------------------------------------------------------------------------
// parallel_find
//-----------------------------------------------------------------------
/** Return extremum value returned by brick f[i,j) for subranges [i,j) of [first,last)
Each f[i,j) must return a value in [i,j). */
template <class _ExecutionPolicy, class _Index, class _Brick, class _Compare>
_Index
parallel_find(_ExecutionPolicy&& __exec, _Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first)
{
typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType;
const _DifferenceType __n = __last - __first;
_DifferenceType __initial_dist = __b_first ? __n : -1;
std::atomic<_DifferenceType> __extremum(__initial_dist);
// TODO: find out what is better here: parallel_for or parallel_reduce
par_backend::parallel_for(std::forward<_ExecutionPolicy>(__exec), __first, __last,
[__comp, __f, __first, &__extremum](_Index __i, _Index __j) {
// See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of
// why using a shared variable scales fairly well in this situation.
if (__comp(__i - __first, __extremum))
{
_Index __res = __f(__i, __j);
// If not '__last' returned then we found what we want so put this to extremum
if (__res != __j)
{
const _DifferenceType __k = __res - __first;
for (_DifferenceType __old = __extremum; __comp(__k, __old);
__old = __extremum)
{
__extremum.compare_exchange_weak(__old, __k);
}
}
}
});
return __extremum != __initial_dist ? __first + __extremum : __last;
}
//------------------------------------------------------------------------
// parallel_or
//------------------------------------------------------------------------
//! Return true if brick f[i,j) returns true for some subrange [i,j) of [first,last)
template <class _ExecutionPolicy, class _Index, class _Brick>
bool
parallel_or(_ExecutionPolicy&& __exec, _Index __first, _Index __last, _Brick __f)
{
std::atomic<bool> __found(false);
par_backend::parallel_for(std::forward<_ExecutionPolicy>(__exec), __first, __last,
[__f, &__found](_Index __i, _Index __j) {
if (!__found.load(std::memory_order_relaxed) && __f(__i, __j))
{
__found.store(true, std::memory_order_relaxed);
par_backend::cancel_execution();
}
});
return __found;
}
} // namespace internal
} // namespace __pstl
#endif /* __PSTL_parallel_impl_H */

View File

@ -0,0 +1,175 @@
// -*- C++ -*-
//===-- pstl_config.h -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_config_H
#define __PSTL_config_H
#define PSTL_VERSION 203
#define PSTL_VERSION_MAJOR (PSTL_VERSION / 100)
#define PSTL_VERSION_MINOR (PSTL_VERSION - PSTL_VERSION_MAJOR * 100)
// Check the user-defined macro for parallel policies
#if defined(PSTL_USE_PARALLEL_POLICIES)
#undef __PSTL_USE_PAR_POLICIES
#define __PSTL_USE_PAR_POLICIES PSTL_USE_PARALLEL_POLICIES
// Check the internal macro for parallel policies
#elif !defined(__PSTL_USE_PAR_POLICIES)
#define __PSTL_USE_PAR_POLICIES 1
#endif
#if __PSTL_USE_PAR_POLICIES
#if !defined(__PSTL_PAR_BACKEND_TBB)
#define __PSTL_PAR_BACKEND_TBB 1
#endif
#else
#undef __PSTL_PAR_BACKEND_TBB
#endif
// Check the user-defined macro for warnings
#if defined(PSTL_USAGE_WARNINGS)
#undef __PSTL_USAGE_WARNINGS
#define __PSTL_USAGE_WARNINGS PSTL_USAGE_WARNINGS
// Check the internal macro for warnings
#elif !defined(__PSTL_USAGE_WARNINGS)
#define __PSTL_USAGE_WARNINGS 0
#endif
// Portability "#pragma" definition
#ifdef _MSC_VER
#define __PSTL_PRAGMA(x) __pragma(x)
#else
#define __PSTL_PRAGMA(x) _Pragma(#x)
#endif
#define __PSTL_STRING_AUX(x) #x
#define __PSTL_STRING(x) __PSTL_STRING_AUX(x)
#define __PSTL_STRING_CONCAT(x, y) x #y
// note that when ICC or Clang is in use, __PSTL_GCC_VERSION might not fully match
// the actual GCC version on the system.
#define __PSTL_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if __clang__
// according to clang documentation, version can be vendor specific
#define __PSTL_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
#endif
// Enable SIMD for compilers that support OpenMP 4.0
#if (_OPENMP >= 201307) || (__INTEL_COMPILER >= 1600) || (!defined(__INTEL_COMPILER) && __PSTL_GCC_VERSION >= 40900)
#define __PSTL_PRAGMA_SIMD __PSTL_PRAGMA(omp simd)
#define __PSTL_PRAGMA_DECLARE_SIMD __PSTL_PRAGMA(omp declare simd)
#define __PSTL_PRAGMA_SIMD_REDUCTION(PRM) __PSTL_PRAGMA(omp simd reduction(PRM))
#elif !defined(_MSC_VER) //#pragma simd
#define __PSTL_PRAGMA_SIMD __PSTL_PRAGMA(simd)
#define __PSTL_PRAGMA_DECLARE_SIMD
#define __PSTL_PRAGMA_SIMD_REDUCTION(PRM) __PSTL_PRAGMA(simd reduction(PRM))
#else //no simd
#define __PSTL_PRAGMA_SIMD
#define __PSTL_PRAGMA_DECLARE_SIMD
#define __PSTL_PRAGMA_SIMD_REDUCTION(PRM)
#endif //Enable SIMD
#if (__INTEL_COMPILER)
#define __PSTL_PRAGMA_FORCEINLINE __PSTL_PRAGMA(forceinline)
#else
#define __PSTL_PRAGMA_FORCEINLINE
#endif
#if (__INTEL_COMPILER >= 1900)
#define __PSTL_PRAGMA_SIMD_SCAN(PRM) __PSTL_PRAGMA(omp simd reduction(inscan, PRM))
#define __PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(PRM) __PSTL_PRAGMA(omp scan inclusive(PRM))
#define __PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(PRM) __PSTL_PRAGMA(omp scan exclusive(PRM))
#else
#define __PSTL_PRAGMA_SIMD_SCAN(PRM)
#define __PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(PRM)
#define __PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(PRM)
#endif
// Should be defined to 1 for environments with a vendor implementation of C++17 execution policies
#define __PSTL_CPP17_EXECUTION_POLICIES_PRESENT (_MSC_VER >= 1912)
#define __PSTL_CPP14_2RANGE_MISMATCH_EQUAL_PRESENT \
(_MSC_VER >= 1900 || __cplusplus >= 201300L || __cpp_lib_robust_nonmodifying_seq_ops == 201304)
#define __PSTL_CPP14_MAKE_REVERSE_ITERATOR_PRESENT \
(_MSC_VER >= 1900 || __cplusplus >= 201402L || __cpp_lib_make_reverse_iterator == 201402)
#define __PSTL_CPP14_INTEGER_SEQUENCE_PRESENT (_MSC_VER >= 1900 || __cplusplus >= 201402L)
#define __PSTL_CPP14_VARIABLE_TEMPLATES_PRESENT \
(!__INTEL_COMPILER || __INTEL_COMPILER >= 1700) && (_MSC_FULL_VER >= 190023918 || __cplusplus >= 201402L)
#define __PSTL_EARLYEXIT_PRESENT (__INTEL_COMPILER >= 1800)
#define __PSTL_MONOTONIC_PRESENT (__INTEL_COMPILER >= 1800)
#if (__INTEL_COMPILER >= 1900 || !defined(__INTEL_COMPILER) && __PSTL_GCC_VERSION >= 40900 || _OPENMP >= 201307)
#define __PSTL_UDR_PRESENT 1
#else
#define __PSTL_UDR_PRESENT 0
#endif
#define __PSTL_UDS_PRESENT (__INTEL_COMPILER >= 1900 && __INTEL_COMPILER_BUILD_DATE >= 20180626)
#if __PSTL_EARLYEXIT_PRESENT
#define __PSTL_PRAGMA_SIMD_EARLYEXIT __PSTL_PRAGMA(omp simd early_exit)
#else
#define __PSTL_PRAGMA_SIMD_EARLYEXIT
#endif
#if __PSTL_MONOTONIC_PRESENT
#define __PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC(PRM) __PSTL_PRAGMA(omp ordered simd monotonic(PRM))
#define __PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC_2ARGS(PRM1, PRM2) __PSTL_PRAGMA(omp ordered simd monotonic(PRM1, PRM2))
#else
#define __PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC(PRM)
#define __PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC_2ARGS(PRM1, PRM2)
#endif
// Declaration of reduction functor, where
// NAME - the name of the functor
// OP - type of the callable object with the reduction operation
// omp_in - refers to the local partial result
// omp_out - refers to the final value of the combiner operator
// omp_priv - refers to the private copy of the initial value
// omp_orig - refers to the original variable to be reduced
#define __PSTL_PRAGMA_DECLARE_REDUCTION(NAME, OP) \
__PSTL_PRAGMA(omp declare reduction(NAME : OP : omp_out(omp_in)) initializer(omp_priv = omp_orig))
#if (__INTEL_COMPILER >= 1600)
#define __PSTL_PRAGMA_VECTOR_UNALIGNED __PSTL_PRAGMA(vector unaligned)
#else
#define __PSTL_PRAGMA_VECTOR_UNALIGNED
#endif
// Check the user-defined macro to use non-temporal stores
#if defined(PSTL_USE_NONTEMPORAL_STORES) && (__INTEL_COMPILER >= 1600)
#define __PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED __PSTL_PRAGMA(vector nontemporal)
#else
#define __PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED
#endif
#if _MSC_VER || __INTEL_COMPILER //the preprocessors don't type a message location
#define __PSTL_PRAGMA_LOCATION __FILE__ ":" __PSTL_STRING(__LINE__) ": [Parallel STL message]: "
#else
#define __PSTL_PRAGMA_LOCATION " [Parallel STL message]: "
#endif
#define __PSTL_PRAGMA_MESSAGE_IMPL(x) __PSTL_PRAGMA(message(__PSTL_STRING_CONCAT(__PSTL_PRAGMA_LOCATION, x)))
#if __PSTL_USAGE_WARNINGS
#define __PSTL_PRAGMA_MESSAGE(x) __PSTL_PRAGMA_MESSAGE_IMPL(x)
#define __PSTL_PRAGMA_MESSAGE_POLICIES(x) __PSTL_PRAGMA_MESSAGE_IMPL(x)
#else
#define __PSTL_PRAGMA_MESSAGE(x)
#define __PSTL_PRAGMA_MESSAGE_POLICIES(x)
#endif
// broken macros
#define __PSTL_CPP11_STD_ROTATE_BROKEN ((__GLIBCXX__ && __GLIBCXX__ < 20150716) || (_MSC_VER && _MSC_VER < 1800))
#define __PSTL_ICC_18_OMP_SIMD_BROKEN (__INTEL_COMPILER == 1800)
#endif /* __PSTL_config_H */

View File

@ -0,0 +1,856 @@
// -*- C++ -*-
//===-- unseq_backend_simd.h ----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_unseq_backend_simd_H
#define __PSTL_unseq_backend_simd_H
#include <type_traits>
#include "pstl_config.h"
#include "utils.h"
// This header defines the minimum set of vector routines required
// to support parallel STL.
namespace __pstl
{
namespace unseq_backend
{
// Expect vector width up to 64 (or 512 bit)
const std::size_t __lane_size = 64;
template <class _Iterator, class _DifferenceType, class _Function>
_Iterator
simd_walk_1(_Iterator __first, _DifferenceType __n, _Function __f) noexcept
{
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 0; __i < __n; ++__i)
__f(__first[__i]);
return __first + __n;
}
template <class _Iterator1, class _DifferenceType, class _Iterator2, class _Function>
_Iterator2
simd_walk_2(_Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Function __f) noexcept
{
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 0; __i < __n; ++__i)
__f(__first1[__i], __first2[__i]);
return __first2 + __n;
}
template <class _Iterator1, class _DifferenceType, class _Iterator2, class _Iterator3, class _Function>
_Iterator3
simd_walk_3(_Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Iterator3 __first3, _Function __f) noexcept
{
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 0; __i < __n; ++__i)
__f(__first1[__i], __first2[__i], __first3[__i]);
return __first3 + __n;
}
// TODO: check whether simd_first() can be used here
template <class _Index, class _DifferenceType, class _Pred>
bool
simd_or(_Index __first, _DifferenceType __n, _Pred __pred) noexcept
{
#if __PSTL_EARLYEXIT_PRESENT
_DifferenceType __i;
__PSTL_PRAGMA_VECTOR_UNALIGNED
__PSTL_PRAGMA_SIMD_EARLYEXIT
for (__i = 0; __i < __n; ++__i)
if (__pred(__first[__i]))
break;
return __i < __n;
#else
_DifferenceType __block_size = 4 < __n ? 4 : __n;
const _Index __last = __first + __n;
while (__last != __first)
{
int32_t __flag = 1;
__PSTL_PRAGMA_SIMD_REDUCTION(& : __flag)
for (_DifferenceType __i = 0; __i < __block_size; ++__i)
if (__pred(*(__first + __i)))
__flag = 0;
if (!__flag)
return true;
__first += __block_size;
if (__last - __first >= __block_size << 1)
{
// Double the block _Size. Any unnecessary iterations can be amortized against work done so far.
__block_size <<= 1;
}
else
{
__block_size = __last - __first;
}
}
return false;
#endif
}
template <class _Index, class _DifferenceType, class _Compare>
_Index
simd_first(_Index __first, _DifferenceType __begin, _DifferenceType __end, _Compare __comp) noexcept
{
#if __PSTL_EARLYEXIT_PRESENT
_DifferenceType __i = __begin;
__PSTL_PRAGMA_VECTOR_UNALIGNED // Do not generate peel loop part
__PSTL_PRAGMA_SIMD_EARLYEXIT for (; __i < __end; ++__i)
{
if (__comp(__first, __i))
{
break;
}
}
return __first + __i;
#else
// Experiments show good block sizes like this
const _DifferenceType __block_size = 8;
alignas(__lane_size) _DifferenceType __lane[__block_size] = {0};
while (__end - __begin >= __block_size)
{
_DifferenceType __found = 0;
__PSTL_PRAGMA_VECTOR_UNALIGNED // Do not generate peel loop part
__PSTL_PRAGMA_SIMD_REDUCTION(|
: __found) for (_DifferenceType __i = __begin; __i < __begin + __block_size;
++__i)
{
const _DifferenceType __t = __comp(__first, __i);
__lane[__i - __begin] = __t;
__found |= __t;
}
if (__found)
{
_DifferenceType __i;
// This will vectorize
for (__i = 0; __i < __block_size; ++__i)
{
if (__lane[__i])
{
break;
}
}
return __first + __begin + __i;
}
__begin += __block_size;
}
//Keep remainder scalar
while (__begin != __end)
{
if (__comp(__first, __begin))
{
return __first + __begin;
}
++__begin;
}
return __first + __end;
#endif //__PSTL_EARLYEXIT_PRESENT
}
template <class _Index1, class _DifferenceType, class _Index2, class _Pred>
std::pair<_Index1, _Index2>
simd_first(_Index1 __first1, _DifferenceType __n, _Index2 __first2, _Pred __pred) noexcept
{
#if __PSTL_EARLYEXIT_PRESENT
_DifferenceType __i = 0;
__PSTL_PRAGMA_VECTOR_UNALIGNED
__PSTL_PRAGMA_SIMD_EARLYEXIT
for (; __i < __n; ++__i)
if (__pred(__first1[__i], __first2[__i]))
break;
return std::make_pair(__first1 + __i, __first2 + __i);
#else
const _Index1 __last1 = __first1 + __n;
const _Index2 __last2 = __first2 + __n;
// Experiments show good block sizes like this
const _DifferenceType __block_size = 8;
alignas(__lane_size) _DifferenceType __lane[__block_size] = {0};
while (__last1 - __first1 >= __block_size)
{
_DifferenceType __found = 0;
_DifferenceType __i;
__PSTL_PRAGMA_VECTOR_UNALIGNED // Do not generate peel loop part
__PSTL_PRAGMA_SIMD_REDUCTION(|
: __found) for (__i = 0; __i < __block_size; ++__i)
{
const _DifferenceType __t = __pred(__first1[__i], __first2[__i]);
__lane[__i] = __t;
__found |= __t;
}
if (__found)
{
_DifferenceType __i;
// This will vectorize
for (__i = 0; __i < __block_size; ++__i)
{
if (__lane[__i])
break;
}
return std::make_pair(__first1 + __i, __first2 + __i);
}
__first1 += __block_size;
__first2 += __block_size;
}
//Keep remainder scalar
for (; __last1 != __first1; ++__first1, ++__first2)
if (__pred(*(__first1), *(__first2)))
return std::make_pair(__first1, __first2);
return std::make_pair(__last1, __last2);
#endif //__PSTL_EARLYEXIT_PRESENT
}
template <class _Index, class _DifferenceType, class _Pred>
_DifferenceType
simd_count(_Index __index, _DifferenceType __n, _Pred __pred) noexcept
{
_DifferenceType __count = 0;
__PSTL_PRAGMA_SIMD_REDUCTION(+ : __count)
for (_DifferenceType __i = 0; __i < __n; ++__i)
if (__pred(*(__index + __i)))
++__count;
return __count;
}
template <class _InputIterator, class _DifferenceType, class _OutputIterator, class _BinaryPredicate>
_OutputIterator
simd_unique_copy(_InputIterator __first, _DifferenceType __n, _OutputIterator __result,
_BinaryPredicate __pred) noexcept
{
if (__n == 0)
return __result;
_DifferenceType __cnt = 1;
__result[0] = __first[0];
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 1; __i < __n; ++__i)
{
__PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC(__cnt : 1)
if (!__pred(__first[__i], __first[__i - 1]))
{
__result[__cnt] = __first[__i];
++__cnt;
}
}
return __result + __cnt;
}
template <class _InputIterator, class _DifferenceType, class _OutputIterator, class _Assigner>
_OutputIterator
simd_assign(_InputIterator __first, _DifferenceType __n, _OutputIterator __result, _Assigner __assigner) noexcept
{
__PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 0; __i < __n; ++__i)
__assigner(__first + __i, __result + __i);
return __result + __n;
}
template <class _InputIterator, class _DifferenceType, class _OutputIterator, class _UnaryPredicate>
_OutputIterator
simd_copy_if(_InputIterator __first, _DifferenceType __n, _OutputIterator __result, _UnaryPredicate __pred) noexcept
{
_DifferenceType __cnt = 0;
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 0; __i < __n; ++__i)
{
__PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC(__cnt : 1)
if (__pred(__first[__i]))
{
__result[__cnt] = __first[__i];
++__cnt;
}
}
return __result + __cnt;
}
template <class _InputIterator, class _DifferenceType, class _BinaryPredicate>
_DifferenceType
simd_calc_mask_2(_InputIterator __first, _DifferenceType __n, bool* __mask, _BinaryPredicate __pred) noexcept
{
_DifferenceType __count = 0;
__PSTL_PRAGMA_SIMD_REDUCTION(+ : __count)
for (_DifferenceType __i = 0; __i < __n; ++__i)
{
__mask[__i] = !__pred(__first[__i], __first[__i - 1]);
__count += __mask[__i];
}
return __count;
}
template <class _InputIterator, class _DifferenceType, class _UnaryPredicate>
_DifferenceType
simd_calc_mask_1(_InputIterator __first, _DifferenceType __n, bool* __mask, _UnaryPredicate __pred) noexcept
{
_DifferenceType __count = 0;
__PSTL_PRAGMA_SIMD_REDUCTION(+ : __count)
for (_DifferenceType __i = 0; __i < __n; ++__i)
{
__mask[__i] = __pred(__first[__i]);
__count += __mask[__i];
}
return __count;
}
template <class _InputIterator, class _DifferenceType, class _OutputIterator, class _Assigner>
void
simd_copy_by_mask(_InputIterator __first, _DifferenceType __n, _OutputIterator __result, bool* __mask,
_Assigner __assigner) noexcept
{
_DifferenceType __cnt = 0;
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 0; __i < __n; ++__i)
{
if (__mask[__i])
{
__PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC(__cnt : 1)
{
__assigner(__first + __i, __result + __cnt);
++__cnt;
}
}
}
}
template <class _InputIterator, class _DifferenceType, class _OutputIterator1, class _OutputIterator2>
void
simd_partition_by_mask(_InputIterator __first, _DifferenceType __n, _OutputIterator1 __out_true,
_OutputIterator2 __out_false, bool* __mask) noexcept
{
_DifferenceType __cnt_true = 0, __cnt_false = 0;
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 0; __i < __n; ++__i)
{
__PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC_2ARGS(__cnt_true : 1, __cnt_false : 1)
if (__mask[__i])
{
__out_true[__cnt_true] = __first[__i];
++__cnt_true;
}
else
{
__out_false[__cnt_false] = __first[__i];
++__cnt_false;
}
}
}
template <class _Index, class _DifferenceType, class _Tp>
_Index
simd_fill_n(_Index __first, _DifferenceType __n, const _Tp& __value) noexcept
{
__PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 0; __i < __n; ++__i)
__first[__i] = __value;
return __first + __n;
}
template <class _Index, class _DifferenceType, class _Generator>
_Index
simd_generate_n(_Index __first, _DifferenceType __size, _Generator __g) noexcept
{
__PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 0; __i < __size; ++__i)
__first[__i] = __g();
return __first + __size;
}
template <class _Index, class _BinaryPredicate>
_Index
simd_adjacent_find(_Index __first, _Index __last, _BinaryPredicate __pred, bool __or_semantic) noexcept
{
if (__last - __first < 2)
return __last;
typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType;
_DifferenceType __i = 0;
#if __PSTL_EARLYEXIT_PRESENT
//Some compiler versions fail to compile the following loop when iterators are used. Indices are used instead
const _DifferenceType __n = __last - __first - 1;
__PSTL_PRAGMA_VECTOR_UNALIGNED
__PSTL_PRAGMA_SIMD_EARLYEXIT
for (; __i < __n; ++__i)
if (__pred(__first[__i], __first[__i + 1]))
break;
return __i < __n ? __first + __i : __last;
#else
// Experiments show good block sizes like this
//TODO: to consider tuning block_size for various data types
const _DifferenceType __block_size = 8;
alignas(__lane_size) _DifferenceType __lane[__block_size] = {0};
while (__last - __first >= __block_size)
{
_DifferenceType __found = 0;
__PSTL_PRAGMA_VECTOR_UNALIGNED // Do not generate peel loop part
__PSTL_PRAGMA_SIMD_REDUCTION(|
: __found) for (__i = 0; __i < __block_size - 1; ++__i)
{
//TODO: to improve SIMD vectorization
const _DifferenceType __t = __pred(*(__first + __i), *(__first + __i + 1));
__lane[__i] = __t;
__found |= __t;
}
//Process a pair of elements on a boundary of a data block
if (__first + __block_size < __last && __pred(*(__first + __i), *(__first + __i + 1)))
__lane[__i] = __found = 1;
if (__found)
{
if (__or_semantic)
return __first;
// This will vectorize
for (__i = 0; __i < __block_size; ++__i)
if (__lane[__i])
break;
return __first + __i; //As far as found is true a __result (__lane[__i] is true) is guaranteed
}
__first += __block_size;
}
//Process the rest elements
for (; __last - __first > 1; ++__first)
if (__pred(*__first, *(__first + 1)))
return __first;
return __last;
#endif
}
// It was created to reduce the code inside std::enable_if
template <typename _Tp, typename _BinaryOperation>
using is_arithmetic_plus = std::integral_constant<bool, std::is_arithmetic<_Tp>::value &&
std::is_same<_BinaryOperation, std::plus<_Tp>>::value>;
template <typename _DifferenceType, typename _Tp, typename _BinaryOperation, typename _UnaryOperation>
typename std::enable_if<is_arithmetic_plus<_Tp, _BinaryOperation>::value, _Tp>::type
simd_transform_reduce(_DifferenceType __n, _Tp __init, _BinaryOperation, _UnaryOperation __f) noexcept
{
__PSTL_PRAGMA_SIMD_REDUCTION(+ : __init)
for (_DifferenceType __i = 0; __i < __n; ++__i)
__init += __f(__i);
return __init;
}
template <typename _Size, typename _Tp, typename _BinaryOperation, typename _UnaryOperation>
typename std::enable_if<!is_arithmetic_plus<_Tp, _BinaryOperation>::value, _Tp>::type
simd_transform_reduce(_Size __n, _Tp __init, _BinaryOperation __binary_op, _UnaryOperation __f) noexcept
{
const std::size_t __block_size = __lane_size / sizeof(_Tp);
if (__n > 2 * __block_size && __block_size > 1)
{
alignas(__lane_size) char __lane_[__lane_size];
_Tp* __lane = reinterpret_cast<_Tp*>(__lane_);
// initializer
__PSTL_PRAGMA_SIMD
for (_Size __i = 0; __i < __block_size; ++__i)
{
::new (__lane + __i) _Tp(__binary_op(__f(__i), __f(__block_size + __i)));
}
// main loop
_Size __i = 2 * __block_size;
const _Size last_iteration = __block_size * (__n / __block_size);
for (; __i < last_iteration; __i += __block_size)
{
__PSTL_PRAGMA_SIMD
for (_Size __j = 0; __j < __block_size; ++__j)
{
__lane[__j] = __binary_op(__lane[__j], __f(__i + __j));
}
}
// remainder
__PSTL_PRAGMA_SIMD
for (_Size __j = 0; __j < __n - last_iteration; ++__j)
{
__lane[__j] = __binary_op(__lane[__j], __f(last_iteration + __j));
}
// combiner
for (_Size __i = 0; __i < __block_size; ++__i)
{
__init = __binary_op(__init, __lane[__i]);
}
// destroyer
__PSTL_PRAGMA_SIMD
for (_Size __i = 0; __i < __block_size; ++__i)
{
__lane[__i].~_Tp();
}
}
else
{
for (_Size __i = 0; __i < __n; ++__i)
{
__init = __binary_op(__init, __f(__i));
}
}
return __init;
}
// Exclusive scan for "+" and arithmetic types
template <class _InputIterator, class _Size, class _OutputIterator, class _UnaryOperation, class _Tp,
class _BinaryOperation>
typename std::enable_if<is_arithmetic_plus<_Tp, _BinaryOperation>::value, std::pair<_OutputIterator, _Tp>>::type
simd_scan(_InputIterator __first, _Size __n, _OutputIterator __result, _UnaryOperation __unary_op, _Tp __init,
_BinaryOperation, /*Inclusive*/ std::false_type)
{
__PSTL_PRAGMA_SIMD_SCAN(+ : __init)
for (_Size __i = 0; __i < __n; ++__i)
{
__result[__i] = __init;
__PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(__init)
__init += __unary_op(__first[__i]);
}
return std::make_pair(__result + __n, __init);
}
// As soon as we cannot call __binary_op in "combiner" we create a wrapper over _Tp to encapsulate __binary_op
template <typename _Tp, typename _BinaryOp>
struct _Combiner
{
_Tp __value;
_BinaryOp* __bin_op; // Here is a pointer to function because of default ctor
_Combiner() : __value{}, __bin_op(nullptr) {}
_Combiner(const _Tp& value, const _BinaryOp* bin_op) : __value(value), __bin_op(const_cast<_BinaryOp*>(bin_op)) {}
_Combiner(const _Combiner& __obj) : __value{}, __bin_op(__obj.__bin_op) {}
void
operator()(const _Combiner& __obj)
{
__value = (*__bin_op)(__value, __obj.__value);
}
};
// Exclusive scan for other binary operations and types
template <class _InputIterator, class _Size, class _OutputIterator, class _UnaryOperation, class _Tp,
class _BinaryOperation>
typename std::enable_if<!is_arithmetic_plus<_Tp, _BinaryOperation>::value, std::pair<_OutputIterator, _Tp>>::type
simd_scan(_InputIterator __first, _Size __n, _OutputIterator __result, _UnaryOperation __unary_op, _Tp __init,
_BinaryOperation __binary_op, /*Inclusive*/ std::false_type)
{
typedef _Combiner<_Tp, _BinaryOperation> _CombinerType;
_CombinerType __init_{__init, &__binary_op};
__PSTL_PRAGMA_DECLARE_REDUCTION(__bin_op, _CombinerType)
__PSTL_PRAGMA_SIMD_SCAN(__bin_op : __init_)
for (_Size __i = 0; __i < __n; ++__i)
{
__result[__i] = __init_.__value;
__PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(__init_)
__PSTL_PRAGMA_FORCEINLINE
__init_.__value = __binary_op(__init_.__value, __unary_op(__first[__i]));
}
return std::make_pair(__result + __n, __init_.__value);
}
// Inclusive scan for "+" and arithmetic types
template <class _InputIterator, class _Size, class _OutputIterator, class _UnaryOperation, class _Tp,
class _BinaryOperation>
typename std::enable_if<is_arithmetic_plus<_Tp, _BinaryOperation>::value, std::pair<_OutputIterator, _Tp>>::type
simd_scan(_InputIterator __first, _Size __n, _OutputIterator __result, _UnaryOperation __unary_op, _Tp __init,
_BinaryOperation, /*Inclusive*/ std::true_type)
{
__PSTL_PRAGMA_SIMD_SCAN(+ : __init)
for (_Size __i = 0; __i < __n; ++__i)
{
__init += __unary_op(__first[__i]);
__PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(__init)
__result[__i] = __init;
}
return std::make_pair(__result + __n, __init);
}
// Inclusive scan for other binary operations and types
template <class _InputIterator, class _Size, class _OutputIterator, class _UnaryOperation, class _Tp,
class _BinaryOperation>
typename std::enable_if<!is_arithmetic_plus<_Tp, _BinaryOperation>::value, std::pair<_OutputIterator, _Tp>>::type
simd_scan(_InputIterator __first, _Size __n, _OutputIterator __result, _UnaryOperation __unary_op, _Tp __init,
_BinaryOperation __binary_op, std::true_type)
{
typedef _Combiner<_Tp, _BinaryOperation> _CombinerType;
_CombinerType __init_{__init, &__binary_op};
__PSTL_PRAGMA_DECLARE_REDUCTION(__bin_op, _CombinerType)
__PSTL_PRAGMA_SIMD_SCAN(__bin_op : __init_)
for (_Size __i = 0; __i < __n; ++__i)
{
__PSTL_PRAGMA_FORCEINLINE
__init_.__value = __binary_op(__init_.__value, __unary_op(__first[__i]));
__PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(__init_)
__result[__i] = __init_.__value;
}
return std::make_pair(__result + __n, __init_.__value);
}
// [restriction] - std::iterator_traits<_ForwardIterator>::value_type should be DefaultConstructible.
// complexity [violation] - We will have at most (__n-1 + number_of_lanes) comparisons instead of at most __n-1.
template <typename _ForwardIterator, typename _Size, typename _Compare>
_ForwardIterator
simd_min_element(_ForwardIterator __first, _Size __n, _Compare __comp) noexcept
{
if (__n == 0)
{
return __first;
}
typedef typename std::iterator_traits<_ForwardIterator>::value_type _ValueType;
struct _ComplexType
{
_ValueType __min_val;
_Size __min_ind;
_Compare* __min_comp;
_ComplexType() : __min_val{}, __min_ind{}, __min_comp(nullptr) {}
_ComplexType(const _ValueType& val, const _Compare* comp)
: __min_val(val), __min_ind(0), __min_comp(const_cast<_Compare*>(comp))
{
}
_ComplexType(const _ComplexType& __obj)
: __min_val(__obj.__min_val), __min_ind(__obj.__min_ind), __min_comp(__obj.__min_comp)
{
}
__PSTL_PRAGMA_DECLARE_SIMD
void
operator()(const _ComplexType& __obj)
{
if (!(*__min_comp)(__min_val, __obj.__min_val) &&
((*__min_comp)(__obj.__min_val, __min_val) || __obj.__min_ind - __min_ind < 0))
{
__min_val = __obj.__min_val;
__min_ind = __obj.__min_ind;
}
}
};
_ComplexType __init{*__first, &__comp};
__PSTL_PRAGMA_DECLARE_REDUCTION(__min_func, _ComplexType)
__PSTL_PRAGMA_SIMD_REDUCTION(__min_func : __init)
for (_Size __i = 1; __i < __n; ++__i)
{
const _ValueType __min_val = __init.__min_val;
const _ValueType __current = __first[__i];
if (__comp(__current, __min_val))
{
__init.__min_val = __current;
__init.__min_ind = __i;
}
}
return __first + __init.__min_ind;
}
// [restriction] - std::iterator_traits<_ForwardIterator>::value_type should be DefaultConstructible.
// complexity [violation] - We will have at most (2*(__n-1) + 4*number_of_lanes) comparisons instead of at most [1.5*(__n-1)].
template <typename _ForwardIterator, typename _Size, typename _Compare>
std::pair<_ForwardIterator, _ForwardIterator>
simd_minmax_element(_ForwardIterator __first, _Size __n, _Compare __comp) noexcept
{
if (__n == 0)
{
return std::make_pair(__first, __first);
}
typedef typename std::iterator_traits<_ForwardIterator>::value_type _ValueType;
struct _ComplexType
{
_ValueType __min_val;
_ValueType __max_val;
_Size __min_ind;
_Size __max_ind;
_Compare* __minmax_comp;
_ComplexType() : __min_val{}, __max_val{}, __min_ind{}, __max_ind{}, __minmax_comp(nullptr) {}
_ComplexType(const _ValueType& min_val, const _ValueType& max_val, const _Compare* comp)
: __min_val(min_val), __max_val(max_val), __min_ind(0), __max_ind(0),
__minmax_comp(const_cast<_Compare*>(comp))
{
}
_ComplexType(const _ComplexType& __obj)
: __min_val(__obj.__min_val), __max_val(__obj.__max_val), __min_ind(__obj.__min_ind),
__max_ind(__obj.__max_ind), __minmax_comp(__obj.__minmax_comp)
{
}
void
operator()(const _ComplexType& __obj)
{
// min
if ((*__minmax_comp)(__obj.__min_val, __min_val))
{
__min_val = __obj.__min_val;
__min_ind = __obj.__min_ind;
}
else if (!(*__minmax_comp)(__min_val, __obj.__min_val))
{
__min_val = __obj.__min_val;
__min_ind = (__min_ind - __obj.__min_ind < 0) ? __min_ind : __obj.__min_ind;
}
// max
if ((*__minmax_comp)(__max_val, __obj.__max_val))
{
__max_val = __obj.__max_val;
__max_ind = __obj.__max_ind;
}
else if (!(*__minmax_comp)(__obj.__max_val, __max_val))
{
__max_val = __obj.__max_val;
__max_ind = (__max_ind - __obj.__max_ind < 0) ? __obj.__max_ind : __max_ind;
}
}
};
_ComplexType __init{*__first, *__first, &__comp};
__PSTL_PRAGMA_DECLARE_REDUCTION(__min_func, _ComplexType);
__PSTL_PRAGMA_SIMD_REDUCTION(__min_func : __init)
for (_Size __i = 1; __i < __n; ++__i)
{
auto __min_val = __init.__min_val;
auto __max_val = __init.__max_val;
auto __current = __first + __i;
if (__comp(*__current, __min_val))
{
__init.__min_val = *__current;
__init.__min_ind = __i;
}
else if (!__comp(*__current, __max_val))
{
__init.__max_val = *__current;
__init.__max_ind = __i;
}
}
return std::make_pair(__first + __init.__min_ind, __first + __init.__max_ind);
}
template <class _InputIterator, class _DifferenceType, class _OutputIterator1, class _OutputIterator2,
class _UnaryPredicate>
std::pair<_OutputIterator1, _OutputIterator2>
simd_partition_copy(_InputIterator __first, _DifferenceType __n, _OutputIterator1 __out_true,
_OutputIterator2 __out_false, _UnaryPredicate __pred) noexcept
{
_DifferenceType __cnt_true = 0, __cnt_false = 0;
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 0; __i < __n; ++__i)
{
__PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC_2ARGS(__cnt_true : 1, __cnt_false : 1)
if (__pred(__first[__i]))
{
__out_true[__cnt_true] = __first[__i];
++__cnt_true;
}
else
{
__out_false[__cnt_false] = __first[__i];
++__cnt_false;
}
}
return std::make_pair(__out_true + __cnt_true, __out_false + __cnt_false);
}
template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
_ForwardIterator1
simd_find_first_of(_ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __s_first,
_ForwardIterator2 __s_last, _BinaryPredicate __pred) noexcept
{
typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferencType;
const _DifferencType __n1 = __last - __first;
const _DifferencType __n2 = __s_last - __s_first;
if (__n1 == 0 || __n2 == 0)
{
return __last; // according to the standard
}
// Common case
// If first sequence larger than second then we'll run simd_first with parameters of first sequence.
// Otherwise, vice versa.
if (__n1 < __n2)
{
for (; __first != __last; ++__first)
{
if (simd_or(__s_first, __n2,
internal::equal_value_by_pred<decltype(*__first), _BinaryPredicate>(*__first, __pred)))
{
return __first;
}
}
}
else
{
for (; __s_first != __s_last; ++__s_first)
{
const auto __result = unseq_backend::simd_first(
__first, _DifferencType(0), __n1, [__s_first, &__pred](_ForwardIterator1 __it, _DifferencType __i) {
return __pred(__it[__i], *__s_first);
});
if (__result != __last)
{
return __result;
}
}
}
return __last;
}
template <class _RandomAccessIterator, class _DifferenceType, class _UnaryPredicate>
_RandomAccessIterator
simd_remove_if(_RandomAccessIterator __first, _DifferenceType __n, _UnaryPredicate __pred) noexcept
{
// find first element we need to remove
auto __current = unseq_backend::simd_first(
__first, _DifferenceType(0), __n,
[&__pred](_RandomAccessIterator __it, _DifferenceType __i) { return __pred(__it[__i]); });
__n -= __current - __first;
// if we have in sequence only one element that pred(__current[1]) != false we can exit the function
if (__n < 2)
{
return __current;
}
_DifferenceType __cnt = 0;
__PSTL_PRAGMA_SIMD
for (_DifferenceType __i = 1; __i < __n; ++__i)
{
__PSTL_PRAGMA_SIMD_ORDERED_MONOTONIC(__cnt : 1)
if (!__pred(__current[__i]))
{
__current[__cnt] = std::move(__current[__i]);
++__cnt;
}
}
return __current + __cnt;
}
} // namespace unseq_backend
} // namespace __pstl
#endif /* __PSTL_unseq_backend_simd_H */

View File

@ -0,0 +1,223 @@
// -*- C++ -*-
//===-- utils.h -----------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_utils_H
#define __PSTL_utils_H
#include <new>
#include <iterator>
namespace __pstl
{
namespace internal
{
template <typename _Fp>
typename std::result_of<_Fp()>::type
except_handler(_Fp __f)
{
try
{
return __f();
}
catch (const std::bad_alloc&)
{
throw; // re-throw bad_alloc according to the standard [algorithms.parallel.exceptions]
}
catch (...)
{
std::terminate(); // Good bye according to the standard [algorithms.parallel.exceptions]
}
}
template <typename _Fp>
void
invoke_if(std::true_type, _Fp __f)
{
__f();
}
template <typename _Fp>
void
invoke_if(std::false_type, _Fp __f)
{
}
template <typename _Fp>
void
invoke_if_not(std::false_type, _Fp __f)
{
__f();
}
template <typename _Fp>
void
invoke_if_not(std::true_type, _Fp __f)
{
}
template <typename _F1, typename _F2>
typename std::result_of<_F1()>::type
invoke_if_else(std::true_type, _F1 __f1, _F2 __f2)
{
return __f1();
}
template <typename _F1, typename _F2>
typename std::result_of<_F2()>::type
invoke_if_else(std::false_type, _F1 __f1, _F2 __f2)
{
return __f2();
}
//! Unary operator that returns reference to its argument.
struct no_op
{
template <typename _Tp>
_Tp&&
operator()(_Tp&& __a) const
{
return std::forward<_Tp>(__a);
}
};
//! Logical negation of a predicate
template <typename _Pred>
class not_pred
{
_Pred _M_pred;
public:
explicit not_pred(_Pred __pred) : _M_pred(__pred) {}
template <typename... _Args>
bool
operator()(_Args&&... __args)
{
return !_M_pred(std::forward<_Args>(__args)...);
}
};
template <typename _Pred>
class reorder_pred
{
_Pred _M_pred;
public:
explicit reorder_pred(_Pred __pred) : _M_pred(__pred) {}
template <typename _FTp, typename _STp>
bool
operator()(_FTp&& __a, _STp&& __b)
{
return _M_pred(std::forward<_STp>(__b), std::forward<_FTp>(__a));
}
};
//! "==" comparison.
/** Not called "equal" to avoid (possibly unfounded) concerns about accidental invocation via
argument-dependent name lookup by code expecting to find the usual std::equal. */
class pstl_equal
{
public:
explicit pstl_equal() {}
template <typename _Xp, typename _Yp>
bool
operator()(_Xp&& __x, _Yp&& __y) const
{
return std::forward<_Xp>(__x) == std::forward<_Yp>(__y);
}
};
//! "<" comparison.
class pstl_less
{
public:
explicit pstl_less() {}
template <typename _Xp, typename _Yp>
bool
operator()(_Xp&& __x, _Yp&& __y) const
{
return std::forward<_Xp>(__x) < std::forward<_Yp>(__y);
}
};
//! Like a polymorphic lambda for pred(...,value)
template <typename _Tp, typename _Predicate>
class equal_value_by_pred
{
const _Tp& _M_value;
_Predicate _M_pred;
public:
equal_value_by_pred(const _Tp& __value, _Predicate __pred) : _M_value(__value), _M_pred(__pred) {}
template <typename _Arg>
bool
operator()(_Arg&& __arg)
{
return _M_pred(std::forward<_Arg>(__arg), _M_value);
}
};
//! Like a polymorphic lambda for ==value
template <typename _Tp>
class equal_value
{
const _Tp& _M_value;
public:
explicit equal_value(const _Tp& __value) : _M_value(__value) {}
template <typename _Arg>
bool
operator()(_Arg&& __arg) const
{
return std::forward<_Arg>(__arg) == _M_value;
}
};
//! Logical negation of ==value
template <typename _Tp>
class not_equal_value
{
const _Tp& _M_value;
public:
explicit not_equal_value(const _Tp& __value) : _M_value(__value) {}
template <typename _Arg>
bool
operator()(_Arg&& __arg) const
{
return !(std::forward<_Arg>(__arg) == _M_value);
}
};
template <typename _ForwardIterator, typename _Compare>
_ForwardIterator
cmp_iterators_by_values(_ForwardIterator __a, _ForwardIterator __b, _Compare __comp)
{
if (__a < __b)
{ // we should return closer iterator
return __comp(*__b, *__a) ? __b : __a;
}
else
{
return __comp(*__a, *__b) ? __a : __b;
}
}
} // namespace internal
} // namespace __pstl
#endif /* __PSTL_utils_H */

25
pstl/include/pstl/memory Normal file
View File

@ -0,0 +1,25 @@
// -*- C++ -*-
//===-- memory ------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_memory
#define __PSTL_memory
#include "internal/pstl_config.h"
#if __PSTL_EXECUTION_POLICIES_DEFINED
// If <execution> has already been included, pull in implementations
#include "internal/glue_memory_impl.h"
#else
// Otherwise just pull in forward declarations
#include "internal/glue_memory_defs.h"
#define __PSTL_MEMORY_FORWARD_DECLARED 1
#endif
#endif /* __PSTL_memory */

25
pstl/include/pstl/numeric Normal file
View File

@ -0,0 +1,25 @@
// -*- C++ -*-
//===-- numeric -----------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_numeric
#define __PSTL_numeric
#include "internal/pstl_config.h"
#if __PSTL_EXECUTION_POLICIES_DEFINED
// If <execution> has already been included, pull in implementations
#include "internal/glue_numeric_impl.h"
#else
// Otherwise just pull in forward declarations
#include "internal/glue_numeric_defs.h"
#define __PSTL_NUMERIC_FORWARD_DECLARED 1
#endif
#endif /* __PSTL_numeric */

View File

@ -0,0 +1,50 @@
// -*- C++ -*-
//===-- pstl_test_config.h ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef __PSTL_TEST_config_H
#define __PSTL_TEST_config_H
#if defined(_MSC_VER) && defined(_DEBUG)
#define _SCL_SECURE_NO_WARNINGS //to prevent the compilation warning. Microsoft STL implementation has specific checking of an iterator range in DEBUG mode for the containers from the standard library.
#endif
#define __PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN \
(__x86_64 && !_DEBUG && __INTEL_COMPILER && __INTEL_COMPILER <= 1700 && !__APPLE__)
#define __PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN \
(!_DEBUG && __INTEL_COMPILER && \
(__INTEL_COMPILER < 1800 || (__INTEL_COMPILER == 1800 && __INTEL_COMPILER_UPDATE < 1)))
#define __PSTL_ICC_1800_TEST_MONOTONIC_RELEASE_64_BROKEN \
(__x86_64 && !_DEBUG && __INTEL_COMPILER && __INTEL_COMPILER == 1800 && __INTEL_COMPILER_UPDATE < 1)
#define __PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN \
(__i386__ && !_DEBUG && __INTEL_COMPILER >= 1700 && __INTEL_COMPILER < 1800 && __APPLE__)
#define __PSTL_ICC_18_VC141_TEST_SIMD_LAMBDA_RELEASE_BROKEN \
(!_DEBUG && __INTEL_COMPILER >= 1800 && __INTEL_COMPILER < 1900 && _MSC_VER == 1910)
#define __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN \
(_M_IX86 && _DEBUG && __INTEL_COMPILER >= 1700 && __INTEL_COMPILER < 1800 && _MSC_VER >= 1900)
#define __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN \
(_M_IX86 && _DEBUG && __INTEL_COMPILER >= 1600 && __INTEL_COMPILER < 1700 && _MSC_VER == 1900)
#define __PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN \
(__PSTL_USE_PAR_POLICIES && ((_M_X64 && _MSC_VER == 1900) || __x86_64) && !_DEBUG && __INTEL_COMPILER < 1700)
#define __PSTL_ICC_16_17_TEST_64_TIMEOUT (__x86_64 && __INTEL_COMPILER && __INTEL_COMPILER < 1800 && !__APPLE__)
#define __PSTL_ICC_18_TEST_EARLY_EXIT_MONOTONIC_RELEASE_BROKEN (!_DEBUG && __INTEL_COMPILER && __INTEL_COMPILER == 1800)
#define __PSTL_CLANG_TEST_BIG_OBJ_DEBUG_32_BROKEN \
(__i386__ && PSTL_USE_DEBUG && __clang__ && __PSTL_CLANG_VERSION <= 90000)
#define __PSTL_ICC_16_17_18_TEST_UNIQUE_MASK_RELEASE_BROKEN \
(!_DEBUG && __INTEL_COMPILER && \
(__INTEL_COMPILER < 1800 || (__INTEL_COMPILER == 1800 && __INTEL_COMPILER_UPDATE < 3)))
#define __PSTL_ICC_18_TEST_EARLY_EXIT_AVX_RELEASE_BROKEN \
(!_DEBUG && __INTEL_COMPILER == 1800 && __AVX__ && !__AVX2__ && !__AVX512__)
#define __PSTL_ICC_19_TEST_IS_PARTITIONED_RELEASE_BROKEN \
(!PSTL_USE_DEBUG && (__linux__ || __APPLE__) && __INTEL_COMPILER == 1900)
#define __PSTL_ICL_19_VC14_VC141_TEST_SCAN_RELEASE_BROKEN \
(__INTEL_COMPILER == 1900 && _MSC_VER >= 1900 && _MSC_VER <= 1910)
#define __PSTL_ICC_19_TEST_SIMD_UDS_WINDOWS_RELEASE_BROKEN (__INTEL_COMPILER == 1900 && _MSC_VER && !_DEBUG)
#endif /* __PSTL_TEST_config_H */

View File

@ -0,0 +1,170 @@
// -*- C++ -*-
//===-- test_adjacent_difference.cpp --------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include <iterator>
#include "pstl/execution"
#include "pstl/algorithm"
#include "pstl/numeric"
#include "utils.h"
using namespace TestUtils;
template <typename T>
struct wrapper
{
T t;
explicit wrapper(T t_) : t(t_) {}
template <typename T2>
wrapper(const wrapper<T2>& a)
{
t = a.t;
}
template <typename T2>
void
operator=(const wrapper<T2>& a)
{
t = a.t;
}
wrapper<T>
operator-(const wrapper<T>& a) const
{
return wrapper<T>(t - a.t);
}
};
template <typename T>
bool
compare(const T& a, const T& b)
{
return a == b;
}
template <typename T>
bool
compare(const wrapper<T>& a, const wrapper<T>& b)
{
return a.t == b.t;
}
template <typename Iterator1, typename Iterator2, typename T, typename Function>
typename std::enable_if<!std::is_floating_point<T>::value, bool>::type
compute_and_check(Iterator1 first, Iterator1 last, Iterator2 d_first, T, Function f)
{
using T2 = typename std::iterator_traits<Iterator2>::value_type;
if (first == last)
return true;
T2 temp(*first);
if (!compare(temp, *d_first))
return false;
Iterator1 second = std::next(first);
++d_first;
for (; second != last; ++first, ++second, ++d_first)
{
T2 temp(f(*second, *first));
if (!compare(temp, *d_first))
return false;
}
return true;
}
// we don't want to check equality here
// because we can't be sure it will be strictly equal for floating point types
template <typename Iterator1, typename Iterator2, typename T, typename Function>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
compute_and_check(Iterator1 first, Iterator1 last, Iterator2 d_first, T, Function)
{
return true;
}
struct test_one_policy
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN // dummy specialization by policy type, in case of broken configuration
template <typename Iterator1, typename Iterator2, typename T, typename Function>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::unsequenced_policy, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b,
Iterator2 actual_e, T trash, Function f)
{
}
template <typename Iterator1, typename Iterator2, typename T, typename Function>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b,
Iterator2 actual_e, T trash, Function f)
{
}
#endif
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename T, typename Function>
void
operator()(ExecutionPolicy&& exec, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, Iterator2 actual_e,
T trash, Function f)
{
using namespace std;
using T2 = typename std::iterator_traits<Iterator1>::value_type;
fill(actual_b, actual_e, trash);
Iterator2 actual_return = adjacent_difference(exec, data_b, data_e, actual_b);
EXPECT_TRUE(compute_and_check(data_b, data_e, actual_b, T2(0), std::minus<T2>()),
"wrong effect of adjacent_difference");
EXPECT_TRUE(actual_return == actual_e, "wrong result of adjacent_difference");
fill(actual_b, actual_e, trash);
actual_return = adjacent_difference(exec, data_b, data_e, actual_b, f);
EXPECT_TRUE(compute_and_check(data_b, data_e, actual_b, T2(0), f),
"wrong effect of adjacent_difference with functor");
EXPECT_TRUE(actual_return == actual_e, "wrong result of adjacent_difference with functor");
}
};
template <typename T1, typename T2, typename Pred>
void
test(Pred pred)
{
typedef typename Sequence<T2>::iterator iterator_type;
const std::size_t max_len = 100000;
const T2 value = T2(77);
const T1 trash = T1(31);
Sequence<T1> actual(max_len, [](std::size_t i) { return T1(i); });
Sequence<T2> data(max_len, [&value](std::size_t i) { return i % 3 == 2 ? T2(i * i) : value; });
for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len))
{
invoke_on_all_policies(test_one_policy(), data.begin(), data.begin() + len, actual.begin(),
actual.begin() + len, trash, pred);
invoke_on_all_policies(test_one_policy(), data.cbegin(), data.cbegin() + len, actual.begin(),
actual.begin() + len, trash, pred);
}
}
int32_t
main()
{
test<uint8_t, uint32_t>([](uint32_t a, uint32_t b) { return a - b; });
test<int32_t, int64_t>([](int64_t a, int64_t b) { return a / (b + 1); });
test<int64_t, float32_t>([](float32_t a, float32_t b) { return (a + b) / 2; });
test<wrapper<int32_t>, wrapper<int64_t>>(
[](const wrapper<int64_t>& a, const wrapper<int64_t>& b) { return a - b; });
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,112 @@
// -*- C++ -*-
//===-- test_adjacent_find.cpp --------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for adjacent_find
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_adjacent_find
{
template <typename Policy, typename Iterator, typename Pred>
void
operator()(Policy&& exec, Iterator first, Iterator last, Pred pred)
{
using namespace std;
auto k = std::adjacent_find(first, last, pred);
auto i = adjacent_find(exec, first, last, pred);
EXPECT_TRUE(i == k, "wrong return value from adjacent_find with predicate");
i = adjacent_find(exec, first, last);
EXPECT_TRUE(i == k, "wrong return value from adjacent_find without predicate");
}
};
template <typename T>
void
test_adjacent_find_by_type()
{
size_t counts[] = {2, 3, 500};
for (int32_t c = 0; c < const_size(counts); ++c)
{
for (int32_t e = 0; e < (counts[c] >= 64 ? 64 : (counts[c] == 2 ? 1 : 2)); ++e)
{
Sequence<T> in(counts[c], [](int32_t v) -> T { return T(v); }); //fill 0...n
in[e] = in[e + 1] = -1; //make an adjacent pair
auto i = std::adjacent_find(in.cbegin(), in.cend(), std::equal_to<T>());
EXPECT_TRUE(i == in.cbegin() + e, "std::adjacent_find returned wrong result");
invoke_on_all_policies(test_adjacent_find(), in.begin(), in.end(), std::equal_to<T>());
invoke_on_all_policies(test_adjacent_find(), in.cbegin(), in.cend(), std::equal_to<T>());
}
}
//special cases: size=0, size=1;
for (int32_t expect = 0; expect < 1; ++expect)
{
Sequence<T> in(expect, [](int32_t v) -> T { return T(v); }); //fill 0...n
auto i = std::adjacent_find(in.cbegin(), in.cend(), std::equal_to<T>());
EXPECT_TRUE(i == in.cbegin() + expect, "std::adjacent_find returned wrong result");
invoke_on_all_policies(test_adjacent_find(), in.begin(), in.end(), std::equal_to<T>());
invoke_on_all_policies(test_adjacent_find(), in.cbegin(), in.cend(), std::equal_to<T>());
}
//special cases:
Sequence<T> a1 = {5, 5, 5, 6, 7, 8, 9};
invoke_on_all_policies(test_adjacent_find(), a1.begin(), a1.end(), std::equal_to<T>());
invoke_on_all_policies(test_adjacent_find(), a1.begin() + 1, a1.end(), std::equal_to<T>());
invoke_on_all_policies(test_adjacent_find(), a1.cbegin(), a1.cend(), std::equal_to<T>());
invoke_on_all_policies(test_adjacent_find(), a1.cbegin() + 1, a1.cend(), std::equal_to<T>());
Sequence<T> a2 = {5, 6, 7, 8, 9, 9};
invoke_on_all_policies(test_adjacent_find(), a2.begin(), a2.end(), std::equal_to<T>());
invoke_on_all_policies(test_adjacent_find(), a2.begin(), a2.end() - 1, std::equal_to<T>());
invoke_on_all_policies(test_adjacent_find(), a2.cbegin(), a2.cend(), std::equal_to<T>());
invoke_on_all_policies(test_adjacent_find(), a2.cbegin(), a2.cend() - 1, std::equal_to<T>());
Sequence<T> a3 = {5, 6, 6, 6, 7, 9, 9, 9, 9};
invoke_on_all_policies(test_adjacent_find(), a3.begin(), a3.end(), std::equal_to<T>());
invoke_on_all_policies(test_adjacent_find(), a3.cbegin(), a3.cend(), std::equal_to<T>());
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
adjacent_find(exec, iter, iter, non_const(std::equal_to<T>()));
}
};
int32_t
main()
{
test_adjacent_find_by_type<int32_t>();
test_adjacent_find_by_type<float64_t>();
test_algo_basic_single<int32_t>(run_for_rnd_bi<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

115
pstl/test/test_all_of.cpp Normal file
View File

@ -0,0 +1,115 @@
// -*- C++ -*-
//===-- test_all_of.cpp ---------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
/*
TODO: consider implementing the following tests for a better code coverage
- correctness
- bad input argument (if applicable)
- data corruption around/of input and output
- correctly work with nested parallelism
- check that algorithm does not require anything more than is described in its requirements section
*/
using namespace TestUtils;
struct test_all_of
{
template <typename ExecutionPolicy, typename Iterator, typename Predicate>
void
operator()(ExecutionPolicy&& exec, Iterator begin, Iterator end, Predicate pred, bool expected)
{
auto actualr = std::all_of(exec, begin, end, pred);
EXPECT_EQ(expected, actualr, "result for all_of");
}
};
template <typename T>
struct Parity
{
bool parity;
public:
Parity(bool parity_) : parity(parity_) {}
bool
operator()(T value) const
{
return (size_t(value) ^ parity) % 2 == 0;
}
};
template <typename T>
void
test(size_t bits)
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
// Sequence of odd values
Sequence<T> in(n, [n, bits](size_t k) { return T(2 * HashBits(n, bits - 1) ^ 1); });
// Even value, or false when T is bool.
T spike(2 * HashBits(n, bits - 1));
Sequence<T> inCopy(in);
invoke_on_all_policies(test_all_of(), in.begin(), in.end(), Parity<T>(1), true);
invoke_on_all_policies(test_all_of(), in.cbegin(), in.cend(), Parity<T>(1), true);
EXPECT_EQ(in, inCopy, "all_of modified input sequence");
if (n > 0)
{
// Sprinkle in a miss
in[2 * n / 3] = spike;
invoke_on_all_policies(test_all_of(), in.begin(), in.end(), Parity<T>(1), false);
invoke_on_all_policies(test_all_of(), in.cbegin(), in.cend(), Parity<T>(1), false);
// Sprinkle in a few more misses
in[n / 2] = spike;
in[n / 3] = spike;
invoke_on_all_policies(test_all_of(), in.begin(), in.end(), Parity<T>(1), false);
invoke_on_all_policies(test_all_of(), in.cbegin(), in.cend(), Parity<T>(1), false);
}
}
}
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
all_of(exec, iter, iter, non_const(is_even));
}
};
int32_t
main()
{
test<int32_t>(8 * sizeof(int32_t));
test<uint16_t>(8 * sizeof(uint16_t));
test<float64_t>(53);
#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN
test<bool>(1);
#endif
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

101
pstl/test/test_any_of.cpp Normal file
View File

@ -0,0 +1,101 @@
// -*- C++ -*-
//===-- test_any_of.cpp ---------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
/*
TODO: consider implementing the following tests for a better code coverage
- correctness
- bad input argument (if applicable)
- data corruption around/of input and output
- correctly work with nested parallelism
- check that algorithm does not require anything more than is described in its requirements section
*/
using namespace TestUtils;
struct test_any_of
{
template <typename ExecutionPolicy, typename Iterator, typename Predicate>
void
operator()(ExecutionPolicy&& exec, Iterator begin, Iterator end, Predicate pred, bool expected)
{
auto actualr = std::any_of(exec, begin, end, pred);
EXPECT_EQ(expected, actualr, "result for any_of");
}
};
template <typename T>
void
test(size_t bits)
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
// Sequence of odd values
Sequence<T> in(n, [n, bits](size_t k) { return T(2 * HashBits(n, bits - 1) ^ 1); });
// Even value, or false when T is bool.
T spike(2 * HashBits(n, bits - 1));
Sequence<T> inCopy(in);
invoke_on_all_policies(test_any_of(), in.begin(), in.end(), is_equal_to<T>(spike), false);
invoke_on_all_policies(test_any_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), false);
EXPECT_EQ(in, inCopy, "any_of modified input sequence");
if (n > 0)
{
// Sprinkle in a hit
in[2 * n / 3] = spike;
invoke_on_all_policies(test_any_of(), in.begin(), in.end(), is_equal_to<T>(spike), true);
invoke_on_all_policies(test_any_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), true);
// Sprinkle in a few more hits
in[n / 2] = spike;
in[n / 3] = spike;
invoke_on_all_policies(test_any_of(), in.begin(), in.end(), is_equal_to<T>(spike), true);
invoke_on_all_policies(test_any_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), true);
}
}
}
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
any_of(exec, iter, iter, non_const(is_even));
}
};
int32_t
main()
{
test<int32_t>(8 * sizeof(int32_t));
test<uint16_t>(8 * sizeof(uint16_t));
test<float64_t>(53);
#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN
test<bool>(1);
#endif
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

145
pstl/test/test_copy_if.cpp Normal file
View File

@ -0,0 +1,145 @@
// -*- C++ -*-
//===-- test_copy_if.cpp --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for copy_if and remove_copy_if
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct run_copy_if
{
#if __PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN // dummy specializations to skip testing in case of broken configuration
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename Predicate, typename T>
void
operator()(pstl::execution::parallel_policy, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n,
Predicate pred, T trash)
{
}
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename Predicate, typename T>
void
operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last,
OutputIterator out_first, OutputIterator out_last, OutputIterator2 expected_first,
OutputIterator2 expected_last, Size n, Predicate pred, T trash)
{
}
#endif
template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename Predicate, typename T>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n,
Predicate pred, T trash)
{
// Cleaning
std::fill_n(expected_first, n, trash);
std::fill_n(out_first, n, trash);
// Run copy_if
auto i = copy_if(first, last, expected_first, pred);
auto k = copy_if(exec, first, last, out_first, pred);
EXPECT_EQ_N(expected_first, out_first, n, "wrong copy_if effect");
for (size_t j = 0; j < GuardSize; ++j)
{
++k;
}
EXPECT_TRUE(out_last == k, "wrong return value from copy_if");
// Cleaning
std::fill_n(expected_first, n, trash);
std::fill_n(out_first, n, trash);
// Run remove_copy_if
i = remove_copy_if(first, last, expected_first, [=](const T& x) { return !pred(x); });
k = remove_copy_if(exec, first, last, out_first, [=](const T& x) { return !pred(x); });
EXPECT_EQ_N(expected_first, out_first, n, "wrong remove_copy_if effect");
for (size_t j = 0; j < GuardSize; ++j)
{
++k;
}
EXPECT_TRUE(out_last == k, "wrong return value from remove_copy_if");
}
};
template <typename T, typename Predicate, typename Convert>
void
test(T trash, Predicate pred, Convert convert, bool check_weakness = true)
{
// Try sequences of various lengths.
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
// count is number of output elements, plus a handful
// more for sake of detecting buffer overruns.
size_t count = GuardSize;
Sequence<T> in(n, [&](size_t k) -> T {
T val = convert(n ^ k);
count += pred(val) ? 1 : 0;
return val;
});
Sequence<T> out(count, [=](size_t) { return trash; });
Sequence<T> expected(count, [=](size_t) { return trash; });
if (check_weakness)
{
auto expected_result = copy_if(in.cfbegin(), in.cfend(), expected.begin(), pred);
size_t m = expected_result - expected.begin();
EXPECT_TRUE(n / 4 <= m && m <= 3 * (n + 1) / 4, "weak test for copy_if");
}
invoke_on_all_policies(run_copy_if(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(),
expected.end(), count, pred, trash);
invoke_on_all_policies(run_copy_if(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(),
expected.end(), count, pred, trash);
}
}
struct test_non_const
{
template <typename Policy, typename InputIterator, typename OutputInterator>
void
operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
copy_if(exec, input_iter, input_iter, out_iter, non_const(is_even));
invoke_if(exec, [&]() { remove_copy_if(exec, input_iter, input_iter, out_iter, non_const(is_even)); });
}
};
int32_t
main()
{
test<float64_t>(-666.0, [](const float64_t& x) { return x * x <= 1024; },
[](size_t j) { return ((j + 1) % 7 & 2) != 0 ? float64_t(j % 32) : float64_t(j % 33 + 34); });
test<int32_t>(-666, [](const int32_t& x) { return x != 42; },
[](size_t j) { return ((j + 1) % 5 & 2) != 0 ? int32_t(j + 1) : 42; });
#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN
test<Number>(Number(42, OddTag()), IsMultiple(3, OddTag()), [](int32_t j) { return Number(j, OddTag()); });
#endif
#if !__PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN
test<int32_t>(-666, [](const int32_t& x) { return true; }, [](size_t j) { return j; }, false);
#endif
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,199 @@
// -*- C++ -*-
//===-- test_copy_move.cpp ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for copy, move and copy_n
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct run_copy
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, typename T>
void
operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size,
Size n, T trash)
{
}
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, typename T>
void
operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last,
OutputIterator out_first, OutputIterator out_last, OutputIterator2 expected_first,
OutputIterator2 expected_last, Size size, Size n, T trash)
{
}
#endif
template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename T>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size,
Size n, T trash)
{
// Cleaning
std::fill_n(expected_first, size, trash);
std::fill_n(out_first, size, trash);
// Run copy
copy(first, last, expected_first);
auto k = copy(exec, first, last, out_first);
for (size_t j = 0; j < GuardSize; ++j)
++k;
EXPECT_EQ_N(expected_first, out_first, size, "wrong effect from copy");
EXPECT_TRUE(out_last == k, "wrong return value from copy");
// Cleaning
std::fill_n(out_first, size, trash);
// Run copy_n
k = copy_n(exec, first, n, out_first);
for (size_t j = 0; j < GuardSize; ++j)
++k;
EXPECT_EQ_N(expected_first, out_first, size, "wrong effect from copy_n");
EXPECT_TRUE(out_last == k, "wrong return value from copy_n");
}
};
template <typename T>
struct run_move
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size>
void
operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size,
Size n, T trash)
{
}
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size>
void
operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last,
OutputIterator out_first, OutputIterator out_last, OutputIterator2 expected_first,
OutputIterator2 expected_last, Size size, Size n, T trash)
{
}
#endif
template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size,
Size n, T trash)
{
// Cleaning
std::fill_n(expected_first, size, trash);
std::fill_n(out_first, size, trash);
// Run move
move(first, last, expected_first);
auto k = move(exec, first, last, out_first);
for (size_t j = 0; j < GuardSize; ++j)
++k;
EXPECT_EQ_N(expected_first, out_first, size, "wrong effect from move");
EXPECT_TRUE(out_last == k, "wrong return value from move");
}
};
template <typename T>
struct run_move<Wrapper<T>>
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size>
void
operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size,
Size n, Wrapper<T> trash)
{
}
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size>
void
operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last,
OutputIterator out_first, OutputIterator out_last, OutputIterator2 expected_first,
OutputIterator2 expected_last, Size size, Size n, Wrapper<T> trash)
{
}
#endif
template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size,
Size n, Wrapper<T> trash)
{
// Cleaning
std::fill_n(out_first, size, trash);
Wrapper<T>::SetMoveCount(0);
// Run move
auto k = move(exec, first, last, out_first);
for (size_t j = 0; j < GuardSize; ++j)
++k;
EXPECT_TRUE(Wrapper<T>::MoveCount() == size, "wrong effect from move");
EXPECT_TRUE(out_last == k, "wrong return value from move");
}
};
template <typename T, typename Convert>
void
test(T trash, Convert convert)
{
// Try sequences of various lengths.
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
// count is number of output elements, plus a handful
// more for sake of detecting buffer overruns.
Sequence<T> in(n, [&](size_t k) -> T {
T val = convert(n ^ k);
return val;
});
const size_t outN = n + GuardSize;
Sequence<T> out(outN, [=](size_t) { return trash; });
Sequence<T> expected(outN, [=](size_t) { return trash; });
invoke_on_all_policies(run_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(),
expected.end(), outN, n, trash);
invoke_on_all_policies(run_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(),
expected.end(), outN, n, trash);
invoke_on_all_policies(run_move<T>(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(),
expected.end(), n, n, trash);
// For this test const iterator isn't suitable
// because const rvalue-reference call copy assignment operator
}
}
int32_t
main()
{
test<int32_t>(-666, [](size_t j) { return int32_t(j); });
test<Wrapper<float64_t>>(Wrapper<float64_t>(-666.0), [](int32_t j) { return Wrapper<float64_t>(j); });
#if !__PSTL_ICC_16_17_TEST_64_TIMEOUT
test<float64_t>(-666.0, [](size_t j) { return float64_t(j); });
test<Number>(Number(42, OddTag()), [](int32_t j) { return Number(j, OddTag()); });
#endif
std::cout << done() << std::endl;
return 0;
}

106
pstl/test/test_count.cpp Normal file
View File

@ -0,0 +1,106 @@
// -*- C++ -*-
//===-- test_count.cpp ----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for count and count_if
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_count
{
template <typename Policy, typename Iterator, typename T>
void
operator()(Policy&& exec, Iterator first, Iterator last, T needle)
{
auto expected = std::count(first, last, needle);
auto result = std::count(exec, first, last, needle);
EXPECT_EQ(expected, result, "wrong count result");
}
};
struct test_count_if
{
template <typename Policy, typename Iterator, typename Predicate>
void
operator()(Policy&& exec, Iterator first, Iterator last, Predicate pred)
{
auto expected = std::count_if(first, last, pred);
auto result = std::count_if(exec, first, last, pred);
EXPECT_EQ(expected, result, "wrong count_if result");
}
};
template <typename T>
class IsEqual
{
T value;
public:
IsEqual(T value_, OddTag) : value(value_) {}
bool
operator()(const T& x) const
{
return x == value;
}
};
template <typename In, typename T, typename Predicate, typename Convert>
void
test(T needle, Predicate pred, Convert convert)
{
// Try sequences of various lengths.
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<In> in(n, [=](size_t k) -> In {
// Sprinkle "42" and "50" early, so that short sequences have non-zero count.
return convert((n - k - 1) % 3 == 0 ? 42 : (n - k - 2) % 5 == 0 ? 50 : 3 * (int(k) % 1000 - 500));
});
invoke_on_all_policies(test_count(), in.begin(), in.end(), needle);
invoke_on_all_policies(test_count_if(), in.begin(), in.end(), pred);
invoke_on_all_policies(test_count(), in.cbegin(), in.cend(), needle);
invoke_on_all_policies(test_count_if(), in.cbegin(), in.cend(), pred);
}
}
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
count_if(exec, iter, iter, non_const(is_even));
}
};
int32_t
main()
{
test<int32_t>(42, IsEqual<int32_t>(50, OddTag()), [](int32_t j) { return j; });
#if !__PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN
test<int32_t>(42, [](const int32_t& x) { return true; }, [](int32_t j) { return j; });
#endif
test<float64_t>(42, IsEqual<float64_t>(50, OddTag()), [](int32_t j) { return float64_t(j); });
test<Number>(Number(42, OddTag()), IsEqual<Number>(Number(50, OddTag()), OddTag()),
[](int32_t j) { return Number(j, OddTag()); });
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

166
pstl/test/test_equal.cpp Normal file
View File

@ -0,0 +1,166 @@
// -*- C++ -*-
//===-- test_equal.cpp ----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
#define CPP14_ENABLED 0
struct UserType
{
float32_t f;
float64_t d;
int32_t i;
size_t key;
bool
operator()(UserType a, UserType b)
{
return a.key < b.key;
}
bool
operator<(UserType a)
{
return a.key < key;
}
bool
operator>=(UserType a)
{
return a.key <= key;
}
bool
operator<=(UserType a)
{
return a.key >= key;
}
bool
operator==(UserType a)
{
return a.key == key;
}
bool
operator==(UserType a) const
{
return a.key == key;
}
bool
operator!=(UserType a)
{
return a.key != key;
}
UserType operator!()
{
UserType tmp;
tmp.key = !key;
return tmp;
}
friend std::ostream&
operator<<(std::ostream& stream, const UserType a)
{
stream << a.key;
return stream;
}
UserType() : key(-1), f(0.0f), d(0.0), i(0) {}
UserType(size_t Number) : key(Number), f(0.0f), d(0.0), i(0) {}
UserType&
operator=(const UserType& other)
{
key = other.key;
return *this;
}
UserType(const UserType& other) : key(other.key), f(other.f), d(other.d), i(other.i) {}
UserType(UserType&& other) : key(other.key), f(other.f), d(other.d), i(other.i)
{
other.key = -1;
other.f = 0.0f;
other.d = 0.0;
other.i = 0;
}
};
struct test_one_policy
{
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2>
void
operator()(ExecutionPolicy&& exec, Iterator1 first1, Iterator1 last1, Iterator2 first2, bool is_true_equal)
{
using namespace std;
auto expected = equal(first1, last1, first2);
auto actual = equal(exec, first1, last1, first2);
EXPECT_EQ(expected, actual, "result for equal for random-access iterator, checking against std::equal()");
// testing bool
EXPECT_TRUE(is_true_equal == actual, "result for equal for random-access iterator, bool");
//add C++14 equal symantics tests
//add more cases for inCopy size less than in
#if CPP14_ENABLED
auto actualr14 = std::equal(in.cbegin(), in.cend(), inCopy.cbegin(), inCopy.cend());
EXPECT_EQ(expected, actualr14, "result for equal for random-access iterator");
#endif
}
};
template <typename T>
void
test(size_t bits)
{
for (size_t n = 1; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
// Sequence of odd values
Sequence<T> in(n, [bits](size_t k) { return T(2 * HashBits(k, bits - 1) ^ 1); });
Sequence<T> inCopy(in);
invoke_on_all_policies(test_one_policy(), in.begin(), in.end(), inCopy.begin(), true);
invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cend(), inCopy.cbegin(), true);
// testing bool !equal()
inCopy[0] = !inCopy[0];
invoke_on_all_policies(test_one_policy(), in.begin(), in.end(), inCopy.begin(), false);
invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cend(), inCopy.cbegin(), false);
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename FirstIterator, typename SecondInterator>
void
operator()(Policy&& exec, FirstIterator first_iter, SecondInterator second_iter)
{
equal(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::equal_to<T>()));
}
};
int32_t
main()
{
test<int32_t>(8 * sizeof(int32_t));
test<uint16_t>(8 * sizeof(uint16_t));
test<float64_t>(53);
#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN
test<bool>(1);
#endif
test<UserType>(256);
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

98
pstl/test/test_fill.cpp Normal file
View File

@ -0,0 +1,98 @@
// -*- C++ -*-
//===-- test_fill.cpp -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for fill/fill_n
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_fill
{
template <typename It, typename T>
bool
check(It first, It last, const T& value)
{
for (; first != last; ++first)
if (*first != value)
return false;
return true;
}
template <typename Policy, typename Iterator, typename T>
void
operator()(Policy&& exec, Iterator first, Iterator last, const T& value)
{
fill(first, last, T(value + 1)); // initialize memory with different value
fill(exec, first, last, value);
EXPECT_TRUE(check(first, last, value), "fill wrong result");
}
};
struct test_fill_n
{
template <typename It, typename Size, typename T>
bool
check(It first, Size n, const T& value)
{
for (Size i = 0; i < n; ++i, ++first)
if (*first != value)
return false;
return true;
}
template <typename Policy, typename Iterator, typename Size, typename T>
void
operator()(Policy&& exec, Iterator first, Size n, const T& value)
{
fill_n(first, n, T(value + 1)); // initialize memory with different value
const Iterator one_past_last = fill_n(exec, first, n, value);
const Iterator expected_return = std::next(first, n);
EXPECT_TRUE(expected_return == one_past_last, "fill_n should return Iterator to one past the element assigned");
EXPECT_TRUE(check(first, n, value), "fill_n wrong result");
//n == -1
const Iterator res = fill_n(exec, first, -1, value);
EXPECT_TRUE(res == first, "fill_n wrong result for n == -1");
}
};
template <typename T>
void
test_fill_by_type(std::size_t n)
{
Sequence<T> in(n, [](std::size_t v) -> T { return T(0); }); //fill with zeros
T value = -1;
invoke_on_all_policies(test_fill(), in.begin(), in.end(), value);
invoke_on_all_policies(test_fill_n(), in.begin(), n, value);
}
int32_t
main()
{
const std::size_t N = 100000;
for (std::size_t n = 0; n < N; n = n < 16 ? n + 1 : size_t(3.1415 * n))
{
test_fill_by_type<int32_t>(n);
test_fill_by_type<float64_t>(n);
}
std::cout << done() << std::endl;
return 0;
}

94
pstl/test/test_find.cpp Normal file
View File

@ -0,0 +1,94 @@
// -*- C++ -*-
//===-- test_find.cpp -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for find
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_find
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename Iterator, typename Value>
void
operator()(pstl::execution::unsequenced_policy, Iterator first, Iterator last, Value value)
{
}
template <typename Iterator, typename Value>
void
operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Value value)
{
}
#endif
template <typename Policy, typename Iterator, typename Value>
void
operator()(Policy&& exec, Iterator first, Iterator last, Value value)
{
auto i = std::find(first, last, value);
auto j = find(exec, first, last, value);
EXPECT_TRUE(i == j, "wrong return value from find");
}
};
template <typename T, typename Value, typename Hit, typename Miss>
void
test(Value value, Hit hit, Miss miss)
{
// Try sequences of various lengths.
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<T> in(n, [&](size_t k) -> T { return miss(n ^ k); });
// Try different find positions, including not found.
// By going backwards, we can add extra matches that are *not* supposed to be found.
// The decreasing exponential gives us O(n) total work for the loop since each find takes O(m) time.
for (size_t m = n; m > 0; m *= 0.6)
{
if (m < n)
in[m] = hit(n ^ m);
invoke_on_all_policies(test_find(), in.begin(), in.end(), value);
invoke_on_all_policies(test_find(), in.cbegin(), in.cend(), value);
}
}
}
// Type defined for sake of checking that std::find works with asymmetric ==.
class Weird
{
Number value;
public:
friend bool
operator==(Number x, Weird y)
{
return x == y.value;
}
Weird(int32_t val, OddTag) : value(val, OddTag()) {}
};
int32_t
main()
{
// Note that the "hit" and "miss" functions here avoid overflow issues.
test<Number>(Weird(42, OddTag()), [](int32_t j) { return Number(42, OddTag()); }, // hit
[](int32_t j) { return Number(j == 42 ? 0 : j, OddTag()); }); // miss
// Test with value that is equal to two different bit patterns (-0.0 and 0.0)
test<float32_t>(-0.0, [](int32_t j) { return j & 1 ? 0.0 : -0.0; }, // hit
[](int32_t j) { return j == 0 ? ~j : j; }); // miss
std::cout << done() << std::endl;
return 0;
}

121
pstl/test/test_find_end.cpp Normal file
View File

@ -0,0 +1,121 @@
// -*- C++ -*-
//===-- test_find_end.cpp -------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_one_policy
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename Iterator1, typename Iterator2, typename Predicate>
void
operator()(pstl::execution::unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub,
Predicate pred)
{
}
template <typename Iterator1, typename Iterator2, typename Predicate>
void
operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub,
Predicate pred)
{
}
#endif
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename Predicate>
void
operator()(ExecutionPolicy&& exec, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred)
{
using namespace std;
// For find_end
{
auto expected = find_end(b, e, bsub, esub, pred);
auto actual = find_end(exec, b, e, bsub, esub);
EXPECT_TRUE(actual == expected, "wrong return result from find_end");
actual = find_end(exec, b, e, bsub, esub, pred);
EXPECT_TRUE(actual == expected, "wrong return result from find_end with a predicate");
}
// For search
{
auto expected = search(b, e, bsub, esub, pred);
auto actual = search(exec, b, e, bsub, esub);
EXPECT_TRUE(actual == expected, "wrong return result from search");
actual = search(exec, b, e, bsub, esub, pred);
EXPECT_TRUE(actual == expected, "wrong return result from search with a predicate");
}
}
};
template <typename T>
void
test(const std::size_t bits)
{
const std::size_t max_n1 = 1000;
const std::size_t max_n2 = (max_n1 * 10) / 8;
Sequence<T> in(max_n1, [max_n1, bits](std::size_t k) { return T(2 * HashBits(max_n1, bits - 1) ^ 1); });
Sequence<T> sub(max_n2, [max_n1, bits](std::size_t k) { return T(2 * HashBits(max_n1, bits - 1)); });
for (std::size_t n1 = 0; n1 <= max_n1; n1 = n1 <= 16 ? n1 + 1 : size_t(3.1415 * n1))
{
std::size_t sub_n[] = {0, 1, 3, n1, (n1 * 10) / 8};
std::size_t res[] = {0, 1, n1 / 2, n1};
for (auto n2 : sub_n)
{
for (auto r : res)
{
std::size_t i = r, isub = 0;
for (; i < n1 & isub < n2; ++i, ++isub)
in[i] = sub[isub];
invoke_on_all_policies(test_one_policy(), in.begin(), in.begin() + n1, sub.begin(), sub.begin() + n2,
std::equal_to<T>());
invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cbegin() + n1, sub.cbegin(),
sub.cbegin() + n2, std::equal_to<T>());
}
}
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename FirstIterator, typename SecondInterator>
void
operator()(Policy&& exec, FirstIterator first_iter, SecondInterator second_iter)
{
invoke_if(exec, [&]() {
find_end(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::equal_to<T>()));
search(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::equal_to<T>()));
});
}
};
int32_t
main()
{
test<int32_t>(8 * sizeof(int32_t));
test<uint16_t>(8 * sizeof(uint16_t));
test<float64_t>(53);
#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN
test<bool>(1);
#endif
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,110 @@
// -*- C++ -*-
//===-- test_find_first_of.cpp --------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_one_policy
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename Iterator1, typename Iterator2, typename Predicate>
void
operator()(pstl::execution::unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub,
Predicate pred)
{
}
template <typename Iterator1, typename Iterator2, typename Predicate>
void
operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub,
Predicate pred)
{
}
#endif
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename Predicate>
void
operator()(ExecutionPolicy&& exec, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred)
{
using namespace std;
Iterator1 expected = find_first_of(b, e, bsub, esub, pred);
Iterator1 actual = find_first_of(exec, b, e, bsub, esub, pred);
EXPECT_TRUE(actual == expected, "wrong return result from find_first_of with a predicate");
expected = find_first_of(b, e, bsub, esub);
actual = find_first_of(exec, b, e, bsub, esub);
EXPECT_TRUE(actual == expected, "wrong return result from find_first_of");
}
};
template <typename T, typename Predicate>
void
test(Predicate pred)
{
const std::size_t max_n1 = 1000;
const std::size_t max_n2 = (max_n1 * 10) / 8;
Sequence<T> in1(max_n1, [](std::size_t k) { return T(1); });
Sequence<T> in2(max_n2, [](std::size_t k) { return T(0); });
for (std::size_t n1 = 0; n1 <= max_n1; n1 = n1 <= 16 ? n1 + 1 : size_t(3.1415 * n1))
{
std::size_t sub_n[] = {0, 1, n1 / 3, n1, (n1 * 10) / 8};
for (const auto n2 : sub_n)
{
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.data(), in2.data() + n2, pred);
in2[n2 / 2] = T(1);
invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + n1, in2.data(), in2.data() + n2,
pred);
if (n2 >= 3)
{
in2[2 * n2 / 3] = T(1);
invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + n1, in2.begin(),
in2.begin() + n2, pred);
in2[2 * n2 / 3] = T(0);
}
in2[n2 / 2] = T(0);
}
}
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + max_n1 / 10, in1.data(),
in1.data() + max_n1 / 10, pred);
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename FirstIterator, typename SecondInterator>
void
operator()(Policy&& exec, FirstIterator first_iter, SecondInterator second_iter)
{
invoke_if(exec, [&]() {
find_first_of(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::equal_to<T>()));
});
}
};
int32_t
main()
{
test<int32_t>(std::equal_to<int32_t>());
test<uint16_t>(std::not_equal_to<uint16_t>());
test<float64_t>([](const float64_t x, const float64_t y) { return x * x == y * y; });
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

107
pstl/test/test_find_if.cpp Normal file
View File

@ -0,0 +1,107 @@
// -*- C++ -*-
//===-- test_find_if.cpp --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for find_if and find_if_not
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_find_if
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename Iterator, typename Predicate, typename NotPredicate>
void
operator()(pstl::execution::unsequenced_policy, Iterator first, Iterator last, Predicate pred,
NotPredicate not_pred)
{
}
template <typename Iterator, typename Predicate, typename NotPredicate>
void
operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Predicate pred,
NotPredicate not_pred)
{
}
#endif
template <typename Policy, typename Iterator, typename Predicate, typename NotPredicate>
void
operator()(Policy&& exec, Iterator first, Iterator last, Predicate pred, NotPredicate not_pred)
{
auto i = std::find_if(first, last, pred);
auto j = find_if(exec, first, last, pred);
EXPECT_TRUE(i == j, "wrong return value from find_if");
auto i_not = find_if_not(exec, first, last, not_pred);
EXPECT_TRUE(i_not == i, "wrong return value from find_if_not");
}
};
template <typename T, typename Predicate, typename Hit, typename Miss>
void
test(Predicate pred, Hit hit, Miss miss)
{
auto not_pred = [pred](T x) { return !pred(x); };
// Try sequences of various lengths.
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<T> in(n, [&](size_t k) -> T { return miss(n ^ k); });
// Try different find positions, including not found.
// By going backwards, we can add extra matches that are *not* supposed to be found.
// The decreasing exponential gives us O(n) total work for the loop since each find takes O(m) time.
for (size_t m = n; m > 0; m *= 0.6)
{
if (m < n)
in[m] = hit(n ^ m);
invoke_on_all_policies(test_find_if(), in.begin(), in.end(), pred, not_pred);
invoke_on_all_policies(test_find_if(), in.cbegin(), in.cend(), pred, not_pred);
}
}
}
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
invoke_if(exec, [&]() {
find_if(exec, iter, iter, non_const(is_even));
find_if_not(exec, iter, iter, non_const(is_even));
});
}
};
int32_t
main()
{
#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN
// Note that the "hit" and "miss" functions here avoid overflow issues.
test<Number>(IsMultiple(5, OddTag()), [](int32_t j) { return Number(j - j % 5, OddTag()); }, // hit
[](int32_t j) { return Number(j % 5 == 0 ? j ^ 1 : j, OddTag()); }); // miss
#endif
// Try type for which algorithm can really be vectorized.
test<float32_t>([](float32_t x) { return x >= 0; }, [](float32_t j) { return j * j; },
[](float32_t j) { return -1 - j * j; });
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,98 @@
// -*- C++ -*-
//===-- test_for_each.cpp -------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename Type>
struct Gen
{
Type
operator()(std::size_t k)
{
return Type(k % 5 != 1 ? 3 * k - 7 : 0);
};
};
template <typename T>
struct Flip
{
int32_t val;
Flip(int32_t y) : val(y) {}
T
operator()(T& x) const
{
return x = val - x;
}
};
struct test_one_policy
{
template <typename Policy, typename Iterator, typename Size>
void
operator()(Policy&& exec, Iterator first, Iterator last, Iterator expected_first, Iterator expected_last, Size n)
{
typedef typename std::iterator_traits<Iterator>::value_type T;
// Try for_each
std::for_each(expected_first, expected_last, Flip<T>(1));
for_each(exec, first, last, Flip<T>(1));
EXPECT_EQ_N(expected_first, first, n, "wrong effect from for_each");
// Try for_each_n
std::for_each_n(pstl::execution::seq, expected_first, n, Flip<T>(1));
for_each_n(exec, first, n, Flip<T>(1));
EXPECT_EQ_N(expected_first, first, n, "wrong effect from for_each_n");
}
};
template <typename T>
void
test()
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<T> inout(n, Gen<T>());
Sequence<T> expected(n, Gen<T>());
invoke_on_all_policies(test_one_policy(), inout.begin(), inout.end(), expected.begin(), expected.end(),
inout.size());
}
}
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
invoke_if(exec, [&]() {
auto f = [](typename std::iterator_traits<Iterator>::reference x) { x = x + 1; };
for_each(exec, iter, iter, non_const(f));
for_each_n(exec, iter, 0, non_const(f));
});
}
};
int32_t
main()
{
test<int32_t>();
test<uint16_t>();
test<float64_t>();
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

101
pstl/test/test_generate.cpp Normal file
View File

@ -0,0 +1,101 @@
// -*- C++ -*-
//===-- test_generate.cpp -------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for generate
#include <atomic>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename T>
struct Generator_count
{
const T def_val = T(-1);
T
operator()()
{
return def_val;
}
T
default_value() const
{
return def_val;
}
};
struct test_generate
{
template <typename Policy, typename Iterator, typename Size>
void
operator()(Policy&& exec, Iterator first, Iterator last, Size n)
{
using namespace std;
typedef typename std::iterator_traits<Iterator>::value_type T;
// Try random-access iterator
{
Generator_count<T> g;
generate(exec, first, last, g);
EXPECT_TRUE(std::count(first, last, g.default_value()) == n, "generate wrong result for generate");
std::fill(first, last, T(0));
}
{
Generator_count<T> g;
const auto m = n / 2;
auto last = generate_n(exec, first, m, g);
EXPECT_TRUE(std::count(first, last, g.default_value()) == m && last == std::next(first, m),
"generate_n wrong result for generate_n");
std::fill(first, last, T(0));
}
}
};
template <typename T>
void
test_generate_by_type()
{
for (size_t n = 0; n <= 100000; n = n < 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<T> in(n, [](size_t v) -> T { return T(0); }); //fill by zero
invoke_on_all_policies(test_generate(), in.begin(), in.end(), in.size());
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
auto gen = []() { return T(0); };
generate(exec, iter, iter, non_const(gen));
generate_n(exec, iter, 0, non_const(gen));
}
};
int32_t
main()
{
test_generate_by_type<int32_t>();
test_generate_by_type<float64_t>();
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

105
pstl/test/test_includes.cpp Normal file
View File

@ -0,0 +1,105 @@
// -*- C++ -*-
//===-- test_includes.cpp -------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for partial_sort
#include <cmath>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename T>
struct Num
{
T val;
explicit Num(const T& v) : val(v) {}
//for "includes" checks
template <typename T1>
bool
operator<(const Num<T1>& v1) const
{
return val < v1.val;
}
//The types Type1 and Type2 must be such that an object of type InputIt can be dereferenced and then implicitly converted to both of them
template <typename T1>
operator Num<T1>() const
{
return Num<T1>((T1)val);
}
};
struct test_one_policy
{
template <typename Policy, typename InputIterator1, typename InputIterator2, typename Compare>
typename std::enable_if<!TestUtils::isReverse<InputIterator1>::value, void>::type
operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
Compare comp)
{
auto expect_res = std::includes(first1, last1, first2, last2, comp);
auto res = std::includes(exec, first1, last1, first2, last2, comp);
EXPECT_TRUE(expect_res == res, "wrong result for includes");
}
template <typename Policy, typename InputIterator1, typename InputIterator2, typename Compare>
typename std::enable_if<TestUtils::isReverse<InputIterator1>::value, void>::type
operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
Compare comp)
{
}
};
template <typename T1, typename T2, typename Compare>
void
test_includes(Compare compare)
{
const std::size_t n_max = 1000000;
// The rand()%(2*n+1) encourages generation of some duplicates.
std::srand(42);
for (std::size_t n = 0; n < n_max; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
for (std::size_t m = 0; m < n_max; m = m <= 16 ? m + 1 : size_t(2.71828 * m))
{
//prepare the input ranges
Sequence<T1> in1(n, [n](std::size_t k) { return rand() % (2 * k + 1); });
Sequence<T2> in2(m, [m](std::size_t k) { return rand() % (k + 1); });
std::sort(in1.begin(), in1.end(), compare);
std::sort(in2.begin(), in2.end(), compare);
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.cbegin(), in2.cend(), compare);
//test w/ non constant predicate
if (n < 5 && m < 5)
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.cbegin(), in2.cend(),
non_const(compare));
}
}
}
int32_t
main()
{
test_includes<float64_t, float64_t>(__pstl::internal::pstl_less());
test_includes<Num<int64_t>, Num<int32_t>>([](const Num<int64_t>& x, const Num<int32_t>& y) { return x < y; });
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,155 @@
// -*- C++ -*-
//===-- test_inplace_merge.cpp --------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include <algorithm>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_one_policy
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN // dummy specialization by policy type, in case of broken configuration
template <typename BiDirIt1, typename Size, typename Generator1, typename Generator2, typename Compare>
void
operator()(pstl::execution::unsequenced_policy, BiDirIt1 first1, BiDirIt1 last1, BiDirIt1 first2, BiDirIt1 last2,
Size n, Size m, Generator1 generator1, Generator2 generator2, Compare comp)
{
}
template <typename BiDirIt1, typename Size, typename Generator1, typename Generator2, typename Compare>
void
operator()(pstl::execution::parallel_unsequenced_policy, BiDirIt1 first1, BiDirIt1 last1, BiDirIt1 first2,
BiDirIt1 last2, Size n, Size m, Generator1 generator1, Generator2 generator2, Compare comp)
{
}
#endif
// inplace_merge works with bidirectional iterators at least
template <typename Policy, typename BiDirIt1, typename Size, typename Generator1, typename Generator2,
typename Compare>
typename std::enable_if<!is_same_iterator_category<BiDirIt1, std::forward_iterator_tag>::value, void>::type
operator()(Policy&& exec, BiDirIt1 first1, BiDirIt1 last1, BiDirIt1 first2, BiDirIt1 last2, Size n, Size m,
Generator1 generator1, Generator2 generator2, Compare comp)
{
using T = typename std::iterator_traits<BiDirIt1>::value_type;
const BiDirIt1 mid1 = std::next(first1, m);
fill_data(first1, mid1, generator1);
fill_data(mid1, last1, generator2);
const BiDirIt1 mid2 = std::next(first2, m);
fill_data(first2, mid2, generator1);
fill_data(mid2, last2, generator2);
std::inplace_merge(first1, mid1, last1, comp);
std::inplace_merge(exec, first2, mid2, last2, comp);
EXPECT_EQ_N(first1, first2, n, "wrong effect from inplace_merge with predicate");
}
template <typename Policy, typename BiDirIt1, typename Size, typename Generator1, typename Generator2,
typename Compare>
typename std::enable_if<is_same_iterator_category<BiDirIt1, std::forward_iterator_tag>::value, void>::type
operator()(Policy&& exec, BiDirIt1 first1, BiDirIt1 last1, BiDirIt1 first2, BiDirIt1 last2, Size n, Size m,
Generator1 generator1, Generator2 generator2, Compare comp)
{
}
};
template <typename T, typename Generator1, typename Generator2, typename Compare>
void
test_by_type(Generator1 generator1, Generator2 generator2, Compare comp)
{
using namespace std;
size_t max_size = 100000;
Sequence<T> in1(max_size, [](size_t v) { return T(v); });
Sequence<T> exp(max_size, [](size_t v) { return T(v); });
size_t m;
for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
m = 0;
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n, exp.begin(), exp.begin() + n, n, m,
generator1, generator2, comp);
m = n / 3;
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n, exp.begin(), exp.begin() + n, n, m,
generator1, generator2, comp);
m = 2 * n / 3;
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n, exp.begin(), exp.begin() + n, n, m,
generator1, generator2, comp);
}
}
template <typename T>
struct LocalWrapper
{
explicit LocalWrapper(int32_t k) : my_val(k) {}
LocalWrapper(LocalWrapper&& input) { my_val = std::move(input.my_val); }
LocalWrapper&
operator=(LocalWrapper&& input)
{
my_val = std::move(input.my_val);
return *this;
}
bool
operator<(const LocalWrapper<T>& w) const
{
return my_val < w.my_val;
}
friend bool
operator==(const LocalWrapper<T>& x, const LocalWrapper<T>& y)
{
return x.my_val == y.my_val;
}
friend std::ostream&
operator<<(std::ostream& stream, const LocalWrapper<T>& input)
{
return stream << input.my_val;
}
private:
T my_val;
};
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
invoke_if(exec, [&]() { inplace_merge(exec, iter, iter, iter, non_const(std::less<T>())); });
}
};
int32_t
main()
{
test_by_type<float64_t>([](int32_t i) { return -2 * i; }, [](int32_t i) { return -(2 * i + 1); },
[](const float64_t x, const float64_t y) { return x > y; });
test_by_type<int32_t>([](int32_t i) { return 10 * i; }, [](int32_t i) { return i + 1; }, std::less<int32_t>());
test_by_type<LocalWrapper<float32_t>>([](int32_t i) { return LocalWrapper<float32_t>(2 * i + 1); },
[](int32_t i) { return LocalWrapper<float32_t>(2 * i); },
std::less<LocalWrapper<float32_t>>());
test_algo_basic_single<int32_t>(run_for_rnd_bi<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

143
pstl/test/test_is_heap.cpp Normal file
View File

@ -0,0 +1,143 @@
// -*- C++ -*-
//===-- test_is_heap.cpp --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for is_heap, is_heap_until
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
#include <iostream>
using namespace TestUtils;
struct WithCmpOp
{
int32_t _first;
int32_t _second;
WithCmpOp() : _first(0), _second(0){};
explicit WithCmpOp(int32_t x) : _first(x), _second(x){};
bool
operator<(const WithCmpOp& rhs) const
{
return this->_first < rhs._first;
}
};
struct test_is_heap
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename Iterator, typename Predicate>
typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::unsequenced_policy, Iterator first, Iterator last, Predicate pred)
{
}
template <typename Iterator, typename Predicate>
typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Predicate pred)
{
}
#endif
template <typename Policy, typename Iterator, typename Predicate>
typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value, void>::type
operator()(Policy&& exec, Iterator first, Iterator last, Predicate pred)
{
using namespace std;
// is_heap
{
bool expected = is_heap(first, last);
bool actual = is_heap(exec, first, last);
EXPECT_TRUE(expected == actual, "wrong return value from is_heap");
}
// is_heap with predicate
{
bool expected = is_heap(first, last, pred);
bool actual = is_heap(exec, first, last, pred);
EXPECT_TRUE(expected == actual, "wrong return value from is_heap with predicate");
}
// is_heap_until
{
Iterator expected = is_heap_until(first, last);
Iterator actual = is_heap_until(exec, first, last);
EXPECT_TRUE(expected == actual, "wrong return value from is_heap_until");
}
// is_heap_until with predicate
{
const Iterator expected = is_heap_until(first, last, pred);
const auto y = std::distance(first, expected);
const Iterator actual = is_heap_until(exec, first, last, pred);
const auto x = std::distance(first, actual);
EXPECT_TRUE(expected == actual, "wrong return value from is_heap_until with predicate");
}
}
// is_heap, is_heap_until works only with random access iterators
template <typename Policy, typename Iterator, typename Predicate>
typename std::enable_if<!is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value, void>::type
operator()(Policy&& exec, Iterator first, Iterator last, Predicate pred)
{
}
};
template <typename T, typename Comp>
void
test_is_heap_by_type(Comp comp)
{
using namespace std;
const size_t max_size = 100000;
for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<T> in(n, [](size_t v) -> T { return T(v); });
invoke_on_all_policies(test_is_heap(), in.begin(), in.end(), comp);
std::make_heap(in.begin(), in.begin() + n / 4, comp);
invoke_on_all_policies(test_is_heap(), in.cbegin(), in.cend(), comp);
std::make_heap(in.begin(), in.begin() + n / 3, comp);
invoke_on_all_policies(test_is_heap(), in.begin(), in.end(), comp);
std::make_heap(in.begin(), in.end(), comp);
invoke_on_all_policies(test_is_heap(), in.cbegin(), in.cend(), comp);
}
Sequence<T> in(max_size / 10, [](size_t v) -> T { return T(1); });
invoke_on_all_policies(test_is_heap(), in.begin(), in.end(), comp);
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
invoke_if(exec, [&]() {
is_heap(exec, iter, iter, non_const(std::less<T>()));
is_heap_until(exec, iter, iter, non_const(std::less<T>()));
});
}
};
int32_t
main()
{
test_is_heap_by_type<float32_t>(std::greater<float32_t>());
test_is_heap_by_type<WithCmpOp>(std::less<WithCmpOp>());
test_is_heap_by_type<uint64_t>([](uint64_t x, uint64_t y) { return x % 100 < y % 100; });
test_algo_basic_single<int32_t>(run_for_rnd<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,99 @@
// -*- C++ -*-
//===-- test_is_partitioned.cpp -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_one_policy
{
//dummy specialization by policy type, in case of broken configuration
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN
template <typename Iterator1, typename Predicate>
void
operator()(pstl::execution::unsequenced_policy, Iterator1 begin1, Iterator1 end1, Predicate pred)
{
}
template <typename Iterator1, typename Predicate>
void
operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 begin1, Iterator1 end1, Predicate pred)
{
}
#endif
template <typename ExecutionPolicy, typename Iterator1, typename Predicate>
void
operator()(ExecutionPolicy&& exec, Iterator1 begin1, Iterator1 end1, Predicate pred)
{
const bool expected = std::is_partitioned(begin1, end1, pred);
const bool actual = std::is_partitioned(exec, begin1, end1, pred);
EXPECT_TRUE(actual == expected, "wrong return result from is_partitioned");
}
};
template <typename T, typename Predicate>
void
test(Predicate pred)
{
const std::size_t max_n = 1000000;
Sequence<T> in(max_n, [](std::size_t k) { return T(k); });
for (std::size_t n1 = 0; n1 <= max_n; n1 = n1 <= 16 ? n1 + 1 : std::size_t(3.1415 * n1))
{
invoke_on_all_policies(test_one_policy(), in.begin(), in.begin() + n1, pred);
std::partition(in.begin(), in.begin() + n1, pred);
invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cbegin() + n1, pred);
}
}
template <typename T>
struct LocalWrapper
{
explicit LocalWrapper(std::size_t k) : my_val(k) {}
private:
T my_val;
};
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
invoke_if(exec, [&]() { is_partitioned(exec, iter, iter, non_const(is_even)); });
}
};
int32_t
main()
{
test<float64_t>([](const float64_t x) { return x < 0; });
test<int32_t>([](const int32_t x) { return x > 1000; });
test<uint16_t>([](const uint16_t x) { return x % 5 < 3; });
#if !__PSTL_ICC_18_TEST_EARLY_EXIT_MONOTONIC_RELEASE_BROKEN && !__PSTL_ICC_19_TEST_IS_PARTITIONED_RELEASE_BROKEN
test<LocalWrapper<float64_t>>([](const LocalWrapper<float64_t>& x) { return true; });
#endif
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,98 @@
// -*- C++ -*-
//===-- test_is_sorted.cpp ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for is_sorted, is_sorted_until
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_is_sorted
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator first, Iterator last, bool exam)
{
using namespace std;
typedef typename std::iterator_traits<Iterator>::value_type T;
//try random-access iterator
bool res = is_sorted(exec, first, last);
EXPECT_TRUE(exam == res, "is_sorted wrong result for random-access iterator");
auto iexam = is_sorted_until(first, last);
auto ires = is_sorted_until(exec, first, last);
EXPECT_TRUE(iexam == ires, "is_sorted_until wrong result for random-access iterator");
//try random-access iterator with a predicate
res = is_sorted(exec, first, last, std::less<T>());
EXPECT_TRUE(exam == res, "is_sorted wrong result for random-access iterator");
iexam = is_sorted_until(first, last, std::less<T>());
ires = is_sorted_until(exec, first, last, std::less<T>());
EXPECT_TRUE(iexam == ires, "is_sorted_until wrong result for random-access iterator");
}
};
template <typename T>
void
test_is_sorted_by_type()
{
Sequence<T> in(99999, [](size_t v) -> T { return T(v); }); //fill 0..n
invoke_on_all_policies(test_is_sorted(), in.begin(), in.end(), std::is_sorted(in.begin(), in.end()));
invoke_on_all_policies(test_is_sorted(), in.cbegin(), in.cend(), std::is_sorted(in.begin(), in.end()));
in[in.size() / 2] = -1;
invoke_on_all_policies(test_is_sorted(), in.begin(), in.end(), std::is_sorted(in.begin(), in.end()));
invoke_on_all_policies(test_is_sorted(), in.cbegin(), in.cend(), std::is_sorted(in.begin(), in.end()));
in[1] = -1;
invoke_on_all_policies(test_is_sorted(), in.begin(), in.end(), std::is_sorted(in.begin(), in.end()));
invoke_on_all_policies(test_is_sorted(), in.cbegin(), in.cend(), std::is_sorted(in.begin(), in.end()));
//an empty container
Sequence<T> in0(0);
invoke_on_all_policies(test_is_sorted(), in0.begin(), in0.end(), std::is_sorted(in0.begin(), in0.end()));
invoke_on_all_policies(test_is_sorted(), in0.cbegin(), in0.cend(), std::is_sorted(in0.begin(), in0.end()));
//non-descending order
Sequence<T> in1(9, [](size_t v) -> T { return T(0); });
invoke_on_all_policies(test_is_sorted(), in1.begin(), in1.end(), std::is_sorted(in1.begin(), in1.end()));
invoke_on_all_policies(test_is_sorted(), in1.cbegin(), in1.cend(), std::is_sorted(in1.begin(), in1.end()));
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
is_sorted(exec, iter, iter, std::less<T>());
is_sorted_until(exec, iter, iter, std::less<T>());
}
};
int32_t
main()
{
test_is_sorted_by_type<int32_t>();
test_is_sorted_by_type<float64_t>();
test_is_sorted_by_type<Wrapper<int32_t>>();
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,174 @@
// -*- C++ -*-
//===-- test_lexicographical_compare.cpp ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include <string>
#include <iostream>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_one_policy
{
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename Predicate>
void
operator()(ExecutionPolicy&& exec, Iterator1 begin1, Iterator1 end1, Iterator2 begin2, Iterator2 end2,
Predicate pred)
{
const bool expected = std::lexicographical_compare(begin1, end1, begin2, end2, pred);
const bool actual = std::lexicographical_compare(exec, begin1, end1, begin2, end2, pred);
EXPECT_TRUE(actual == expected, "wrong return result from lexicographical compare with predicate");
}
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2>
void
operator()(ExecutionPolicy&& exec, Iterator1 begin1, Iterator1 end1, Iterator2 begin2, Iterator2 end2)
{
const bool expected = std::lexicographical_compare(begin1, end1, begin2, end2);
const bool actual = std::lexicographical_compare(exec, begin1, end1, begin2, end2);
EXPECT_TRUE(actual == expected, "wrong return result from lexicographical compare without predicate");
}
};
template <typename T1, typename T2, typename Predicate>
void
test(Predicate pred)
{
const std::size_t max_n = 1000000;
Sequence<T1> in1(max_n, [](std::size_t k) { return T1(k); });
Sequence<T2> in2(2 * max_n, [](std::size_t k) { return T2(k); });
std::size_t n2;
// Test case: Call algorithm's version without predicate.
invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + max_n, in2.cbegin() + 3 * max_n / 10,
in2.cbegin() + 5 * max_n / 10);
// Test case: If one range is a prefix of another, the shorter range is lexicographically less than the other.
std::size_t max_n2 = max_n / 10;
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + max_n, in2.cbegin(), in2.cbegin() + max_n2,
pred);
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + max_n, in2.begin() + max_n2,
in2.begin() + 3 * max_n2, pred);
// Test case: If one range is a prefix of another, the shorter range is lexicographically less than the other.
max_n2 = 2 * max_n;
invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + max_n, in2.begin(), in2.begin() + max_n2,
pred);
for (std::size_t n1 = 0; n1 <= max_n; n1 = n1 <= 16 ? n1 + 1 : std::size_t(3.1415 * n1))
{
// Test case: If two ranges have equivalent elements and are of the same length, then the ranges are lexicographically equal.
n2 = n1;
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.begin(), in2.begin() + n2, pred);
n2 = n1;
// Test case: two ranges have different elements and are of the same length (second sequence less than first)
std::size_t ind = n1 / 2;
in2[ind] = T2(-1);
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.begin(), in2.begin() + n2, pred);
in2[ind] = T2(ind);
// Test case: two ranges have different elements and are of the same length (first sequence less than second)
ind = n1 / 5;
in1[ind] = T1(-1);
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.cbegin(), in2.cbegin() + n2, pred);
in1[ind] = T1(ind);
}
}
template <typename Predicate>
void
test_string(Predicate pred)
{
const std::size_t max_n = 1000000;
std::string in1 = "";
std::string in2 = "";
for (std::size_t n1 = 0; n1 <= max_n; ++n1)
{
in1 += n1;
}
for (std::size_t n1 = 0; n1 <= 2 * max_n; ++n1)
{
in2 += n1;
}
std::size_t n2;
for (std::size_t n1 = 0; n1 < in1.size(); n1 = n1 <= 16 ? n1 + 1 : std::size_t(3.1415 * n1))
{
// Test case: If two ranges have equivalent elements and are of the same length, then the ranges are lexicographically equal.
n2 = n1;
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.begin(), in2.begin() + n2, pred);
n2 = n1;
// Test case: two ranges have different elements and are of the same length (second sequence less than first)
in2[n1 / 2] = 'a';
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.begin(), in2.begin() + n2, pred);
// Test case: two ranges have different elements and are of the same length (first sequence less than second)
in1[n1 / 5] = 'a';
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.cbegin(), in2.cbegin() + n2, pred);
}
invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + max_n, in2.cbegin() + 3 * max_n / 10,
in2.cbegin() + 5 * max_n / 10);
}
template <typename T>
struct LocalWrapper
{
explicit LocalWrapper(std::size_t k) : my_val(k) {}
bool
operator<(const LocalWrapper<T>& w) const
{
return my_val < w.my_val;
}
private:
T my_val;
};
template <typename T>
struct test_non_const
{
template <typename Policy, typename FirstIterator, typename SecondInterator>
void
operator()(Policy&& exec, FirstIterator first_iter, SecondInterator second_iter)
{
invoke_if(exec, [&]() {
lexicographical_compare(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::less<T>()));
});
}
};
int32_t
main()
{
test<uint16_t, float64_t>(std::less<float64_t>());
test<float32_t, int32_t>(std::greater<float32_t>());
#if !__PSTL_ICC_18_TEST_EARLY_EXIT_AVX_RELEASE_BROKEN
test<float64_t, int32_t>([](const float64_t x, const int32_t y) { return x * x < y * y; });
#endif
test<LocalWrapper<int32_t>, LocalWrapper<int32_t>>(
[](const LocalWrapper<int32_t>& x, const LocalWrapper<int32_t>& y) { return x < y; });
test_string([](const char x, const char y) { return x < y; });
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

114
pstl/test/test_merge.cpp Normal file
View File

@ -0,0 +1,114 @@
// -*- C++ -*-
//===-- test_merge.cpp ----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include <algorithm>
#include <functional>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_merge
{
template <typename Policy, typename InputIterator1, typename InputIterator2, typename OutputIterator,
typename Compare>
void
operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
OutputIterator out_first, OutputIterator out_last, Compare comp)
{
using namespace std;
{
const auto res = merge(exec, first1, last1, first2, last2, out_first, comp);
EXPECT_TRUE(res == out_last, "wrong return result from merge with predicate");
EXPECT_TRUE(is_sorted(out_first, res, comp), "wrong result from merge with predicate");
EXPECT_TRUE(includes(out_first, res, first1, last1, comp), "first sequence is not a part of result");
EXPECT_TRUE(includes(out_first, res, first2, last2, comp), "second sequence is not a part of result");
}
{
const auto res = merge(exec, first1, last1, first2, last2, out_first);
EXPECT_TRUE(res == out_last, "wrong return result from merge");
EXPECT_TRUE(is_sorted(out_first, res), "wrong result from merge");
}
}
// for reverse iterators
template <typename Policy, typename InputIterator1, typename InputIterator2, typename OutputIterator,
typename Compare>
void
operator()(Policy&& exec, std::reverse_iterator<InputIterator1> first1, std::reverse_iterator<InputIterator1> last1,
std::reverse_iterator<InputIterator2> first2, std::reverse_iterator<InputIterator2> last2,
std::reverse_iterator<OutputIterator> out_first, std::reverse_iterator<OutputIterator> out_last,
Compare comp)
{
using namespace std;
typedef typename std::iterator_traits<std::reverse_iterator<InputIterator1>>::value_type T;
const auto res = merge(exec, first1, last1, first2, last2, out_first, std::greater<T>());
EXPECT_TRUE(res == out_last, "wrong return result from merge with predicate");
EXPECT_TRUE(is_sorted(out_first, res, std::greater<T>()), "wrong result from merge with predicate");
EXPECT_TRUE(includes(out_first, res, first1, last1, std::greater<T>()),
"first sequence is not a part of result");
EXPECT_TRUE(includes(out_first, res, first2, last2, std::greater<T>()),
"second sequence is not a part of result");
}
};
template <typename T, typename Generator1, typename Generator2>
void
test_merge_by_type(Generator1 generator1, Generator2 generator2)
{
using namespace std;
size_t max_size = 100000;
Sequence<T> in1(max_size, generator1);
Sequence<T> in2(max_size / 2, generator2);
Sequence<T> out(in1.size() + in2.size());
std::sort(in1.begin(), in1.end());
std::sort(in2.begin(), in2.end());
for (size_t size = 0; size <= max_size; size = size <= 16 ? size + 1 : size_t(3.1415 * size))
{
invoke_on_all_policies(test_merge(), in1.cbegin(), in1.cbegin() + size, in2.data(), in2.data() + size / 2,
out.begin(), out.begin() + 1.5 * size, std::less<T>());
invoke_on_all_policies(test_merge(), in1.data(), in1.data() + size, in2.cbegin(), in2.cbegin() + size / 2,
out.begin(), out.begin() + 3 * size / 2, std::less<T>());
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename InputIterator, typename OutputIterator>
void
operator()(Policy&& exec, InputIterator input_iter, OutputIterator out_iter)
{
merge(exec, input_iter, input_iter, input_iter, input_iter, out_iter, non_const(std::less<T>()));
}
};
int32_t
main()
{
test_merge_by_type<int32_t>([](size_t v) { return (v % 2 == 0 ? v : -v) * 3; }, [](size_t v) { return v * 2; });
test_merge_by_type<float64_t>([](size_t v) { return float64_t(v); }, [](size_t v) { return float64_t(v - 100); });
#if !__PSTL_ICC_16_17_TEST_64_TIMEOUT
test_merge_by_type<Wrapper<int16_t>>([](size_t v) { return Wrapper<int16_t>(v % 100); },
[](size_t v) { return Wrapper<int16_t>(v % 10); });
#endif
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,192 @@
// -*- C++ -*-
//===-- test_minmax_element.cpp -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for min_element, max_element, minmax_element
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
#include <set>
#include <cassert>
#include <cmath>
using namespace TestUtils;
struct check_minelement
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator begin, Iterator end)
{
typedef typename std::iterator_traits<Iterator>::value_type T;
const Iterator expect = std::min_element(begin, end);
const Iterator result = std::min_element(exec, begin, end);
const Iterator result_pred = std::min_element(exec, begin, end, std::less<T>());
EXPECT_TRUE(expect == result, "wrong return result from min_element");
EXPECT_TRUE(expect == result_pred, "wrong return result from min_element");
}
};
struct check_maxelement
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator begin, Iterator end)
{
typedef typename std::iterator_traits<Iterator>::value_type T;
const Iterator expect = std::max_element(begin, end);
const Iterator result = std::max_element(exec, begin, end);
const Iterator result_pred = std::max_element(exec, begin, end, std::less<T>());
EXPECT_TRUE(expect == result, "wrong return result from max_element");
EXPECT_TRUE(expect == result_pred, "wrong return result from max_element");
}
};
struct check_minmaxelement
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator begin, Iterator end)
{
typedef typename std::iterator_traits<Iterator>::value_type T;
const std::pair<Iterator, Iterator> expect = std::minmax_element(begin, end);
const std::pair<Iterator, Iterator> got = std::minmax_element(exec, begin, end);
const std::pair<Iterator, Iterator> got_pred = std::minmax_element(exec, begin, end, std::less<T>());
EXPECT_TRUE(expect.first == got.first, "wrong return result from minmax_element (min part)");
EXPECT_TRUE(expect.second == got.second, "wrong return result from minmax_element (max part)");
EXPECT_TRUE(expect == got_pred, "wrong return result from minmax_element");
}
};
template <typename T>
struct sequence_wrapper
{
TestUtils::Sequence<T> seq;
const T min_value;
const T max_value;
static const std::size_t bits = 30; // We assume that T can handle signed 2^bits+1 value
// TestUtils::HashBits returns value between 0 and (1<<bits)-1,
// therefore we could threat 1<<bits as maximum and -(1<<bits) as a minimum
sequence_wrapper(std::size_t n) : seq(n), min_value(-(1 << bits)), max_value(1 << bits) {}
void
pattern_fill()
{
seq.fill([](std::size_t i) -> T { return T(TestUtils::HashBits(i, bits)); });
}
// sets first one at position `at` and bunch of them farther
void
set_desired_value(std::size_t at, T value)
{
if (seq.size() == 0)
return;
seq[at] = value;
//Producing serveral red herrings
for (std::size_t i = at + 1; i < seq.size(); i += 1 + TestUtils::HashBits(i, 5))
seq[i] = value;
}
};
template <typename T>
void
test_by_type(std::size_t n)
{
sequence_wrapper<T> wseq(n);
// to avoid overtesing we use std::set to leave only unique indexes
std::set<std::size_t> targets{0};
if (n > 1)
{
targets.insert(1);
targets.insert(2.718282 * n / 3);
targets.insert(n / 2);
targets.insert(n / 7.389056);
targets.insert(n - 1); // last
}
for (std::set<std::size_t>::iterator it = targets.begin(); it != targets.end(); ++it)
{
wseq.pattern_fill();
wseq.set_desired_value(*it, wseq.min_value);
TestUtils::invoke_on_all_policies(check_minelement(), wseq.seq.cbegin(), wseq.seq.cend());
TestUtils::invoke_on_all_policies(check_minelement(), wseq.seq.begin(), wseq.seq.end());
wseq.set_desired_value(*it, wseq.max_value);
TestUtils::invoke_on_all_policies(check_maxelement(), wseq.seq.cbegin(), wseq.seq.cend());
TestUtils::invoke_on_all_policies(check_maxelement(), wseq.seq.begin(), wseq.seq.end());
if (targets.size() > 1)
{
for (std::set<std::size_t>::reverse_iterator rit = targets.rbegin(); rit != targets.rend(); ++rit)
{
if (*rit == *it) // we requires at least 2 unique indexes in targets
break;
wseq.pattern_fill();
wseq.set_desired_value(*it, wseq.min_value); // setting minimum element
wseq.set_desired_value(*rit, wseq.max_value); // setting maximum element
TestUtils::invoke_on_all_policies(check_minmaxelement(), wseq.seq.cbegin(), wseq.seq.cend());
TestUtils::invoke_on_all_policies(check_minmaxelement(), wseq.seq.begin(), wseq.seq.end());
}
}
else
{ // we must check this corner case; it can not be tested in loop above
TestUtils::invoke_on_all_policies(check_minmaxelement(), wseq.seq.cbegin(), wseq.seq.cend());
TestUtils::invoke_on_all_policies(check_minmaxelement(), wseq.seq.begin(), wseq.seq.end());
}
}
}
// should provide minimal requirements only
struct OnlyLessCompare
{
int32_t val;
OnlyLessCompare() : val(0) {}
OnlyLessCompare(int32_t val_) : val(val_) {}
bool
operator<(const OnlyLessCompare& other) const
{
return val < other.val;
}
};
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
max_element(exec, iter, iter, non_const(std::less<T>()));
min_element(exec, iter, iter, non_const(std::less<T>()));
minmax_element(exec, iter, iter, non_const(std::less<T>()));
}
};
int32_t
main()
{
using TestUtils::float64_t;
const std::size_t N = 100000;
for (std::size_t n = 0; n < N; n = n < 16 ? n + 1 : size_t(3.14159 * n))
{
test_by_type<float64_t>(n);
test_by_type<OnlyLessCompare>(n);
}
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << TestUtils::done() << std::endl;
return 0;
}

133
pstl/test/test_mismatch.cpp Normal file
View File

@ -0,0 +1,133 @@
// -*- C++ -*-
//===-- test_mismatch.cpp -------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for the rest algorithms; temporary approach to check compiling
#include "pstl/execution"
#include "pstl/algorithm"
#include "pstl/numeric"
#include "pstl/memory"
#include "utils.h"
using namespace TestUtils;
struct test_mismatch
{
template <typename Policy, typename Iterator1, typename Iterator2>
void
operator()(Policy&& exec, Iterator1 first1, Iterator1 last1, Iterator2 first2)
{
using namespace std;
typedef typename iterator_traits<Iterator1>::value_type T;
{
const auto expected = std::mismatch(first1, last1, first2, std::equal_to<T>());
const auto res3 = mismatch(exec, first1, last1, first2, std::equal_to<T>());
EXPECT_TRUE(expected == res3, "wrong return result from mismatch");
const auto res4 = mismatch(exec, first1, last1, first2);
EXPECT_TRUE(expected == res4, "wrong return result from mismatch");
}
}
template <typename Policy, typename Iterator1, typename Iterator2>
void
operator()(Policy&& exec, Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
{
using namespace std;
typedef typename iterator_traits<Iterator1>::value_type T;
{
const auto expected = mismatch(pstl::execution::seq, first1, last1, first2, last2, std::equal_to<T>());
const auto res1 = mismatch(exec, first1, last1, first2, last2, std::equal_to<T>());
EXPECT_TRUE(expected == res1, "wrong return result from mismatch");
const auto res2 = mismatch(exec, first1, last1, first2, last2);
EXPECT_TRUE(expected == res2, "wrong return result from mismatch");
}
}
};
template <typename T>
void
test_mismatch_by_type()
{
using namespace std;
for (size_t size = 0; size <= 100000; size = size <= 16 ? size + 1 : size_t(3.1415 * size))
{
const T val = T(-1);
Sequence<T> in(size, [](size_t v) -> T { return T(v % 100); });
{
Sequence<T> in2(in);
invoke_on_all_policies(test_mismatch(), in.begin(), in.end(), in2.begin(), in2.end());
invoke_on_all_policies(test_mismatch(), in.begin(), in.end(), in2.begin());
const size_t min_size = 3;
if (size > min_size)
{
const size_t idx_for_1 = size / min_size;
in[idx_for_1] = val, in[idx_for_1 + 1] = val, in[idx_for_1 + 2] = val;
invoke_on_all_policies(test_mismatch(), in.begin(), in.end(), in2.begin(), in2.end());
invoke_on_all_policies(test_mismatch(), in.begin(), in.end(), in2.begin());
}
const size_t idx_for_2 = 500;
if (size >= idx_for_2 - 1)
{
in2[size / idx_for_2] = val;
invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin(), in2.cend());
invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin());
}
}
{
Sequence<T> in2(100, [](size_t v) -> T { return T(v); });
invoke_on_all_policies(test_mismatch(), in2.begin(), in2.end(), in.begin(), in.end());
// We can't call std::mismatch with semantic below when size of second sequence less than size of first sequence
if (in2.size() <= in.size())
invoke_on_all_policies(test_mismatch(), in2.begin(), in2.end(), in.begin());
const size_t idx = 97;
in2[idx] = val;
in2[idx + 1] = val;
invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin(), in2.cend());
if (in.size() <= in2.size())
invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin());
}
{
Sequence<T> in2({});
invoke_on_all_policies(test_mismatch(), in2.begin(), in2.end(), in.begin(), in.end());
invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin(), in2.cend());
if (in.size() == 0)
invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin());
}
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename FirstIterator, typename SecondInterator>
void
operator()(Policy&& exec, FirstIterator first_iter, SecondInterator second_iter)
{
mismatch(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::less<T>()));
}
};
int32_t
main()
{
test_mismatch_by_type<int32_t>();
test_mismatch_by_type<float64_t>();
test_mismatch_by_type<Wrapper<int32_t>>();
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,99 @@
// -*- C++ -*-
//===-- test_none_of.cpp --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
/*
TODO: consider implementing the following tests for a better code coverage
- correctness
- bad input argument (if applicable)
- data corruption around/of input and output
- correctly work with nested parallelism
- check that algorithm does not require anything more than is described in its requirements section
*/
using namespace TestUtils;
struct test_none_of
{
template <typename ExecutionPolicy, typename Iterator, typename Predicate>
void
operator()(ExecutionPolicy&& exec, Iterator begin, Iterator end, Predicate pred, bool expected)
{
auto actualr = std::none_of(exec, begin, end, pred);
EXPECT_EQ(expected, actualr, "result for none_of");
}
};
template <typename T>
void
test(size_t bits)
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
// Sequence of odd values
Sequence<T> in(n, [n, bits](size_t k) { return T(2 * HashBits(n, bits - 1) ^ 1); });
// Even value, or false when T is bool.
T spike(2 * HashBits(n, bits - 1));
invoke_on_all_policies(test_none_of(), in.begin(), in.end(), is_equal_to<T>(spike), true);
invoke_on_all_policies(test_none_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), true);
if (n > 0)
{
// Sprinkle in a hit
in[2 * n / 3] = spike;
invoke_on_all_policies(test_none_of(), in.begin(), in.end(), is_equal_to<T>(spike), false);
invoke_on_all_policies(test_none_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), false);
// Sprinkle in a few more hits
in[n / 3] = spike;
in[n / 2] = spike;
invoke_on_all_policies(test_none_of(), in.begin(), in.end(), is_equal_to<T>(spike), false);
invoke_on_all_policies(test_none_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), false);
}
}
}
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
none_of(exec, iter, iter, non_const(is_even));
}
};
int32_t
main()
{
test<int32_t>(8 * sizeof(int32_t));
test<uint16_t>(8 * sizeof(uint16_t));
test<float64_t>(53);
#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN
test<bool>(1);
#endif
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,176 @@
// -*- C++ -*-
//===-- test_nth_element.cpp ----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include <algorithm>
#include <iostream>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
// User defined type with minimal requirements
template <typename T>
struct DataType
{
explicit DataType(int32_t k) : my_val(k) {}
DataType(DataType&& input)
{
my_val = std::move(input.my_val);
input.my_val = T(0);
}
DataType&
operator=(DataType&& input)
{
my_val = std::move(input.my_val);
input.my_val = T(0);
return *this;
}
T
get_val() const
{
return my_val;
}
friend std::ostream&
operator<<(std::ostream& stream, const DataType<T>& input)
{
return stream << input.my_val;
}
private:
T my_val;
};
template <typename T>
bool
is_equal(const DataType<T>& x, const DataType<T>& y)
{
return x.get_val() == y.get_val();
}
template <typename T>
bool
is_equal(const T& x, const T& y)
{
return x == y;
}
struct test_one_policy
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN // dummy specialization by policy type, in case of broken configuration
template <typename Iterator1, typename Size, typename Generator1, typename Generator2, typename Compare>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::unsequenced_policy, Iterator1 first1, Iterator1 last1, Iterator1 first2,
Iterator1 last2, Size n, Size m, Generator1 generator1, Generator2 generator2, Compare comp)
{
}
template <typename Iterator1, typename Size, typename Generator1, typename Generator2, typename Compare>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 first1, Iterator1 last1, Iterator1 first2,
Iterator1 last2, Size n, Size m, Generator1 generator1, Generator2 generator2, Compare comp)
{
}
#endif
// nth_element works only with random access iterators
template <typename Policy, typename Iterator1, typename Size, typename Generator1, typename Generator2,
typename Compare>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(Policy&& exec, Iterator1 first1, Iterator1 last1, Iterator1 first2, Iterator1 last2, Size n, Size m,
Generator1 generator1, Generator2 generator2, Compare comp)
{
using T = typename std::iterator_traits<Iterator1>::value_type;
const Iterator1 mid1 = std::next(first1, m);
const Iterator1 mid2 = std::next(first2, m);
fill_data(first1, mid1, generator1);
fill_data(mid1, last1, generator2);
fill_data(first2, mid2, generator1);
fill_data(mid2, last2, generator2);
std::nth_element(first1, mid1, last1, comp);
std::nth_element(exec, first2, mid2, last2, comp);
if (m > 0 && m < n)
{
EXPECT_TRUE(is_equal(*mid1, *mid2), "wrong result from nth_element with predicate");
}
EXPECT_TRUE(std::find_first_of(first2, mid2, mid2, last2, [comp](T& x, T& y) { return comp(y, x); }) == mid2,
"wrong effect from nth_element with predicate");
}
template <typename Policy, typename Iterator1, typename Size, typename Generator1, typename Generator2,
typename Compare>
typename std::enable_if<!is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(Policy&& exec, Iterator1 first1, Iterator1 last1, Iterator1 first2, Iterator1 last2, Size n, Size m,
Generator1 generator1, Generator2 generator2, Compare comp)
{
}
};
template <typename T, typename Generator1, typename Generator2, typename Compare>
void
test_by_type(Generator1 generator1, Generator2 generator2, Compare comp)
{
using namespace std;
size_t max_size = 10000;
Sequence<T> in1(max_size, [](size_t v) { return T(v); });
Sequence<T> exp(max_size, [](size_t v) { return T(v); });
size_t m;
for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
m = 0;
invoke_on_all_policies(test_one_policy(), exp.begin(), exp.begin() + n, in1.begin(), in1.begin() + n, n, m,
generator1, generator2, comp);
m = n / 7;
invoke_on_all_policies(test_one_policy(), exp.begin(), exp.begin() + n, in1.begin(), in1.begin() + n, n, m,
generator1, generator2, comp);
m = 3 * n / 5;
invoke_on_all_policies(test_one_policy(), exp.begin(), exp.begin() + n, in1.begin(), in1.begin() + n, n, m,
generator1, generator2, comp);
}
invoke_on_all_policies(test_one_policy(), exp.begin(), exp.begin() + max_size, in1.begin(), in1.begin() + max_size,
max_size, max_size, generator1, generator2, comp);
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
invoke_if(exec, [&]() { nth_element(exec, iter, iter, iter, non_const(std::less<T>())); });
}
};
int32_t
main()
{
test_by_type<int32_t>([](int32_t i) { return 10 * i; }, [](int32_t i) { return i + 1; }, std::less<int32_t>());
test_by_type<int32_t>([](int32_t) { return 0; }, [](int32_t) { return 0; }, std::less<int32_t>());
test_by_type<float64_t>([](int32_t i) { return -2 * i; }, [](int32_t i) { return -(2 * i + 1); },
[](const float64_t x, const float64_t y) { return x > y; });
test_by_type<DataType<float32_t>>(
[](int32_t i) { return DataType<float32_t>(2 * i + 1); }, [](int32_t i) { return DataType<float32_t>(2 * i); },
[](const DataType<float32_t>& x, const DataType<float32_t>& y) { return x.get_val() < y.get_val(); });
test_algo_basic_single<int32_t>(run_for_rnd<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,150 @@
// -*- C++ -*-
//===-- test_partial_sort.cpp ---------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for partial_sort
#include <cmath>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
static std::atomic<int32_t> count_val;
static std::atomic<int32_t> count_comp;
template <typename T>
struct Num
{
T val;
Num() { ++count_val; }
Num(T v) : val(v) { ++count_val; }
Num(const Num<T>& v) : val(v.val) { ++count_val; }
Num(Num<T>&& v) : val(v.val) { ++count_val; }
~Num() { --count_val; }
Num<T>&
operator=(const Num<T>& v)
{
val = v.val;
return *this;
}
operator T() const { return val; }
bool
operator<(const Num<T>& v) const
{
++count_comp;
return val < v.val;
}
};
struct test_brick_partial_sort
{
template <typename Policy, typename InputIterator, typename Compare>
typename std::enable_if<is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
void>::type
operator()(Policy&& exec, InputIterator first, InputIterator last, InputIterator exp_first, InputIterator exp_last,
Compare compare)
{
typedef typename std::iterator_traits<InputIterator>::value_type T;
// The rand()%(2*n+1) encourages generation of some duplicates.
std::srand(42);
const std::size_t n = last - first;
for (std::size_t k = 0; k < n; ++k)
{
first[k] = T(rand() % (2 * n + 1));
}
std::copy(first, last, exp_first);
for (std::size_t p = 0; p < n; p = p <= 16 ? p + 1 : std::size_t(31.415 * p))
{
auto m1 = first + p;
auto m2 = exp_first + p;
std::partial_sort(exp_first, m2, exp_last, compare);
count_comp = 0;
std::partial_sort(exec, first, m1, last, compare);
EXPECT_EQ_N(exp_first, first, p, "wrong effect from partial_sort");
//checking upper bound number of comparisons; O(p*(last-first)log(middle-first)); where p - number of threads;
if (m1 - first > 1)
{
auto complex = std::ceil(n * std::log(float32_t(m1 - first)));
#if __PSTL_USE_PAR_POLICIES
auto p = tbb::this_task_arena::max_concurrency();
#else
auto p = 1;
#endif
#ifdef _DEBUG
if (count_comp > complex * p)
{
std::cout << "complexity exceeded" << std::endl;
}
#endif
}
}
}
template <typename Policy, typename InputIterator, typename Compare>
typename std::enable_if<!is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
void>::type
operator()(Policy&& exec, InputIterator first, InputIterator last, InputIterator exp_first, InputIterator exp_last,
Compare compare)
{
}
};
template <typename T, typename Compare>
void
test_partial_sort(Compare compare)
{
const std::size_t n_max = 100000;
Sequence<T> in(n_max);
Sequence<T> exp(n_max);
for (std::size_t n = 0; n < n_max; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
invoke_on_all_policies(test_brick_partial_sort(), in.begin(), in.begin() + n, exp.begin(), exp.begin() + n,
compare);
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
partial_sort(exec, iter, iter, iter, non_const(std::less<T>()));
}
};
int32_t
main()
{
count_val = 0;
test_partial_sort<Num<float32_t>>([](Num<float32_t> x, Num<float32_t> y) { return x < y; });
EXPECT_TRUE(count_val == 0, "cleanup error");
test_partial_sort<int32_t>(
[](int32_t x, int32_t y) { return x > y; }); // Reversed so accidental use of < will be detected.
test_algo_basic_single<int32_t>(run_for_rnd<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,190 @@
// -*- C++ -*-
//===-- test_partial_sort_copy.cpp ----------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for partial_sort_copy
#include <cmath>
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename T>
struct Num
{
T val;
Num() : val(0) {}
Num(T v) : val(v) {}
Num(const Num<T>& v) : val(v.val) {}
Num(Num<T>&& v) : val(v.val) {}
Num<T>&
operator=(const Num<T>& v)
{
val = v.val;
return *this;
}
operator T() const { return val; }
bool
operator<(const Num<T>& v) const
{
return val < v.val;
}
};
template <typename RandomAccessIterator>
struct test_one_policy
{
RandomAccessIterator d_first;
RandomAccessIterator d_last;
RandomAccessIterator exp_first;
RandomAccessIterator exp_last;
// This ctor is needed because output shouldn't be transformed to any iterator type (only random access iterators are allowed)
test_one_policy(RandomAccessIterator b1, RandomAccessIterator e1, RandomAccessIterator b2, RandomAccessIterator e2)
: d_first(b1), d_last(e1), exp_first(b2), exp_last(e2)
{
}
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN // dummy specialization by policy type, in case of broken configuration
template <typename InputIterator, typename Size, typename T, typename Compare>
void
operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, Size n1, Size n2,
const T& trash, Compare compare)
{
}
template <typename InputIterator, typename Size, typename T, typename Compare>
void
operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, Size n1, Size n2,
const T& trash, Compare compare)
{
}
template <typename InputIterator, typename Size, typename T>
void
operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, Size n1, Size n2,
const T& trash)
{
}
template <typename InputIterator, typename Size, typename T>
void
operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, Size n1, Size n2,
const T& trash)
{
}
#endif
template <typename Policy, typename InputIterator, typename Size, typename T, typename Compare>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, Size n1, Size n2, const T& trash,
Compare compare)
{
prepare_data(first, last, n1, trash);
RandomAccessIterator exp = std::partial_sort_copy(first, last, exp_first, exp_last, compare);
RandomAccessIterator res = std::partial_sort_copy(exec, first, last, d_first, d_last, compare);
EXPECT_TRUE((exp - exp_first) == (res - d_first), "wrong result from partial_sort_copy with predicate");
EXPECT_EQ_N(exp_first, d_first, n2, "wrong effect from partial_sort_copy with predicate");
}
template <typename Policy, typename InputIterator, typename Size, typename T>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, Size n1, Size n2, const T& trash)
{
prepare_data(first, last, n1, trash);
RandomAccessIterator exp = std::partial_sort_copy(first, last, exp_first, exp_last);
RandomAccessIterator res = std::partial_sort_copy(exec, first, last, d_first, d_last);
EXPECT_TRUE((exp - exp_first) == (res - d_first), "wrong result from partial_sort_copy without predicate");
EXPECT_EQ_N(exp_first, d_first, n2, "wrong effect from partial_sort_copy without predicate");
}
private:
template <typename InputIterator, typename Size, typename T>
void
prepare_data(InputIterator first, InputIterator last, Size n1, const T& trash)
{
// The rand()%(2*n+1) encourages generation of some duplicates.
std::srand(42);
std::generate(first, last, [n1]() { return T(rand() % (2 * n1 + 1)); });
std::fill(exp_first, exp_last, trash);
std::fill(d_first, d_last, trash);
}
};
template <typename T, typename Compare>
void
test_partial_sort_copy(Compare compare)
{
typedef typename Sequence<T>::iterator iterator_type;
const std::size_t n_max = 100000;
Sequence<T> in(n_max);
Sequence<T> out(2 * n_max);
Sequence<T> exp(2 * n_max);
std::size_t n1 = 0;
std::size_t n2;
T trash = T(-666);
for (; n1 < n_max; n1 = n1 <= 16 ? n1 + 1 : size_t(3.1415 * n1))
{
// If both sequences are equal
n2 = n1;
invoke_on_all_policies(
test_one_policy<iterator_type>(out.begin(), out.begin() + n2, exp.begin(), exp.begin() + n2), in.begin(),
in.begin() + n1, n1, n2, trash, compare);
// If first sequence is greater than second
n2 = n1 / 3;
invoke_on_all_policies(
test_one_policy<iterator_type>(out.begin(), out.begin() + n2, exp.begin(), exp.begin() + n2), in.begin(),
in.begin() + n1, n1, n2, trash, compare);
// If first sequence is less than second
n2 = 2 * n1;
invoke_on_all_policies(
test_one_policy<iterator_type>(out.begin(), out.begin() + n2, exp.begin(), exp.begin() + n2), in.begin(),
in.begin() + n1, n1, n2, trash, compare);
}
// Test partial_sort_copy without predicate
n1 = n_max;
n2 = 2 * n1;
invoke_on_all_policies(test_one_policy<iterator_type>(out.begin(), out.begin() + n2, exp.begin(), exp.begin() + n2),
in.begin(), in.begin() + n1, n1, n2, trash);
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename InputIterator, typename OutputInterator>
void
operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter)
{
invoke_if(exec, [&]() {
partial_sort_copy(exec, input_iter, input_iter, out_iter, out_iter, non_const(std::less<T>()));
});
}
};
int32_t
main()
{
test_partial_sort_copy<Num<float32_t>>([](Num<float32_t> x, Num<float32_t> y) { return x < y; });
test_partial_sort_copy<int32_t>([](int32_t x, int32_t y) { return x > y; });
test_algo_basic_double<int32_t>(run_for_rnd<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,178 @@
// -*- C++ -*-
//===-- test_partition.cpp ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for stable_partition and partition
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
#include <iterator>
#include <type_traits>
using namespace TestUtils;
template <typename T>
struct DataType
{
explicit DataType(int32_t k) : my_val(k) {}
DataType(DataType&& input) { my_val = std::move(input.my_val); }
DataType&
operator=(DataType&& input)
{
my_val = std::move(input.my_val);
return *this;
}
T
get_val() const
{
return my_val;
}
friend std::ostream&
operator<<(std::ostream& stream, const DataType<T>& input)
{
return stream << input.my_val;
}
private:
T my_val;
};
template <typename Iterator>
typename std::enable_if<std::is_trivial<typename std::iterator_traits<Iterator>::value_type>::value, bool>::type
is_equal(Iterator first, Iterator last, Iterator d_first)
{
return std::equal(first, last, d_first);
}
template <typename Iterator>
typename std::enable_if<!std::is_trivial<typename std::iterator_traits<Iterator>::value_type>::value, bool>::type
is_equal(Iterator first, Iterator last, Iterator d_first)
{
return true;
}
struct test_one_policy
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specializations to skip testing in case of broken configuration
template <typename BiDirIt, typename Size, typename UnaryOp, typename Generator>
void
operator()(pstl::execution::unsequenced_policy, BiDirIt first, BiDirIt last, BiDirIt exp_first, BiDirIt exp_last,
Size n, UnaryOp unary_op, Generator generator)
{
}
template <typename BiDirIt, typename Size, typename UnaryOp, typename Generator>
void
operator()(pstl::execution::parallel_unsequenced_policy, BiDirIt first, BiDirIt last, BiDirIt exp_first,
BiDirIt exp_last, Size n, UnaryOp unary_op, Generator generator)
{
}
#elif __PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN //dummy specializations to skip testing in case of broken configuration
template <typename BiDirIt, typename Size, typename UnaryOp, typename Generator>
void
operator()(pstl::execution::parallel_policy, BiDirIt first, BiDirIt last, BiDirIt exp_first, BiDirIt exp_last,
Size n, UnaryOp unary_op, Generator generator)
{
}
template <typename BiDirIt, typename Size, typename UnaryOp, typename Generator>
void
operator()(pstl::execution::parallel_unsequenced_policy, BiDirIt first, BiDirIt last, BiDirIt exp_first,
BiDirIt exp_last, Size n, UnaryOp unary_op, Generator generator)
{
}
#endif
template <typename Policy, typename BiDirIt, typename Size, typename UnaryOp, typename Generator>
typename std::enable_if<!is_same_iterator_category<BiDirIt, std::forward_iterator_tag>::value, void>::type
operator()(Policy&& exec, BiDirIt first, BiDirIt last, BiDirIt exp_first, BiDirIt exp_last, Size n,
UnaryOp unary_op, Generator generator)
{
// partition
{
fill_data(first, last, generator);
BiDirIt actual_ret = std::partition(exec, first, last, unary_op);
EXPECT_TRUE(std::all_of(first, actual_ret, unary_op) && !std::any_of(actual_ret, last, unary_op),
"wrong effect from partition");
}
// stable_partition
{
fill_data(exp_first, exp_last, generator);
BiDirIt exp_ret = std::stable_partition(exp_first, exp_last, unary_op);
fill_data(first, last, generator);
BiDirIt actual_ret = std::stable_partition(exec, first, last, unary_op);
EXPECT_TRUE(std::distance(first, actual_ret) == std::distance(exp_first, exp_ret),
"wrong result from stable_partition");
EXPECT_TRUE((is_equal<BiDirIt>(exp_first, exp_last, first)), "wrong effect from stable_partition");
}
}
template <typename Policy, typename BiDirIt, typename Size, typename UnaryOp, typename Generator>
typename std::enable_if<is_same_iterator_category<BiDirIt, std::forward_iterator_tag>::value, void>::type
operator()(Policy&& exec, BiDirIt first, BiDirIt last, BiDirIt exp_first, BiDirIt exp_last, Size n,
UnaryOp unary_op, Generator generator)
{
}
};
template <typename T, typename Generator, typename UnaryPred>
void
test_by_type(Generator generator, UnaryPred pred)
{
using namespace std;
size_t max_size = 100000;
Sequence<T> in(max_size, [](size_t v) { return T(v); });
Sequence<T> exp(max_size, [](size_t v) { return T(v); });
for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
invoke_on_all_policies(test_one_policy(), in.begin(), in.begin() + n, exp.begin(), exp.begin() + n, n, pred,
generator);
}
}
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
invoke_if(exec, [&]() {
partition(exec, iter, iter, non_const(is_even));
stable_partition(exec, iter, iter, non_const(is_even));
});
}
};
int32_t
main()
{
#if !__PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN
test_by_type<int32_t>([](int32_t i) { return i; }, [](int32_t) { return true; });
#endif
test_by_type<float64_t>([](int32_t i) { return -i; }, [](const float64_t x) { return x < 0; });
test_by_type<int64_t>([](int32_t i) { return i + 1; }, [](int64_t x) { return x % 3 == 0; });
test_by_type<DataType<float32_t>>([](int32_t i) { return DataType<float32_t>(2 * i + 1); },
[](const DataType<float32_t>& x) { return x.get_val() < 0; });
test_algo_basic_single<int32_t>(run_for_rnd_bi<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,115 @@
// -*- C++ -*-
//===-- test_partition_copy.cpp -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for stable_partition and partition_copy
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
#include <cstdlib>
#include <iterator>
using namespace TestUtils;
struct test_partition_copy
{
template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2,
typename UnaryOp>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator true_first,
OutputIterator true_last, OutputIterator2 false_first, OutputIterator2 false_last, UnaryOp unary_op)
{
auto actual_ret = std::partition_copy(exec, first, last, true_first, false_first, unary_op);
EXPECT_TRUE(std::distance(true_first, actual_ret.first) == std::count_if(first, last, unary_op),
"partition_copy has wrong effect from true sequence");
EXPECT_TRUE(std::distance(false_first, actual_ret.second) ==
std::count_if(first, last, __pstl::internal::not_pred<UnaryOp>(unary_op)),
"partition_copy has wrong effect from false sequence");
}
//dummy specialization by iterator type and policy type, in case of broken configuration
#if __PSTL_ICC_1800_TEST_MONOTONIC_RELEASE_64_BROKEN
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename UnaryOp>
void
operator()(pstl::execution::unsequenced_policy, std::reverse_iterator<InputIterator> first,
std::reverse_iterator<InputIterator> last, std::reverse_iterator<OutputIterator> true_first,
std::reverse_iterator<OutputIterator> true_last, std::reverse_iterator<OutputIterator2> false_first,
OutputIterator2 false_last, UnaryOp unary_op)
{
}
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename UnaryOp>
void
operator()(pstl::execution::parallel_unsequenced_policy, std::reverse_iterator<InputIterator> first,
std::reverse_iterator<InputIterator> last, std::reverse_iterator<OutputIterator> true_first,
std::reverse_iterator<OutputIterator> true_last, std::reverse_iterator<OutputIterator2> false_first,
OutputIterator2 false_last, UnaryOp unary_op)
{
}
#endif
};
template <typename T, typename UnaryPred>
void
test(UnaryPred pred)
{
const std::size_t max_size = 100000;
Sequence<T> in(max_size, [](std::size_t v) -> T { return T(v); });
Sequence<T> actual_true(max_size);
Sequence<T> actual_false(max_size);
for (std::size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : std::size_t(3.1415 * n))
{
// for non-const input iterators
invoke_on_all_policies(test_partition_copy(), in.begin(), in.begin() + n, actual_true.begin(),
actual_true.begin() + n, actual_false.begin(), actual_false.begin() + n, pred);
// for const input iterators
invoke_on_all_policies(test_partition_copy(), in.cbegin(), in.cbegin() + n, actual_true.begin(),
actual_true.begin() + n, actual_false.begin(), actual_false.begin() + n, pred);
}
}
struct test_non_const
{
template <typename Policy, typename InputIterator, typename OutputInterator>
void
operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
partition_copy(exec, input_iter, input_iter, out_iter, out_iter, non_const(is_even));
}
};
int32_t
main()
{
test<int32_t>([](const int32_t value) { return value % 2; });
#if !__PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN
test<int32_t>([](const int32_t value) { return true; });
#endif
test<float64_t>([](const float64_t value) { return value > 2 << 6; });
test<Wrapper<float64_t>>([](const Wrapper<float64_t>& value) -> bool { return value.get_my_field() != nullptr; });
test_algo_basic_double<int32_t>(run_for_rnd_bi<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

112
pstl/test/test_reduce.cpp Normal file
View File

@ -0,0 +1,112 @@
// -*- C++ -*-
//===-- test_reduce.cpp ---------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/numeric"
#include "utils.h"
using namespace TestUtils;
struct test_long_forms_for_one_policy
{
template <typename Policy, typename Iterator, typename T, typename BinaryOp>
void
operator()(Policy&& exec, Iterator first, Iterator last, T init, BinaryOp binary, T expected)
{
T result_r = std::reduce(exec, first, last, init, binary);
EXPECT_EQ(expected, result_r, "bad result from reduce(exec, first, last, init, binary_op)");
}
};
template <typename T, typename BinaryOp, typename F>
void
test_long_form(T init, BinaryOp binary_op, F f)
{
// Try sequences of various lengths
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
T expected(init);
Sequence<T> in(n, [n, f](size_t k) { return f((int32_t(k ^ n) % 1000 - 500)); });
for (size_t k = 0; k < n; ++k)
expected = binary_op(expected, in[k]);
using namespace std;
T result = transform_reduce_serial(in.cfbegin(), in.cfend(), init, binary_op, [](const T& t) { return t; });
EXPECT_EQ(expected, result, "bad result from reduce(first, last, init, binary_op_op)");
invoke_on_all_policies(test_long_forms_for_one_policy(), in.begin(), in.end(), init, binary_op, expected);
invoke_on_all_policies(test_long_forms_for_one_policy(), in.cbegin(), in.cend(), init, binary_op, expected);
}
}
struct test_two_short_forms
{
#if __PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename Iterator>
void
operator()(pstl::execution::parallel_policy, Iterator first, Iterator last, Sum init, Sum expected)
{
}
template <typename Iterator>
void
operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Sum init, Sum expected)
{
}
#endif
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator first, Iterator last, Sum init, Sum expected)
{
using namespace std;
Sum r0 = init + reduce(exec, first, last);
EXPECT_EQ(expected, r0, "bad result from reduce(exec, first, last)");
Sum r1 = reduce(exec, first, last, init);
EXPECT_EQ(expected, r1, "bad result from reduce(exec, first, last, init)");
}
};
// Test forms of reduce(...) that omit the binary_op or init operands.
void
test_short_forms()
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sum init(42, OddTag());
Sum expected(init);
Sequence<Sum> in(n, [n](size_t k) { return Sum((int32_t(k ^ n) % 1000 - 500), OddTag()); });
for (size_t k = 0; k < n; ++k)
expected = expected + in[k];
invoke_on_all_policies(test_two_short_forms(), in.begin(), in.end(), init, expected);
invoke_on_all_policies(test_two_short_forms(), in.cbegin(), in.cend(), init, expected);
}
}
int32_t
main()
{
// Test for popular types
test_long_form(42, std::plus<int32_t>(), [](int32_t x) { return x; });
test_long_form(42.0, std::plus<float64_t>(), [](float64_t x) { return x; });
// Test for strict types
test_long_form<Number>(Number(42, OddTag()), Add(OddTag()), [](int32_t x) { return Number(x, OddTag()); });
// Short forms are just facade for long forms, so just test with a single type.
test_short_forms();
std::cout << done() << std::endl;
return 0;
}

152
pstl/test/test_remove.cpp Normal file
View File

@ -0,0 +1,152 @@
// -*- C++ -*-
//===-- test_remove.cpp ---------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Test for remove, remove_if
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct run_remove
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename InputIterator, typename OutputIterator, typename Size, typename T>
void
operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size n,
const T& value)
{
}
template <typename InputIterator, typename OutputIterator, typename Size, typename T>
void
operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last,
OutputIterator out_first, OutputIterator out_last, OutputIterator expected_first,
OutputIterator expected_last, Size n, const T& value)
{
}
#endif
template <typename Policy, typename InputIterator, typename OutputIterator, typename Size, typename T>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size,
const T& value)
{
// Cleaning
std::copy(first, last, expected_first);
std::copy(first, last, out_first);
// Run remove
OutputIterator i = remove(expected_first, expected_last, value);
OutputIterator k = remove(exec, out_first, out_last, value);
EXPECT_TRUE(std::distance(expected_first, i) == std::distance(out_first, k), "wrong return value from remove");
EXPECT_EQ_N(expected_first, out_first, std::distance(expected_first, i), "wrong remove effect");
}
};
struct run_remove_if
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename InputIterator, typename OutputIterator, typename Size, typename Predicate>
void
operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size n,
Predicate pred)
{
}
template <typename InputIterator, typename OutputIterator, typename Size, typename Predicate>
void
operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last,
OutputIterator out_first, OutputIterator out_last, OutputIterator expected_first,
OutputIterator expected_last, Size n, Predicate pred)
{
}
#endif
template <typename Policy, typename InputIterator, typename OutputIterator, typename Size, typename Predicate>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size,
Predicate pred)
{
// Cleaning
std::copy(first, last, expected_first);
std::copy(first, last, out_first);
// Run remove_if
OutputIterator i = remove_if(expected_first, expected_last, pred);
OutputIterator k = remove_if(exec, out_first, out_last, pred);
EXPECT_TRUE(std::distance(expected_first, i) == std::distance(out_first, k),
"wrong return value from remove_if");
EXPECT_EQ_N(expected_first, out_first, std::distance(expected_first, i), "wrong remove_if effect");
}
};
template <typename T, typename Predicate, typename Convert>
void
test(T trash, const T& value, Predicate pred, Convert convert)
{
const std::size_t max_size = 100000;
Sequence<T> out(max_size, [trash](size_t) { return trash; });
Sequence<T> expected(max_size, [trash](size_t) { return trash; });
for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<T> data(n, [&](size_t k) -> T { return convert(k); });
invoke_on_all_policies(run_remove(), data.begin(), data.end(), out.begin(), out.begin() + n, expected.begin(),
expected.begin() + n, n, value);
invoke_on_all_policies(run_remove_if(), data.begin(), data.end(), out.begin(), out.begin() + n,
expected.begin(), expected.begin() + n, n, pred);
}
}
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
invoke_if(exec, [&]() { remove_if(exec, iter, iter, non_const(is_even)); });
}
};
int32_t
main()
{
#if !__PSTL_ICC_18_TEST_EARLY_EXIT_MONOTONIC_RELEASE_BROKEN
test<int32_t>(666, 42, [](int32_t val) { return true; }, [](size_t j) { return j; });
#endif
test<int32_t>(666, 2001, [](const int32_t& val) { return val != 2001; },
[](size_t j) { return ((j + 1) % 5 & 2) != 0 ? 2001 : -1 - int32_t(j); });
test<float64_t>(-666.0, 8.5, [](const float64_t& val) { return val != 8.5; },
[](size_t j) { return ((j + 1) % 7 & 2) != 0 ? 8.5 : float64_t(j % 32 + j); });
#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN
test<Number>(Number(-666, OddTag()), Number(42, OddTag()), IsMultiple(3, OddTag()),
[](int32_t j) { return Number(j, OddTag()); });
#endif
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,88 @@
// -*- C++ -*-
//===-- test_remove_copy.cpp ----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for remove_copy
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct run_remove_copy
{
template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename T>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n,
const T& value, T trash)
{
// Cleaning
std::fill_n(expected_first, n, trash);
std::fill_n(out_first, n, trash);
// Run copy_if
auto i = remove_copy(first, last, expected_first, value);
auto k = remove_copy(exec, first, last, out_first, value);
EXPECT_EQ_N(expected_first, out_first, n, "wrong remove_copy effect");
for (size_t j = 0; j < GuardSize; ++j)
{
++k;
}
EXPECT_TRUE(out_last == k, "wrong return value from remove_copy");
}
};
template <typename T, typename Convert>
void
test(T trash, const T& value, Convert convert, bool check_weakness = true)
{
// Try sequences of various lengths.
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
// count is number of output elements, plus a handful
// more for sake of detecting buffer overruns.
size_t count = GuardSize;
Sequence<T> in(n, [&](size_t k) -> T {
T x = convert(n ^ k);
count += !(x == value) ? 1 : 0;
return x;
});
using namespace std;
Sequence<T> out(count, [=](size_t) { return trash; });
Sequence<T> expected(count, [=](size_t) { return trash; });
if (check_weakness)
{
auto expected_result = remove_copy(in.cfbegin(), in.cfend(), expected.begin(), value);
size_t m = expected_result - expected.begin();
EXPECT_TRUE(n / 4 <= m && m <= 3 * (n + 1) / 4, "weak test for remove_copy");
}
invoke_on_all_policies(run_remove_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(),
expected.end(), count, value, trash);
invoke_on_all_policies(run_remove_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(),
expected.end(), count, value, trash);
}
}
int32_t
main()
{
test<float64_t>(-666.0, 8.5, [](size_t j) { return ((j + 1) % 7 & 2) != 0 ? 8.5 : float64_t(j % 32 + j); });
test<int32_t>(-666, 42, [](size_t j) { return ((j + 1) % 5 & 2) != 0 ? 42 : -1 - int32_t(j); });
test<Number>(Number(42, OddTag()), Number(2001, OddTag()),
[](int32_t j) { return ((j + 1) % 3 & 2) != 0 ? Number(2001, OddTag()) : Number(j, OddTag()); });
std::cout << done() << std::endl;
return 0;
}

158
pstl/test/test_replace.cpp Normal file
View File

@ -0,0 +1,158 @@
// -*- C++ -*-
//===-- test_replace.cpp --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
// This class is needed to check the self-copying
struct copy_int
{
int32_t value;
int32_t copied_times = 0;
explicit copy_int(int32_t val = 0) { value = val; }
copy_int&
operator=(const copy_int& other)
{
if (&other == this)
copied_times++;
else
{
value = other.value;
copied_times = other.copied_times;
}
return *this;
}
bool
operator==(const copy_int& other) const
{
return (value == other.value);
}
};
template <typename Iterator>
struct test_one_policy
{
std::size_t len;
Iterator data_b;
Iterator data_e;
test_one_policy(Iterator data_, std::size_t len_)
{
len = len_;
data_b = data_;
data_e = std::next(data_b, len);
}
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename T, typename Predicate>
void
operator()(ExecutionPolicy&& exec, Iterator1 expected_b, Iterator1 expected_e, Iterator2 actual_b,
Iterator2 actual_e, Predicate pred, const T& value, const T& old_value)
{
using namespace std;
copy(data_b, data_e, expected_b);
copy(data_b, data_e, actual_b);
replace(expected_b, expected_e, old_value, value);
replace(exec, actual_b, actual_e, old_value, value);
EXPECT_TRUE((check<T, Iterator2>(actual_b, actual_e)), "wrong result of self assignment check");
EXPECT_TRUE(equal(expected_b, expected_e, actual_b), "wrong result of replace");
copy(data_b, data_e, expected_b);
copy(data_b, data_e, actual_b);
replace_if(expected_b, expected_e, pred, value);
replace_if(exec, actual_b, actual_e, pred, value);
EXPECT_TRUE(equal(expected_b, expected_e, actual_b), "wrong result of replace_if");
}
template <typename T, typename Iterator1>
bool
check(Iterator1 b, Iterator1 e)
{
return true;
}
template <typename T, typename Iterator1>
typename std::enable_if<std::is_same<T, copy_int>::value, bool>::type_t
check(Iterator1 b, Iterator1 e)
{
return std::all_of(b, e, [](const copy_int& elem) { return elem.copied_times == 0; });
}
};
template <typename T1, typename T2, typename Pred>
void
test(Pred pred)
{
typedef typename Sequence<T2>::iterator iterator_type;
const std::size_t max_len = 100000;
const T1 value = T1(0);
const T1 new_value = T1(666);
Sequence<T2> expected(max_len);
Sequence<T2> actual(max_len);
Sequence<T2> data(max_len, [&value](std::size_t i) {
if (i % 3 == 2)
{
return T1(i);
}
else
{
return value;
}
});
for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len))
{
test_one_policy<iterator_type> temp(data.begin(), len);
invoke_on_all_policies(temp, expected.begin(), expected.begin() + len, actual.begin(), actual.begin() + len,
pred, new_value, value);
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
invoke_if(exec, [&]() { replace_if(exec, iter, iter, non_const(is_even), T(0)); });
}
};
int32_t
main()
{
test<int32_t, float32_t>(__pstl::internal::equal_value<int32_t>(666));
test<uint16_t, uint8_t>([](const uint16_t& elem) { return elem % 3 < 2; });
test<float64_t, int64_t>([](const float64_t& elem) { return elem * elem - 3.5 * elem > 10; });
test<copy_int, copy_int>([](const copy_int& val) { return val.value / 5 > 2; });
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,103 @@
// -*- C++ -*-
//===-- test_replace_copy.cpp ---------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for replace_copy and replace_copy_if
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_replace_copy
{
template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename Predicate, typename T>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n,
Predicate pred, const T& old_value, const T& new_value, T trash)
{
// Cleaning
std::fill_n(expected_first, n, trash);
std::fill_n(out_first, n, trash);
// Run replace_copy
auto i = std::replace_copy(first, last, expected_first, old_value, new_value);
auto k = std::replace_copy(exec, first, last, out_first, old_value, new_value);
EXPECT_EQ_N(expected_first, out_first, n, "wrong replace_copy effect");
EXPECT_TRUE(out_last == k, "wrong return value from replace_copy");
// Cleaning
std::fill_n(expected_first, n, trash);
std::fill_n(out_first, n, trash);
// Run replace_copy_if
i = replace_copy_if(first, last, expected_first, pred, new_value);
k = replace_copy_if(exec, first, last, out_first, pred, new_value);
EXPECT_EQ_N(expected_first, out_first, n, "wrong replace_copy_if effect");
EXPECT_TRUE(out_last == k, "wrong return value from replace_copy_if");
}
};
template <typename T, typename Convert, typename Predicate>
void
test(T trash, const T& old_value, const T& new_value, Predicate pred, Convert convert)
{
// Try sequences of various lengths.
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<T> in(n, [&](size_t k) -> T { return convert(n ^ k); });
Sequence<T> out(n, [=](size_t) { return trash; });
Sequence<T> expected(n, [=](size_t) { return trash; });
invoke_on_all_policies(test_replace_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(),
expected.end(), out.size(), pred, old_value, new_value, trash);
invoke_on_all_policies(test_replace_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(),
expected.end(), out.size(), pred, old_value, new_value, trash);
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename InputIterator, typename OutputInterator>
void
operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter)
{
auto is_even = [&](float64_t v) {
uint32_t i = (uint32_t)v;
return i % 2 == 0;
};
invoke_if(exec, [&]() { replace_copy_if(exec, input_iter, input_iter, out_iter, non_const(is_even), T(0)); });
}
};
int32_t
main()
{
test<float64_t>(-666.0, 8.5, 0.33, [](const float64_t& x) { return x * x <= 1024; },
[](size_t j) { return ((j + 1) % 7 & 2) != 0 ? 8.5 : float64_t(j % 32 + j); });
test<int32_t>(-666, 42, 99, [](const int32_t& x) { return x != 42; },
[](size_t j) { return ((j + 1) % 5 & 2) != 0 ? 42 : -1 - int32_t(j); });
#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN
test<Number>(Number(42, OddTag()), Number(2001, OddTag()), Number(2017, OddTag()), IsMultiple(3, OddTag()),
[](int32_t j) { return ((j + 1) % 3 & 2) != 0 ? Number(2001, OddTag()) : Number(j, OddTag()); });
#endif
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

103
pstl/test/test_reverse.cpp Normal file
View File

@ -0,0 +1,103 @@
// -*- C++ -*-
//===-- test_reverse.cpp --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include <iterator>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_one_policy
{
#if __PSTL_ICC_18_VC141_TEST_SIMD_LAMBDA_RELEASE_BROKEN || __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN // dummy specialization by policy type, in case of broken configuration
template <typename Iterator1, typename Iterator2>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::unsequenced_policy, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b,
Iterator2 actual_e)
{
}
template <typename Iterator1, typename Iterator2>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b,
Iterator2 actual_e)
{
}
#endif
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2>
typename std::enable_if<!is_same_iterator_category<Iterator1, std::forward_iterator_tag>::value>::type
operator()(ExecutionPolicy&& exec, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, Iterator2 actual_e)
{
using namespace std;
copy(data_b, data_e, actual_b);
reverse(exec, actual_b, actual_e);
bool check = equal(data_b, data_e, reverse_iterator<Iterator2>(actual_e));
EXPECT_TRUE(check, "wrong result of reverse");
}
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2>
typename std::enable_if<is_same_iterator_category<Iterator1, std::forward_iterator_tag>::value>::type
operator()(ExecutionPolicy&& exec, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, Iterator2 actual_e)
{
}
};
template <typename T>
void
test()
{
const std::size_t max_len = 100000;
Sequence<T> actual(max_len);
Sequence<T> data(max_len, [](std::size_t i) { return T(i); });
for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len))
{
invoke_on_all_policies(test_one_policy(), data.begin(), data.begin() + len, actual.begin(),
actual.begin() + len);
}
}
template <typename T>
struct wrapper
{
T t;
wrapper() {}
explicit wrapper(T t_) : t(t_) {}
bool
operator==(const wrapper<T>& a) const
{
return t == a.t;
}
};
int32_t
main()
{
test<int32_t>();
test<uint16_t>();
test<float64_t>();
#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN
test<wrapper<float64_t>>();
#endif
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,132 @@
// -*- C++ -*-
//===-- test_reverse_copy.cpp ---------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include <iterator>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename T>
struct wrapper
{
T t;
wrapper() {}
explicit wrapper(T t_) : t(t_) {}
wrapper&
operator=(const T& t_)
{
t = t_;
return *this;
}
bool
operator==(const wrapper& t_) const
{
return t == t_.t;
}
};
template <typename T1, typename T2>
bool
eq(const wrapper<T1>& a, const wrapper<T2>& b)
{
return a.t == b.t;
}
template <typename T1, typename T2>
bool
eq(const T1& a, const T2& b)
{
return a == b;
}
// we need to save state here, because we need to test with different types of iterators
// due to the caller invoke_on_all_policies does forcing modification passed iterator type to cover additional usage cases.
template <typename Iterator>
struct test_one_policy
{
Iterator data_b;
Iterator data_e;
test_one_policy(Iterator b, Iterator e) : data_b(b), data_e(e) {}
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN // dummy specialization by policy type, in case of broken configuration
template <typename Iterator1>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::unsequenced_policy, Iterator1 actual_b, Iterator1 actual_e)
{
}
template <typename Iterator1>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 actual_b, Iterator1 actual_e)
{
}
#endif
template <typename ExecutionPolicy, typename Iterator1>
void
operator()(ExecutionPolicy&& exec, Iterator1 actual_b, Iterator1 actual_e)
{
using namespace std;
using T = typename iterator_traits<Iterator1>::value_type;
using DifferenceType = typename iterator_traits<Iterator1>::difference_type;
fill(actual_b, actual_e, T(-123));
Iterator1 actual_return = reverse_copy(exec, data_b, data_e, actual_b);
EXPECT_TRUE(actual_return == actual_e, "wrong result of reverse_copy");
const auto n = std::distance(data_b, data_e);
Sequence<T> res(n);
std::copy(std::reverse_iterator<Iterator>(data_e), std::reverse_iterator<Iterator>(data_b), res.begin());
EXPECT_EQ_N(res.begin(), actual_b, n, "wrong effect of reverse_copy");
}
};
template <typename T1, typename T2>
void
test()
{
typedef typename Sequence<T1>::iterator iterator_type;
typedef typename Sequence<T1>::const_bidirectional_iterator cbi_iterator_type;
const std::size_t max_len = 100000;
Sequence<T2> actual(max_len);
Sequence<T1> data(max_len, [](std::size_t i) { return T1(i); });
for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len))
{
invoke_on_all_policies(test_one_policy<iterator_type>(data.begin(), data.begin() + len), actual.begin(),
actual.begin() + len);
invoke_on_all_policies(test_one_policy<cbi_iterator_type>(data.cbibegin(), std::next(data.cbibegin(), len)),
actual.begin(), actual.begin() + len);
}
}
int32_t
main()
{
// clang-3.8 fails to correctly auto vectorize the loop in some cases of different types of container's elements,
// for example: int32_t and int8_t. This issue isn't detected for clang-3.9 and newer versions.
test<int16_t, int8_t>();
test<uint16_t, float32_t>();
test<float64_t, int64_t>();
test<wrapper<float64_t>, wrapper<float64_t>>();
std::cout << done() << std::endl;
return 0;
}

172
pstl/test/test_rotate.cpp Normal file
View File

@ -0,0 +1,172 @@
// -*- C++ -*-
//===-- test_rotate.cpp ---------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include <iterator>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename T>
struct wrapper
{
T t;
int move_count;
explicit wrapper(T t_) : t(t_), move_count(0) {}
wrapper&
operator=(const T& t_)
{
t = t_;
return *this;
}
wrapper(const wrapper<T>& a) : move_count(0) { t = a.t; }
wrapper<T>&
operator=(wrapper<T>& a)
{
t = a.t;
return *this;
}
wrapper<T>&
operator=(wrapper<T>&& a)
{
t = a.t;
move_count += 1;
return *this;
}
};
template <typename T>
struct compare
{
bool
operator()(const T& a, const T& b)
{
return a == b;
}
};
template <typename T>
struct compare<wrapper<T>>
{
bool
operator()(const wrapper<T>& a, const wrapper<T>& b)
{
return a.t == b.t;
}
};
#include <typeinfo>
struct test_one_policy
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN // dummy specializations to skip testing in case of broken configuration
template <typename Iterator, typename Size>
void
operator()(pstl::execution::unsequenced_policy, Iterator data_b, Iterator data_e, Iterator actual_b,
Iterator actual_e, Size shift)
{
}
template <typename Iterator, typename Size>
void
operator()(pstl::execution::parallel_unsequenced_policy, Iterator data_b, Iterator data_e, Iterator actual_b,
Iterator actual_e, Size shift)
{
}
#endif
template <typename ExecutionPolicy, typename Iterator, typename Size>
void
operator()(ExecutionPolicy&& exec, Iterator data_b, Iterator data_e, Iterator actual_b, Iterator actual_e,
Size shift)
{
using namespace std;
using T = typename iterator_traits<Iterator>::value_type;
Iterator actual_m = std::next(actual_b, shift);
copy(data_b, data_e, actual_b);
Iterator actual_return = rotate(exec, actual_b, actual_m, actual_e);
EXPECT_TRUE(actual_return == std::next(actual_b, std::distance(actual_m, actual_e)), "wrong result of rotate");
auto comparator = compare<T>();
bool check = std::equal(actual_return, actual_e, data_b, comparator);
check = check && std::equal(actual_b, actual_return, std::next(data_b, shift), comparator);
EXPECT_TRUE(check, "wrong effect of rotate");
EXPECT_TRUE(check_move(exec, actual_b, actual_e, shift), "wrong move test of rotate");
}
template <typename ExecutionPolicy, typename Iterator, typename Size>
typename std::enable_if<
is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value &&
!std::is_same<ExecutionPolicy, pstl::execution::sequenced_policy>::value &&
std::is_same<typename std::iterator_traits<Iterator>::value_type, wrapper<float32_t>>::value,
bool>::type
check_move(ExecutionPolicy&& exec, Iterator b, Iterator e, Size shift)
{
bool result = all_of(b, e, [](wrapper<float32_t>& a) {
bool temp = a.move_count > 0;
a.move_count = 0;
return temp;
});
return shift == 0 || result;
}
template <typename ExecutionPolicy, typename Iterator, typename Size>
typename std::enable_if<
!(is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value &&
!std::is_same<ExecutionPolicy, pstl::execution::sequenced_policy>::value &&
std::is_same<typename std::iterator_traits<Iterator>::value_type, wrapper<float32_t>>::value),
bool>::type
check_move(ExecutionPolicy&& exec, Iterator b, Iterator e, Size shift)
{
return true;
}
};
template <typename T>
void
test()
{
const int32_t max_len = 100000;
Sequence<T> actual(max_len, [](std::size_t i) { return T(i); });
Sequence<T> data(max_len, [](std::size_t i) { return T(i); });
for (int32_t len = 0; len < max_len; len = len <= 16 ? len + 1 : int32_t(3.1415 * len))
{
int32_t shifts[] = {0, 1, 2, len / 3, (2 * len) / 3, len - 1};
for (auto shift : shifts)
{
if (shift >= 0 && shift < len)
{
invoke_on_all_policies(test_one_policy(), data.begin(), data.begin() + len, actual.begin(),
actual.begin() + len, shift);
}
}
}
}
int32_t
main()
{
test<int32_t>();
test<wrapper<float64_t>>();
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,145 @@
// -*- C++ -*-
//===-- test_rotate_copy.cpp ----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include <iterator>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename T>
struct wrapper;
template <typename T>
bool
compare(const wrapper<T>& a, const wrapper<T>& b)
{
return a.t == b.t;
}
template <typename T>
bool
compare(const T& a, const T& b)
{
return a == b;
}
template <typename T>
struct wrapper
{
explicit wrapper(T t_) : t(t_) {}
wrapper&
operator=(const T& t_)
{
t = t_;
return *this;
}
friend bool
compare<T>(const wrapper<T>& a, const wrapper<T>& b);
private:
T t;
};
template <typename T, typename It1, typename It2>
struct comparator
{
using T1 = typename std::iterator_traits<It1>::value_type;
using T2 = typename std::iterator_traits<It2>::value_type;
bool
operator()(T1 a, T2 b)
{
T temp = a;
return compare(temp, b);
}
};
struct test_one_policy
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN // dummy specialization by policy type, in case of broken configuration
template <typename Iterator1, typename Iterator2>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::unsequenced_policy, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b,
Iterator2 actual_e, std::size_t shift)
{
}
template <typename Iterator1, typename Iterator2>
typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type
operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b,
Iterator2 actual_e, std::size_t shift)
{
}
#endif
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2>
void
operator()(ExecutionPolicy&& exec, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, Iterator2 actual_e,
std::size_t shift)
{
using namespace std;
using T = typename iterator_traits<Iterator2>::value_type;
Iterator1 data_m = std::next(data_b, shift);
fill(actual_b, actual_e, T(-123));
Iterator2 actual_return = rotate_copy(exec, data_b, data_m, data_e, actual_b);
EXPECT_TRUE(actual_return == actual_e, "wrong result of rotate_copy");
auto comparer = comparator<T, Iterator1, Iterator2>();
bool check = std::equal(data_m, data_e, actual_b, comparer);
check = check && std::equal(data_b, data_m, std::next(actual_b, std::distance(data_m, data_e)), comparer);
EXPECT_TRUE(check, "wrong effect of rotate_copy");
}
};
template <typename T1, typename T2>
void
test()
{
const std::size_t max_len = 100000;
Sequence<T2> actual(max_len, [](std::size_t i) { return T1(i); });
Sequence<T1> data(max_len, [](std::size_t i) { return T1(i); });
for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len))
{
std::size_t shifts[] = {0, 1, 2, len / 3, (2 * len) / 3, len - 1};
for (std::size_t shift : shifts)
{
if (shift > 0 && shift < len)
{
invoke_on_all_policies(test_one_policy(), data.begin(), data.begin() + len, actual.begin(),
actual.begin() + len, shift);
invoke_on_all_policies(test_one_policy(), data.cbegin(), data.cbegin() + len, actual.begin(),
actual.begin() + len, shift);
}
}
}
}
int32_t
main()
{
test<int32_t, int8_t>();
test<uint16_t, float32_t>();
test<float64_t, int64_t>();
test<wrapper<float64_t>, wrapper<float64_t>>();
std::cout << done() << std::endl;
return 0;
}

197
pstl/test/test_scan.cpp Normal file
View File

@ -0,0 +1,197 @@
// -*- C++ -*-
//===-- test_scan.cpp -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl/execution"
#include "pstl/numeric"
#include "utils.h"
#include "pstl_test_config.h"
using namespace TestUtils;
// We provide the no execution policy versions of the exclusive_scan and inclusive_scan due checking correctness result of the versions with execution policies.
//TODO: to add a macro for availability of ver implementations
template <class InputIterator, class OutputIterator, class T>
OutputIterator
exclusive_scan_serial(InputIterator first, InputIterator last, OutputIterator result, T init)
{
for (; first != last; ++first, ++result)
{
*result = init;
init = init + *first;
}
return result;
}
template <class InputIterator, class OutputIterator, class T, class BinaryOperation>
OutputIterator
exclusive_scan_serial(InputIterator first, InputIterator last, OutputIterator result, T init, BinaryOperation binary_op)
{
for (; first != last; ++first, ++result)
{
*result = init;
init = binary_op(init, *first);
}
return result;
}
// Note: N4582 is missing the ", class T". Issue was reported 2016-Apr-11 to cxxeditor@gmail.com
template <class InputIterator, class OutputIterator, class BinaryOperation, class T>
OutputIterator
inclusive_scan_serial(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op, T init)
{
for (; first != last; ++first, ++result)
{
init = binary_op(init, *first);
*result = init;
}
return result;
}
template <class InputIterator, class OutputIterator, class BinaryOperation>
OutputIterator
inclusive_scan_serial(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op)
{
if (first != last)
{
auto tmp = *first;
*result = tmp;
return inclusive_scan_serial(++first, last, ++result, binary_op, tmp);
}
else
{
return result;
}
}
template <class InputIterator, class OutputIterator>
OutputIterator
inclusive_scan_serial(InputIterator first, InputIterator last, OutputIterator result)
{
typedef typename std::iterator_traits<InputIterator>::value_type input_type;
return inclusive_scan_serial(first, last, result, std::plus<input_type>());
}
// Most of the framework required for testing inclusive and exclusive scan is identical,
// so the tests for both are in this file. Which is being tested is controlled by the global
// flag inclusive, which is set to each alternative by main().
static bool inclusive;
template <typename Iterator, typename Size, typename T>
void
check_and_reset(Iterator expected_first, Iterator out_first, Size n, T trash)
{
EXPECT_EQ_N(expected_first, out_first, n,
inclusive ? "wrong result from inclusive_scan" : "wrong result from exclusive_scan");
std::fill_n(out_first, n, trash);
}
struct test_scan_with_plus
{
template <typename Policy, typename Iterator1, typename Iterator2, typename Iterator3, typename Size, typename T>
void
operator()(Policy&& exec, Iterator1 in_first, Iterator1 in_last, Iterator2 out_first, Iterator2 out_last,
Iterator3 expected_first, Iterator3 expected_last, Size n, T init, T trash)
{
using namespace std;
auto orr1 = inclusive ? inclusive_scan_serial(in_first, in_last, expected_first)
: exclusive_scan_serial(in_first, in_last, expected_first, init);
auto orr = inclusive ? inclusive_scan(exec, in_first, in_last, out_first)
: exclusive_scan(exec, in_first, in_last, out_first, init);
EXPECT_TRUE(out_last == orr,
inclusive ? "inclusive_scan returned wrong iterator" : "exclusive_scan returned wrong iterator");
check_and_reset(expected_first, out_first, n, trash);
fill(out_first, out_last, trash);
}
};
template <typename T, typename Convert>
void
test_with_plus(T init, T trash, Convert convert)
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<T> in(n, convert);
Sequence<T> expected(in);
Sequence<T> out(n, [&](int32_t) { return trash; });
invoke_on_all_policies(test_scan_with_plus(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(),
expected.end(), in.size(), init, trash);
invoke_on_all_policies(test_scan_with_plus(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(),
expected.end(), in.size(), init, trash);
}
}
struct test_scan_with_binary_op
{
template <typename Policy, typename Iterator1, typename Iterator2, typename Iterator3, typename Size, typename T,
typename BinaryOp>
typename std::enable_if<!TestUtils::isReverse<Iterator1>::value, void>::type
operator()(Policy&& exec, Iterator1 in_first, Iterator1 in_last, Iterator2 out_first, Iterator2 out_last,
Iterator3 expected_first, Iterator3 expected_last, Size n, T init, BinaryOp binary_op, T trash)
{
using namespace std;
auto orr1 = inclusive ? inclusive_scan_serial(in_first, in_last, expected_first, binary_op, init)
: exclusive_scan_serial(in_first, in_last, expected_first, init, binary_op);
auto orr = inclusive ? inclusive_scan(exec, in_first, in_last, out_first, binary_op, init)
: exclusive_scan(exec, in_first, in_last, out_first, init, binary_op);
EXPECT_TRUE(out_last == orr, "scan returned wrong iterator");
check_and_reset(expected_first, out_first, n, trash);
}
template <typename Policy, typename Iterator1, typename Iterator2, typename Iterator3, typename Size, typename T,
typename BinaryOp>
typename std::enable_if<TestUtils::isReverse<Iterator1>::value, void>::type
operator()(Policy&& exec, Iterator1 in_first, Iterator1 in_last, Iterator2 out_first, Iterator2 out_last,
Iterator3 expected_first, Iterator3 expected_last, Size n, T init, BinaryOp binary_op, T trash)
{
}
};
template <typename In, typename Out, typename BinaryOp>
void
test_matrix(Out init, BinaryOp binary_op, Out trash)
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<In> in(n, [](size_t k) { return In(k, k + 1); });
Sequence<Out> out(n, [&](size_t) { return trash; });
Sequence<Out> expected(n, [&](size_t) { return trash; });
invoke_on_all_policies(test_scan_with_binary_op(), in.begin(), in.end(), out.begin(), out.end(),
expected.begin(), expected.end(), in.size(), init, binary_op, trash);
invoke_on_all_policies(test_scan_with_binary_op(), in.cbegin(), in.cend(), out.begin(), out.end(),
expected.begin(), expected.end(), in.size(), init, binary_op, trash);
}
}
int32_t
main()
{
for (int32_t mode = 0; mode < 2; ++mode)
{
inclusive = mode != 0;
#if !__PSTL_ICC_19_TEST_SIMD_UDS_WINDOWS_RELEASE_BROKEN
// Test with highly restricted type and associative but not commutative operation
test_matrix<Matrix2x2<int32_t>, Matrix2x2<int32_t>>(Matrix2x2<int32_t>(), multiply_matrix<int32_t>,
Matrix2x2<int32_t>(-666, 666));
#endif
// Since the implict "+" forms of the scan delegate to the generic forms,
// there's little point in using a highly restricted type, so just use double.
test_with_plus<float64_t>(inclusive ? 0.0 : -1.0, -666.0,
[](uint32_t k) { return float64_t((k % 991 + 1) ^ (k % 997 + 2)); });
}
std::cout << done() << std::endl;
return 0;
}

107
pstl/test/test_search_n.cpp Normal file
View File

@ -0,0 +1,107 @@
// -*- C++ -*-
//===-- test_search_n.cpp -------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_one_policy
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename Iterator, typename Size, typename T, typename Predicate>
void
operator()(pstl::execution::unsequenced_policy, Iterator b, Iterator e, Size count, const T& value, Predicate pred)
{
}
template <typename Iterator, typename Size, typename T, typename Predicate>
void
operator()(pstl::execution::parallel_unsequenced_policy, Iterator b, Iterator e, Size count, const T& value,
Predicate pred)
{
}
#endif
template <typename ExecutionPolicy, typename Iterator, typename Size, typename T, typename Predicate>
void
operator()(ExecutionPolicy&& exec, Iterator b, Iterator e, Size count, const T& value, Predicate pred)
{
using namespace std;
auto expected = search_n(b, e, count, value, pred);
auto actual = search_n(exec, b, e, count, value);
EXPECT_TRUE(actual == expected, "wrong return result from search_n");
actual = search_n(exec, b, e, count, value, pred);
EXPECT_TRUE(actual == expected, "wrong return result from search_n with a predicate");
}
};
template <typename T>
void
test()
{
const std::size_t max_n1 = 100000;
const T value = T(1);
for (std::size_t n1 = 0; n1 <= max_n1; n1 = n1 <= 16 ? n1 + 1 : size_t(3.1415 * n1))
{
std::size_t sub_n[] = {0, 1, 3, n1, (n1 * 10) / 8};
std::size_t res[] = {0, 1, n1 / 2, n1};
for (auto n2 : sub_n)
{
// Some of standard libraries return "first" in this case. We return "last" according to the standard
if (n2 == 0)
{
continue;
}
for (auto r : res)
{
Sequence<T> in(n1, [n1](std::size_t k) { return T(0); });
std::size_t i = r, isub = 0;
for (; i < n1 & isub < n2; ++i, ++isub)
in[i] = value;
invoke_on_all_policies(test_one_policy(), in.begin(), in.begin() + n1, n2, value, std::equal_to<T>());
invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cbegin() + n1, n2, value, std::equal_to<T>());
}
}
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
invoke_if(exec, [&]() { search_n(exec, iter, iter, 0, T(0), non_const(std::equal_to<T>())); });
}
};
int32_t
main()
{
test<int32_t>();
test<uint16_t>();
test<float64_t>();
#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN
test<bool>();
#endif
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

161
pstl/test/test_set.cpp Normal file
View File

@ -0,0 +1,161 @@
// -*- C++ -*-
//===-- test_set.cpp ------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for partial_sort
#include <cmath>
#include <chrono>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename T>
struct Num
{
T val;
Num() : val{} {}
Num(const T& v) : val(v) {}
//for "includes" checks
template <typename T1>
bool
operator<(const Num<T1>& v1) const
{
return val < v1.val;
}
//The types Type1 and Type2 must be such that an object of type InputIt can be dereferenced and then implicitly converted to both of them
template <typename T1>
operator Num<T1>() const
{
return Num<T1>((T1)val);
}
friend bool
operator==(const Num& v1, const Num& v2)
{
return v1.val == v2.val;
}
};
struct test_one_policy
{
template <typename Policy, typename InputIterator1, typename InputIterator2, typename Compare>
typename std::enable_if<!TestUtils::isReverse<InputIterator1>::value, void>::type
operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
Compare comp)
{
using T1 = typename std::iterator_traits<InputIterator1>::value_type;
auto n1 = std::distance(first1, last1);
auto n2 = std::distance(first2, last2);
auto n = n1 + n2;
Sequence<T1> expect(n);
Sequence<T1> out(n);
//1. set_union
auto expect_res = std::set_union(first1, last1, first2, last2, expect.begin(), comp);
auto res = std::set_union(exec, first1, last1, first2, last2, out.begin(), comp);
EXPECT_TRUE(expect_res - expect.begin() == res - out.begin(), "wrong result for set_union");
EXPECT_EQ_N(expect.begin(), out.begin(), std::distance(out.begin(), res), "wrong set_union effect");
//2. set_intersection
expect_res = std::set_intersection(first1, last1, first2, last2, expect.begin(), comp);
res = std::set_intersection(exec, first1, last1, first2, last2, out.begin(), comp);
EXPECT_TRUE(expect_res - expect.begin() == res - out.begin(), "wrong result for set_intersection");
EXPECT_EQ_N(expect.begin(), out.begin(), std::distance(out.begin(), res), "wrong set_intersection effect");
//3. set_difference
expect_res = std::set_difference(first1, last1, first2, last2, expect.begin(), comp);
res = std::set_difference(exec, first1, last1, first2, last2, out.begin(), comp);
EXPECT_TRUE(expect_res - expect.begin() == res - out.begin(), "wrong result for set_difference");
EXPECT_EQ_N(expect.begin(), out.begin(), std::distance(out.begin(), res), "wrong set_difference effect");
//4. set_symmetric_difference
expect_res = std::set_symmetric_difference(first1, last1, first2, last2, expect.begin(), comp);
res = std::set_symmetric_difference(exec, first1, last1, first2, last2, out.begin(), comp);
EXPECT_TRUE(expect_res - expect.begin() == res - out.begin(), "wrong result for set_symmetric_difference");
EXPECT_EQ_N(expect.begin(), out.begin(), std::distance(out.begin(), res),
"wrong set_symmetric_difference effect");
}
template <typename Policy, typename InputIterator1, typename InputIterator2, typename Compare>
typename std::enable_if<TestUtils::isReverse<InputIterator1>::value, void>::type
operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
Compare comp)
{
}
};
template <typename T1, typename T2, typename Compare>
void
test_set(Compare compare)
{
const std::size_t n_max = 100000;
// The rand()%(2*n+1) encourages generation of some duplicates.
std::srand(4200);
for (std::size_t n = 0; n < n_max; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
for (std::size_t m = 0; m < n_max; m = m <= 16 ? m + 1 : size_t(2.71828 * m))
{
//prepare the input ranges
Sequence<T1> in1(n, [n](std::size_t k) { return rand() % (2 * k + 1); });
Sequence<T2> in2(m, [m](std::size_t k) { return (m % 2) * rand() + rand() % (k + 1); });
std::sort(in1.begin(), in1.end(), compare);
std::sort(in2.begin(), in2.end(), compare);
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.cbegin(), in2.cend(), compare);
}
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename InputIterator, typename OutputInterator>
void
operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter)
{
set_difference(exec, input_iter, input_iter, input_iter, input_iter, out_iter, non_const(std::less<T>()));
set_intersection(exec, input_iter, input_iter, input_iter, input_iter, out_iter, non_const(std::less<T>()));
set_symmetric_difference(exec, input_iter, input_iter, input_iter, input_iter, out_iter,
non_const(std::less<T>()));
set_union(exec, input_iter, input_iter, input_iter, input_iter, out_iter, non_const(std::less<T>()));
}
};
int32_t
main()
{
test_set<float64_t, float64_t>(__pstl::internal::pstl_less());
test_set<Num<int64_t>, Num<int32_t>>([](const Num<int64_t>& x, const Num<int32_t>& y) { return x < y; });
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

245
pstl/test/test_sort.cpp Normal file
View File

@ -0,0 +1,245 @@
// -*- C++ -*-
//===-- test_sort.cpp -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for sort and stable_sort
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
#define _CRT_SECURE_NO_WARNINGS
#include <atomic>
static bool Stable;
//! Number of extant keys
static std::atomic<int32_t> KeyCount;
//! One more than highest index in array to be sorted.
static uint32_t LastIndex;
//! Keeping Equal() static and a friend of ParanoidKey class (C++, paragraphs 3.5/7.1.1)
class ParanoidKey;
static bool
Equal(const ParanoidKey& x, const ParanoidKey& y);
//! A key to be sorted, with lots of checking.
class ParanoidKey
{
//! Value used by comparator
int32_t value;
//! Original position or special value (Empty or Dead)
int32_t index;
//! Special value used to mark object without a comparable value, e.g. after being moved from.
static const int32_t Empty = -1;
//! Special value used to mark destroyed objects.
static const int32_t Dead = -2;
// True if key object has comparable value
bool
isLive() const
{
return (uint32_t)(index) < LastIndex;
}
// True if key object has been constructed.
bool
isConstructed() const
{
return isLive() || index == Empty;
}
public:
ParanoidKey()
{
++KeyCount;
index = Empty;
value = Empty;
}
ParanoidKey(const ParanoidKey& k) : value(k.value), index(k.index)
{
EXPECT_TRUE(k.isLive(), "source for copy-constructor is dead");
++KeyCount;
}
~ParanoidKey()
{
EXPECT_TRUE(isConstructed(), "double destruction");
index = Dead;
--KeyCount;
}
ParanoidKey&
operator=(const ParanoidKey& k)
{
EXPECT_TRUE(k.isLive(), "source for copy-assignment is dead");
EXPECT_TRUE(isConstructed(), "destination for copy-assignment is dead");
value = k.value;
index = k.index;
return *this;
}
ParanoidKey(int32_t index, int32_t value, OddTag) : index(index), value(value) {}
ParanoidKey(ParanoidKey&& k) : value(k.value), index(k.index)
{
EXPECT_TRUE(k.isConstructed(), "source for move-construction is dead");
// std::stable_sort() fails in move semantics on paranoid test before VS2015
#if !defined(_MSC_VER) || _MSC_VER >= 1900
k.index = Empty;
#endif
++KeyCount;
}
ParanoidKey&
operator=(ParanoidKey&& k)
{
EXPECT_TRUE(k.isConstructed(), "source for move-assignment is dead");
EXPECT_TRUE(isConstructed(), "destination for move-assignment is dead");
value = k.value;
index = k.index;
// std::stable_sort() fails in move semantics on paranoid test before VS2015
#if !defined(_MSC_VER) || _MSC_VER >= 1900
k.index = Empty;
#endif
return *this;
}
friend class KeyCompare;
friend bool
Equal(const ParanoidKey& x, const ParanoidKey& y);
};
class KeyCompare
{
enum statusType
{
//! Special value used to mark defined object.
Live = 0xabcd,
//! Special value used to mark destroyed objects.
Dead = -1
} status;
public:
KeyCompare(OddTag) : status(Live) {}
~KeyCompare() { status = Dead; }
bool
operator()(const ParanoidKey& j, const ParanoidKey& k) const
{
EXPECT_TRUE(status == Live, "key comparison object not defined");
EXPECT_TRUE(j.isLive(), "first key to operator() is not live");
EXPECT_TRUE(k.isLive(), "second key to operator() is not live");
return j.value < k.value;
}
};
// Equal is equality comparison used for checking result of sort against expected result.
static bool
Equal(const ParanoidKey& x, const ParanoidKey& y)
{
return (x.value == y.value && !Stable) || (x.index == y.index);
}
static bool
Equal(float32_t x, float32_t y)
{
return x == y;
}
static bool
Equal(int32_t x, int32_t y)
{
return x == y;
}
struct test_sort_with_compare
{
template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename Compare>
typename std::enable_if<is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
void>::type
operator()(Policy&& exec, OutputIterator tmp_first, OutputIterator tmp_last, OutputIterator2 expected_first,
OutputIterator2 expected_last, InputIterator first, InputIterator last, Size n, Compare compare)
{
using namespace std;
copy_n(first, n, expected_first);
copy_n(first, n, tmp_first);
if (Stable)
std::stable_sort(expected_first + 1, expected_last - 1, compare);
else
std::sort(expected_first + 1, expected_last - 1, compare);
int32_t count0 = KeyCount;
if (Stable)
stable_sort(exec, tmp_first + 1, tmp_last - 1, compare);
else
sort(exec, tmp_first + 1, tmp_last - 1, compare);
for (size_t i = 0; i < n; ++i, ++expected_first, ++tmp_first)
{
// Check that expected[i] is equal to tmp[i]
EXPECT_TRUE(Equal(*expected_first, *tmp_first), "bad sort");
}
int32_t count1 = KeyCount;
EXPECT_EQ(count0, count1, "key cleanup error");
}
template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename Compare>
typename std::enable_if<!is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
void>::type
operator()(Policy&& exec, OutputIterator tmp_first, OutputIterator tmp_last, OutputIterator2 expected_first,
OutputIterator2 expected_last, InputIterator first, InputIterator last, Size n, Compare compare)
{
}
};
template <typename T, typename Compare, typename Convert>
void
test_sort(Compare compare, Convert convert)
{
for (size_t n = 0; n < 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
LastIndex = n + 2;
// The rand()%(2*n+1) encourages generation of some duplicates.
// Sequence is padded with an extra element at front and back, to detect overwrite bugs.
Sequence<T> in(n + 2, [=](size_t k) { return convert(k, rand() % (2 * n + 1)); });
Sequence<T> expected(in);
Sequence<T> tmp(in);
invoke_on_all_policies(test_sort_with_compare(), tmp.begin(), tmp.end(), expected.begin(), expected.end(),
in.begin(), in.end(), in.size(), compare);
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
sort(exec, iter, iter, non_const(std::less<T>()));
stable_sort(exec, iter, iter, non_const(std::less<T>()));
}
};
int32_t
main()
{
std::srand(42);
for (int32_t kind = 0; kind < 2; ++kind)
{
Stable = kind != 0;
test_sort<ParanoidKey>(KeyCompare(OddTag()),
[](size_t k, size_t val) { return ParanoidKey(k, val, OddTag()); });
test_sort<float32_t>([](float32_t x, float32_t y) { return x < y; },
[](size_t, size_t val) { return float32_t(val); });
test_sort<int32_t>(
[](int32_t x, int32_t y) { return x > y; }, // Reversed so accidental use of < will be detected.
[](size_t, size_t val) { return int32_t(val); });
}
test_algo_basic_single<int32_t>(run_for_rnd<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,132 @@
// -*- C++ -*-
//===-- test_swap_ranges.cpp ----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl_test_config.h"
#include <iterator>
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename T>
struct wrapper
{
T t;
std::size_t number_of_swaps = 0;
wrapper() {}
explicit wrapper(T t_) : t(t_) {}
template <typename U>
void
operator=(const U& b)
{
t = b;
}
bool
operator==(const wrapper<T>& a) const
{
return t == a.t;
}
};
template <typename T>
void
swap(wrapper<T>& a, wrapper<T>& b)
{
std::swap(a.t, b.t);
a.number_of_swaps++;
b.number_of_swaps++;
}
template <typename T>
struct check_swap
{
bool
operator()(T& a)
{
return true;
}
};
template <typename T>
struct check_swap<wrapper<T>>
{
bool
operator()(wrapper<T>& a)
{
bool temp = (a.number_of_swaps == 1);
a.number_of_swaps = 0;
return temp;
}
};
struct test_one_policy
{
template <typename ExecutionPolicy, typename Iterator1, typename Iterator2>
void
operator()(ExecutionPolicy&& exec, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, Iterator2 actual_e)
{
using namespace std;
using T_ref = typename iterator_traits<Iterator1>::reference;
using T = typename iterator_traits<Iterator1>::value_type;
iota(data_b, data_e, 0);
iota(actual_b, actual_e, std::distance(data_b, data_e));
Iterator2 actual_return = swap_ranges(exec, data_b, data_e, actual_b);
bool check_return = (actual_return == actual_e);
EXPECT_TRUE(check_return, "wrong result of swap_ranges");
if (check_return)
{
std::size_t i = 0;
bool check = all_of(actual_b, actual_e, [&i](T_ref a) { return a == T(i++); }) &&
all_of(data_b, data_e, [&i](T_ref a) { return a == T(i++); });
EXPECT_TRUE(check, "wrong effect of swap_ranges");
if (check)
{
bool swap_check =
all_of(data_b, data_e, check_swap<T>()) && all_of(actual_b, actual_e, check_swap<T>());
EXPECT_TRUE(swap_check, "wrong effect of swap_ranges swap check");
}
}
}
};
template <typename T>
void
test()
{
const std::size_t max_len = 100000;
Sequence<T> data(max_len);
Sequence<T> actual(max_len);
for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len))
{
invoke_on_all_policies(test_one_policy(), data.begin(), data.begin() + len, actual.begin(),
actual.begin() + len);
}
}
int32_t
main()
{
test<wrapper<uint16_t>>();
test<wrapper<float64_t>>();
test<int32_t>();
test<float32_t>();
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,117 @@
// -*- C++ -*-
//===-- test_transform_binary.cpp -----------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename In1, typename In2, typename Out>
class TheOperation
{
Out val;
public:
TheOperation(Out v) : val(v) {}
Out
operator()(const In1& x, const In2& y) const
{
return Out(val + x - y);
}
};
template <typename InputIterator1, typename InputIterator2, typename OutputIterator>
void
check_and_reset(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator out_first)
{
typedef typename std::iterator_traits<OutputIterator>::value_type Out;
typename std::iterator_traits<OutputIterator>::difference_type k = 0;
for (; first1 != last1; ++first1, ++first2, ++out_first, ++k)
{
// check
Out expected = Out(1.5) + *first1 - *first2;
Out actual = *out_first;
if (std::is_floating_point<Out>::value)
{
EXPECT_TRUE((expected > actual ? expected - actual : actual - expected) < 1e7,
"wrong value in output sequence");
}
else
{
EXPECT_EQ(expected, actual, "wrong value in output sequence");
}
// reset
*out_first = k % 7 != 4 ? 7 * k - 5 : 0;
}
}
struct test_one_policy
{
template <typename Policy, typename InputIterator1, typename InputIterator2, typename OutputIterator,
typename BinaryOp>
void
operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
OutputIterator out_first, OutputIterator out_last, BinaryOp op)
{
auto orrr = std::transform(exec, first1, last1, first2, out_first, op);
check_and_reset(first1, last1, first2, out_first);
}
};
template <typename In1, typename In2, typename Out, typename Predicate>
void
test(Predicate pred)
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<In1> in1(n, [](size_t k) { return k % 5 != 1 ? 3 * k - 7 : 0; });
Sequence<In2> in2(n, [](size_t k) { return k % 7 != 2 ? 5 * k - 5 : 0; });
Sequence<Out> out(n, [](size_t k) { return -1; });
invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.begin(), in2.end(), out.begin(),
out.end(), pred);
invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cend(), in2.cbegin(), in2.cend(), out.begin(),
out.end(), pred);
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename InputIterator, typename OutputInterator>
void
operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter)
{
invoke_if(exec, [&]() {
InputIterator input_iter2 = input_iter;
transform(exec, input_iter, input_iter, input_iter2, out_iter, non_const(std::plus<T>()));
});
}
};
int32_t
main()
{
//const operator()
test<int32_t, int32_t, int32_t>(TheOperation<int32_t, int32_t, int32_t>(1));
test<float32_t, float32_t, float32_t>(TheOperation<float32_t, float32_t, float32_t>(1.5));
//non-const operator()
test<int32_t, float32_t, float32_t>(non_const(TheOperation<int32_t, float32_t, float32_t>(1.5)));
test<int64_t, float64_t, float32_t>(non_const(TheOperation<int64_t, float64_t, float32_t>(1.5)));
//lambda
test<int8_t, float64_t, int8_t>([](const int8_t& x, const float64_t& y) { return int8_t(int8_t(1.5) + x - y); });
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,134 @@
// -*- C++ -*-
//===-- test_transform_reduce.cpp -----------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for inner_product
#include "pstl/execution"
#include "pstl/numeric"
#include "utils.h"
using namespace TestUtils;
// Equal for all types
template <typename T>
static bool
Equal(T x, T y)
{
return x == y;
}
// Functor for xor-operation for modeling binary operations in inner_product
class XOR
{
public:
template <typename T>
T
operator()(const T& left, const T& right) const
{
return left ^ right;
}
};
// Model of User-defined class
class MyClass
{
public:
int32_t my_field;
MyClass() { my_field = 0; }
MyClass(int32_t in) { my_field = in; }
MyClass(const MyClass& in) { my_field = in.my_field; }
friend MyClass
operator+(const MyClass& x, const MyClass& y)
{
return MyClass(x.my_field + y.my_field);
}
friend MyClass
operator-(const MyClass& x)
{
return MyClass(-x.my_field);
}
friend MyClass operator*(const MyClass& x, const MyClass& y) { return MyClass(x.my_field * y.my_field); }
bool
operator==(const MyClass& in)
{
return my_field == in.my_field;
}
};
template <typename T>
void
CheckResults(const T& expected, const T& in)
{
EXPECT_TRUE(Equal(expected, in), "wrong result of transform_reduce");
}
// We need to check correctness only for "int" (for example) except cases
// if we have "floating-point type"-specialization
void
CheckResults(const float32_t& expected, const float32_t& in)
{
}
// Test for different types and operations with different iterators
struct test_transform_reduce
{
template <typename Policy, typename InputIterator1, typename InputIterator2, typename T, typename BinaryOperation1,
typename BinaryOperation2, typename UnaryOp>
void
operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
T init, BinaryOperation1 opB1, BinaryOperation2 opB2, UnaryOp opU)
{
auto expectedB = std::inner_product(first1, last1, first2, init, opB1, opB2);
auto expectedU = transform_reduce_serial(first1, last1, init, opB1, opU);
T resRA = std::transform_reduce(exec, first1, last1, first2, init, opB1, opB2);
CheckResults(expectedB, resRA);
resRA = std::transform_reduce(exec, first1, last1, init, opB1, opU);
CheckResults(expectedU, resRA);
}
};
template <typename T, typename BinaryOperation1, typename BinaryOperation2, typename UnaryOp, typename Initializer>
void
test_by_type(T init, BinaryOperation1 opB1, BinaryOperation2 opB2, UnaryOp opU, Initializer initObj)
{
std::size_t maxSize = 100000;
Sequence<T> in1(maxSize, initObj);
Sequence<T> in2(maxSize, initObj);
for (std::size_t n = 0; n < maxSize; n = n < 16 ? n + 1 : size_t(3.1415 * n))
{
invoke_on_all_policies(test_transform_reduce(), in1.begin(), in1.begin() + n, in2.begin(), in2.begin() + n,
init, opB1, opB2, opU);
invoke_on_all_policies(test_transform_reduce(), in1.cbegin(), in1.cbegin() + n, in2.cbegin(), in2.cbegin() + n,
init, opB1, opB2, opU);
}
}
int32_t
main()
{
test_by_type<int32_t>(42, std::plus<int32_t>(), std::multiplies<int32_t>(), std::negate<int32_t>(),
[](std::size_t a) -> int32_t { return int32_t(rand() % 1000); });
test_by_type<int64_t>(0, [](const int64_t& a, const int64_t& b) -> int64_t { return a | b; }, XOR(),
[](const int64_t& x) -> int64_t { return x * 2; },
[](std::size_t a) -> int64_t { return int64_t(rand() % 1000); });
test_by_type<float32_t>(1.0f, std::multiplies<float32_t>(),
[](const float32_t& a, const float32_t& b) -> float32_t { return a + b; },
[](const float32_t& x) -> float32_t { return x + 2; },
[](std::size_t a) -> float32_t { return rand() % 1000; });
test_by_type<MyClass>(MyClass(), std::plus<MyClass>(), std::multiplies<MyClass>(), std::negate<MyClass>(),
[](std::size_t a) -> MyClass { return MyClass(rand() % 1000); });
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,174 @@
// -*- C++ -*-
//===-- test_transform_scan.cpp -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl/execution"
#include "pstl/numeric"
#include "utils.h"
#include "pstl_test_config.h"
using namespace TestUtils;
// Most of the framework required for testing inclusive and exclusive transform-scans is identical,
// so the tests for both are in this file. Which is being tested is controlled by the global
// flag inclusive, which is set to each alternative by main().
static bool inclusive;
template <typename Iterator, typename Size, typename T>
void
check_and_reset(Iterator expected_first, Iterator out_first, Size n, T trash)
{
EXPECT_EQ_N(expected_first, out_first, n,
inclusive ? "wrong result from transform_inclusive_scan"
: "wrong result from transform_exclusive_scan");
std::fill_n(out_first, n, trash);
}
struct test_transform_scan
{
template <typename Policy, typename InputIterator, typename OutputIterator, typename Size, typename UnaryOp,
typename T, typename BinaryOp>
typename std::enable_if<!TestUtils::isReverse<InputIterator>::value, void>::type
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size n,
UnaryOp unary_op, T init, BinaryOp binary_op, T trash)
{
using namespace std;
auto orr1 = inclusive ? transform_inclusive_scan(pstl::execution::seq, first, last, expected_first, binary_op,
unary_op, init)
: transform_exclusive_scan(pstl::execution::seq, first, last, expected_first, init,
binary_op, unary_op);
auto orr2 = inclusive ? transform_inclusive_scan(exec, first, last, out_first, binary_op, unary_op, init)
: transform_exclusive_scan(exec, first, last, out_first, init, binary_op, unary_op);
EXPECT_TRUE(out_last == orr2, "transform...scan returned wrong iterator");
check_and_reset(expected_first, out_first, n, trash);
// Checks inclusive scan if init is not provided
if (inclusive && n > 0)
{
orr1 = transform_inclusive_scan(pstl::execution::seq, first, last, expected_first, binary_op, unary_op);
orr2 = transform_inclusive_scan(exec, first, last, out_first, binary_op, unary_op);
EXPECT_TRUE(out_last == orr2, "transform...scan returned wrong iterator");
check_and_reset(expected_first, out_first, n, trash);
}
}
template <typename Policy, typename InputIterator, typename OutputIterator, typename Size, typename UnaryOp,
typename T, typename BinaryOp>
typename std::enable_if<TestUtils::isReverse<InputIterator>::value, void>::type
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size n,
UnaryOp unary_op, T init, BinaryOp binary_op, T trash)
{
}
};
const uint32_t encryption_mask = 0x314;
template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename T,
typename BinaryOperation>
std::pair<OutputIterator, T>
transform_inclusive_scan_serial(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation unary_op,
T init, BinaryOperation binary_op) noexcept
{
for (; first != last; ++first, ++result)
{
init = binary_op(init, unary_op(*first));
*result = init;
}
return std::make_pair(result, init);
}
template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename T,
typename BinaryOperation>
std::pair<OutputIterator, T>
transform_exclusive_scan_serial(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation unary_op,
T init, BinaryOperation binary_op) noexcept
{
for (; first != last; ++first, ++result)
{
*result = init;
init = binary_op(init, unary_op(*first));
}
return std::make_pair(result, init);
}
template <typename In, typename Out, typename UnaryOp, typename BinaryOp>
void
test(UnaryOp unary_op, Out init, BinaryOp binary_op, Out trash)
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<In> in(n, [](size_t k) { return In(k ^ encryption_mask); });
Out tmp = init;
Sequence<Out> expected(n, [&](size_t k) -> Out {
if (inclusive)
{
tmp = binary_op(tmp, unary_op(in[k]));
return tmp;
}
else
{
Out val = tmp;
tmp = binary_op(tmp, unary_op(in[k]));
return val;
}
});
Sequence<Out> out(n, [&](size_t) { return trash; });
auto result =
inclusive
? transform_inclusive_scan_serial(in.cbegin(), in.cend(), out.fbegin(), unary_op, init, binary_op)
: transform_exclusive_scan_serial(in.cbegin(), in.cend(), out.fbegin(), unary_op, init, binary_op);
check_and_reset(expected.begin(), out.begin(), out.size(), trash);
invoke_on_all_policies(test_transform_scan(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(),
expected.end(), in.size(), unary_op, init, binary_op, trash);
invoke_on_all_policies(test_transform_scan(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(),
expected.end(), in.size(), unary_op, init, binary_op, trash);
}
}
template <typename In, typename Out, typename UnaryOp, typename BinaryOp>
void
test_matrix(UnaryOp unary_op, Out init, BinaryOp binary_op, Out trash)
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<In> in(n, [](size_t k) { return In(k, k + 1); });
Sequence<Out> out(n, [&](size_t) { return trash; });
Sequence<Out> expected(n, [&](size_t) { return trash; });
invoke_on_all_policies(test_transform_scan(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(),
expected.end(), in.size(), unary_op, init, binary_op, trash);
invoke_on_all_policies(test_transform_scan(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(),
expected.end(), in.size(), unary_op, init, binary_op, trash);
}
}
int32_t
main()
{
for (int32_t mode = 0; mode < 2; ++mode)
{
inclusive = mode != 0;
#if !__PSTL_ICC_19_TEST_SIMD_UDS_WINDOWS_RELEASE_BROKEN
test_matrix<Matrix2x2<int32_t>, Matrix2x2<int32_t>>([](const Matrix2x2<int32_t> x) { return x; },
Matrix2x2<int32_t>(), multiply_matrix<int32_t>,
Matrix2x2<int32_t>(-666, 666));
#endif
test<int32_t, uint32_t>([](int32_t x) { return x++; }, -123, [](int32_t x, int32_t y) { return x + y; }, 666);
}
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,87 @@
// -*- C++ -*-
//===-- test_transform_unary.cpp ------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
template <typename InputIterator, typename OutputIterator>
void
check_and_reset(InputIterator first, InputIterator last, OutputIterator out_first)
{
typedef typename std::iterator_traits<OutputIterator>::value_type Out;
typename std::iterator_traits<OutputIterator>::difference_type k = 0;
for (; first != last; ++first, ++out_first, ++k)
{
// check
Out expected = 1 - *first;
Out actual = *out_first;
EXPECT_EQ(expected, actual, "wrong value in output sequence");
// reset
*out_first = k % 7 != 4 ? 7 * k - 5 : 0;
}
}
struct test_one_policy
{
template <typename Policy, typename InputIterator, typename OutputIterator, typename UnaryOp>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, UnaryOp op)
{
auto orr = std::transform(exec, first, last, out_first, op);
EXPECT_TRUE(out_last == orr, "transform returned wrong iterator");
check_and_reset(first, last, out_first);
}
};
template <typename Tin, typename Tout>
void
test()
{
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<Tin> in(n, [](int32_t k) { return k % 5 != 1 ? 3 * k - 7 : 0; });
Sequence<Tout> out(n);
const auto flip = Complement<Tin, Tout>(1);
invoke_on_all_policies(test_one_policy(), in.begin(), in.end(), out.begin(), out.end(), flip);
invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cend(), out.begin(), out.end(), flip);
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename InputIterator, typename OutputInterator>
void
operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter)
{
invoke_if(exec, [&]() { transform(exec, input_iter, input_iter, out_iter, non_const(std::negate<T>())); });
}
};
int32_t
main()
{
test<int32_t, int32_t>();
test<int32_t, float32_t>();
test<uint16_t, float32_t>();
test<float32_t, float64_t>();
test<float64_t, float64_t>();
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,121 @@
// -*- C++ -*-
//===-- test_uninitialized_construct.cpp ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for uninitialized_default_consruct, uninitialized_default_consruct_n,
// uninitialized_value_consruct, uninitialized_value_consruct_n
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/memory"
#include "utils.h"
using namespace TestUtils;
// function of checking correctness for uninitialized.construct.value
template <typename T, typename Iterator>
bool
IsCheckValueCorrectness(Iterator begin, Iterator end)
{
for (; begin != end; ++begin)
{
if (*begin != T())
{
return false;
}
}
return true;
}
struct test_uninit_construct
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator begin, Iterator end, size_t n, /*is_trivial<T>=*/std::false_type)
{
typedef typename std::iterator_traits<Iterator>::value_type T;
// it needs for cleaning memory that was filled by default constructors in unique_ptr<T[]> p(new T[n])
// and for cleaning memory after last calling of uninitialized_value_construct_n.
// It is important for non-trivial types
std::destroy_n(exec, begin, n);
// reset counter of constructors
T::SetCount(0);
// run algorithm
std::uninitialized_default_construct(exec, begin, end);
// compare counter of constructors to length of container
EXPECT_TRUE(T::Count() == n, "wrong uninitialized_default_construct");
// destroy objects for testing new algorithms on same memory
std::destroy(exec, begin, end);
std::uninitialized_default_construct_n(exec, begin, n);
EXPECT_TRUE(T::Count() == n, "wrong uninitialized_default_construct_n");
std::destroy_n(exec, begin, n);
std::uninitialized_value_construct(exec, begin, end);
EXPECT_TRUE(T::Count() == n, "wrong uninitialized_value_construct");
std::destroy(exec, begin, end);
std::uninitialized_value_construct_n(exec, begin, n);
EXPECT_TRUE(T::Count() == n, "wrong uninitialized_value_construct_n");
}
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator begin, Iterator end, size_t n, /*is_trivial<T>=*/std::true_type)
{
typedef typename std::iterator_traits<Iterator>::value_type T;
std::uninitialized_default_construct(exec, begin, end);
std::destroy(exec, begin, end);
std::uninitialized_default_construct_n(exec, begin, n);
std::destroy_n(exec, begin, n);
std::uninitialized_value_construct(exec, begin, end);
// check correctness for uninitialized.construct.value
EXPECT_TRUE(IsCheckValueCorrectness<T>(begin, end), "wrong uninitialized_value_construct");
std::destroy(exec, begin, end);
std::uninitialized_value_construct_n(exec, begin, n);
EXPECT_TRUE(IsCheckValueCorrectness<T>(begin, end), "wrong uninitialized_value_construct_n");
std::destroy_n(exec, begin, n);
}
};
template <typename T>
void
test_uninit_construct_by_type()
{
std::size_t N = 100000;
for (size_t n = 0; n <= N; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
std::unique_ptr<T[]> p(new T[n]);
invoke_on_all_policies(test_uninit_construct(), p.get(), std::next(p.get(), n), n, std::is_trivial<T>());
}
}
int32_t
main()
{
// for user-defined types
#if !__PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN
test_uninit_construct_by_type<Wrapper<int32_t>>();
test_uninit_construct_by_type<Wrapper<std::vector<std::string>>>();
#endif
// for trivial types
test_uninit_construct_by_type<int8_t>();
test_uninit_construct_by_type<float64_t>();
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,143 @@
// -*- C++ -*-
//===-- test_uninitialized_copy_move.cpp ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for uninitialized_copy, uninitialized_copy_n, uninitialized_move, uninitialized_move_n
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/memory"
#include "utils.h"
using namespace TestUtils;
// function of checking correctness for uninitialized.construct.value
template <typename InputIterator, typename OutputIterator, typename Size>
bool
IsCheckValueCorrectness(InputIterator first1, OutputIterator first2, Size n)
{
for (Size i = 0; i < n; ++i, ++first1, ++first2)
{
if (*first1 != *first2)
{
return false;
}
}
return true;
}
struct test_uninitialized_copy_move
{
template <typename Policy, typename InputIterator, typename OutputIterator>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, size_t n,
/*is_trivial<T>=*/std::false_type)
{
typedef typename std::iterator_traits<InputIterator>::value_type T;
// it needs for cleaning memory that was filled by default constructors in unique_ptr<T[]> p(new T[n])
// and for cleaning memory after last calling of uninitialized_value_construct_n.
// It is important for non-trivial types
std::destroy_n(exec, out_first, n);
// reset counter of constructors
T::SetCount(0);
// run algorithm
std::uninitialized_copy(exec, first, last, out_first);
// compare counter of constructors to length of container
EXPECT_TRUE(T::Count() == n, "wrong uninitialized_copy");
// destroy objects for testing new algorithms on same memory
std::destroy_n(exec, out_first, n);
std::uninitialized_copy_n(exec, first, n, out_first);
EXPECT_TRUE(T::Count() == n, "wrong uninitialized_copy_n");
std::destroy_n(exec, out_first, n);
// For move
std::uninitialized_move(exec, first, last, out_first);
// compare counter of constructors to length of container
EXPECT_TRUE(T::MoveCount() == n, "wrong uninitialized_move");
// destroy objects for testing new algorithms on same memory
std::destroy_n(exec, out_first, n);
std::uninitialized_move_n(exec, first, n, out_first);
EXPECT_TRUE(T::MoveCount() == n, "wrong uninitialized_move_n");
std::destroy_n(exec, out_first, n);
}
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN
template <typename InputIterator, typename OutputIterator>
void
operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first,
size_t n, /*is_trivial<T>=*/std::true_type)
{
}
template <typename InputIterator, typename OutputIterator>
void
operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last,
OutputIterator out_first, size_t n, /*is_trivial<T>=*/std::true_type)
{
}
#endif
template <typename Policy, typename InputIterator, typename OutputIterator>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, size_t n,
/*is_trivial<T>=*/std::true_type)
{
typedef typename std::iterator_traits<InputIterator>::value_type T;
std::uninitialized_copy(exec, first, last, out_first);
EXPECT_TRUE(IsCheckValueCorrectness(first, out_first, n), "wrong uninitialized_copy");
std::destroy_n(exec, out_first, n);
std::uninitialized_copy_n(exec, first, n, out_first);
EXPECT_TRUE(IsCheckValueCorrectness(first, out_first, n), "wrong uninitialized_copy_n");
std::destroy_n(exec, out_first, n);
std::uninitialized_move(exec, first, last, out_first);
EXPECT_TRUE(IsCheckValueCorrectness(first, out_first, n), "wrong uninitialized_move");
std::destroy_n(exec, out_first, n);
std::uninitialized_move_n(exec, first, n, out_first);
EXPECT_TRUE(IsCheckValueCorrectness(first, out_first, n), "wrong uninitialized_move_n");
std::destroy_n(exec, out_first, n);
}
};
template <typename T>
void
test_uninitialized_copy_move_by_type()
{
std::size_t N = 100000;
for (size_t n = 0; n <= N; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
Sequence<T> in(n, [=](size_t k) -> T { return T(k); });
std::unique_ptr<T[]> p(new T[n]);
invoke_on_all_policies(test_uninitialized_copy_move(), in.begin(), in.end(), p.get(), n, std::is_trivial<T>());
}
}
int32_t
main()
{
// for trivial types
test_uninitialized_copy_move_by_type<int16_t>();
test_uninitialized_copy_move_by_type<float64_t>();
// for user-defined types
#if !__PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN && !__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN && \
!__PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN
test_uninitialized_copy_move_by_type<Wrapper<int8_t>>();
#endif
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,92 @@
// -*- C++ -*-
//===-- test_uninitialized_fill_destroy.cpp -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for the destroy, destroy_n, uninitialized_fill, uninitialized_fill_n algorithms
#include "pstl/execution"
#include "pstl/memory"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct test_uninitialized_fill_destroy
{
template <typename Policy, typename Iterator, typename T>
void
operator()(Policy&& exec, Iterator first, Iterator last, const T& in, std::size_t n, std::false_type)
{
using namespace std;
{
T::SetCount(0);
uninitialized_fill(exec, first, last, in);
size_t count = count_if(first, last, [&in](T& x) -> bool { return x == in; });
EXPECT_TRUE(n == count, "wrong work of uninitialized_fill");
destroy(exec, first, last);
EXPECT_TRUE(T::Count() == 0, "wrong work of destroy");
}
{
auto res = uninitialized_fill_n(exec, first, n, in);
EXPECT_TRUE(res == last, "wrong result of uninitialized_fill_n");
size_t count = count_if(first, last, [&in](T& x) -> bool { return x == in; });
EXPECT_TRUE(n == count, "wrong work of uninitialized_fill_n");
destroy_n(exec, first, n);
EXPECT_TRUE(T::Count() == 0, "wrong work of destroy_n");
}
}
template <typename Policy, typename Iterator, typename T>
void
operator()(Policy&& exec, Iterator first, Iterator last, const T& in, std::size_t n, std::true_type)
{
using namespace std;
{
destroy(exec, first, last);
uninitialized_fill(exec, first, last, in);
size_t count = count_if(first, last, [&in](T& x) -> bool { return x == in; });
EXPECT_EQ(n, count, "wrong work of uninitialized:_fill");
}
{
destroy_n(exec, first, n);
auto res = uninitialized_fill_n(exec, first, n, in);
size_t count = count_if(first, last, [&in](T& x) -> bool { return x == in; });
EXPECT_EQ(n, count, "wrong work of uninitialized_fill_n");
EXPECT_TRUE(res == last, "wrong result of uninitialized_fill_n");
}
}
};
template <typename T>
void
test_uninitialized_fill_destroy_by_type()
{
std::size_t N = 100000;
for (size_t n = 0; n <= N; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
std::unique_ptr<T[]> p(new T[n]);
invoke_on_all_policies(test_uninitialized_fill_destroy(), p.get(), std::next(p.get(), n), T(), n,
std::is_trivial<T>());
}
}
int32_t
main()
{
// for trivial types
test_uninitialized_fill_destroy_by_type<int32_t>();
test_uninitialized_fill_destroy_by_type<float64_t>();
// for user-defined types
test_uninitialized_fill_destroy_by_type<Wrapper<std::string>>();
test_uninitialized_fill_destroy_by_type<Wrapper<int8_t*>>();
std::cout << done() << std::endl;
return 0;
}

155
pstl/test/test_unique.cpp Normal file
View File

@ -0,0 +1,155 @@
// -*- C++ -*-
//===-- test_unique.cpp ---------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Test for unique
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct run_unique
{
#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
__PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
template <typename ForwardIt, typename Generator>
void
operator()(pstl::execution::unsequenced_policy, ForwardIt first1, ForwardIt last1, ForwardIt first2,
ForwardIt last2, Generator generator)
{
}
template <typename ForwardIt, typename Generator>
void
operator()(pstl::execution::parallel_unsequenced_policy, ForwardIt first1, ForwardIt last1, ForwardIt first2,
ForwardIt last2, Generator generator)
{
}
template <typename ForwardIt, typename BinaryPred, typename Generator>
void
operator()(pstl::execution::unsequenced_policy, ForwardIt first1, ForwardIt last1, ForwardIt first2,
ForwardIt last2, BinaryPred pred, Generator generator)
{
}
template <typename ForwardIt, typename BinaryPred, typename Generator>
void
operator()(pstl::execution::parallel_unsequenced_policy, ForwardIt first1, ForwardIt last1, ForwardIt first2,
ForwardIt last2, BinaryPred pred, Generator generator)
{
}
#endif
template <typename Policy, typename ForwardIt, typename Generator>
void
operator()(Policy&& exec, ForwardIt first1, ForwardIt last1, ForwardIt first2, ForwardIt last2, Generator generator)
{
using namespace std;
// Preparation
fill_data(first1, last1, generator);
fill_data(first2, last2, generator);
ForwardIt i = unique(first1, last1);
ForwardIt k = unique(exec, first2, last2);
auto n = std::distance(first1, i);
EXPECT_TRUE(std::distance(first2, k) == n, "wrong return value from unique without predicate");
EXPECT_EQ_N(first1, first2, n, "wrong effect from unique without predicate");
}
template <typename Policy, typename ForwardIt, typename BinaryPred, typename Generator>
void
operator()(Policy&& exec, ForwardIt first1, ForwardIt last1, ForwardIt first2, ForwardIt last2, BinaryPred pred,
Generator generator)
{
using namespace std;
// Preparation
fill_data(first1, last1, generator);
fill_data(first2, last2, generator);
ForwardIt i = unique(first1, last1, pred);
ForwardIt k = unique(exec, first2, last2, pred);
auto n = std::distance(first1, i);
EXPECT_TRUE(std::distance(first2, k) == n, "wrong return value from unique with predicate");
EXPECT_EQ_N(first1, first2, n, "wrong effect from unique with predicate");
}
};
template <typename T, typename Generator, typename Predicate>
void
test(Generator generator, Predicate pred)
{
const std::size_t max_size = 1000000;
Sequence<T> in(max_size, [](size_t v) { return T(v); });
Sequence<T> exp(max_size, [](size_t v) { return T(v); });
for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
invoke_on_all_policies(run_unique(), exp.begin(), exp.begin() + n, in.begin(), in.begin() + n, generator);
invoke_on_all_policies(run_unique(), exp.begin(), exp.begin() + n, in.begin(), in.begin() + n, pred, generator);
}
}
template <typename T>
struct LocalWrapper
{
T my_val;
explicit LocalWrapper(T k) : my_val(k) {}
LocalWrapper(LocalWrapper&& input) : my_val(std::move(input.my_val)) {}
LocalWrapper&
operator=(LocalWrapper&& input)
{
my_val = std::move(input.my_val);
return *this;
}
friend bool
operator==(const LocalWrapper<T>& x, const LocalWrapper<T>& y)
{
return x.my_val == y.my_val;
}
};
template <typename T>
struct test_non_const
{
template <typename Policy, typename Iterator>
void
operator()(Policy&& exec, Iterator iter)
{
invoke_if(exec, [&]() { unique(exec, iter, iter, non_const(std::equal_to<T>())); });
}
};
int32_t
main()
{
#if !__PSTL_ICC_16_17_18_TEST_UNIQUE_MASK_RELEASE_BROKEN
test<int32_t>([](size_t j) { return j / 3; },
[](const int32_t& val1, const int32_t& val2) { return val1 * val1 == val2 * val2; });
test<float64_t>([](size_t) { return float64_t(1); },
[](const float64_t& val1, const float64_t& val2) { return val1 != val2; });
#endif
test<LocalWrapper<uint32_t>>([](size_t j) { return LocalWrapper<uint32_t>(j); },
[](const LocalWrapper<uint32_t>& val1, const LocalWrapper<uint32_t>& val2) {
return val1.my_val != val2.my_val;
});
test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

View File

@ -0,0 +1,133 @@
// -*- C++ -*-
//===-- test_unique_copy_equal.cpp ----------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for unique_copy
#include "pstl_test_config.h"
#include "pstl/execution"
#include "pstl/algorithm"
#include "utils.h"
using namespace TestUtils;
struct run_unique_copy
{
#if __PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN // dummy specializations to skip testing in case of broken configuration
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename Predicate, typename T>
void
operator()(pstl::execution::parallel_policy, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n,
Predicate pred, T trash)
{
}
template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename Predicate, typename T>
void
operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last,
OutputIterator out_first, OutputIterator out_last, OutputIterator2 expected_first,
OutputIterator2 expected_last, Size n, Predicate pred, T trash)
{
}
#endif
template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
typename Predicate, typename T>
void
operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first,
OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n,
Predicate pred, T trash)
{
// Cleaning
std::fill_n(expected_first, n, trash);
std::fill_n(out_first, n, trash);
// Run unique_copy
auto i = unique_copy(first, last, expected_first);
auto k = unique_copy(exec, first, last, out_first);
EXPECT_EQ_N(expected_first, out_first, n, "wrong unique_copy effect");
for (size_t j = 0; j < GuardSize; ++j)
{
++k;
}
EXPECT_TRUE(out_last == k, "wrong return value from unique_copy");
// Cleaning
std::fill_n(expected_first, n, trash);
std::fill_n(out_first, n, trash);
// Run unique_copy with predicate
i = unique_copy(first, last, expected_first, pred);
k = unique_copy(exec, first, last, out_first, pred);
EXPECT_EQ_N(expected_first, out_first, n, "wrong unique_copy with predicate effect");
for (size_t j = 0; j < GuardSize; ++j)
{
++k;
}
EXPECT_TRUE(out_last == k, "wrong return value from unique_copy with predicate");
}
};
template <typename T, typename BinaryPredicate, typename Convert>
void
test(T trash, BinaryPredicate pred, Convert convert, bool check_weakness = true)
{
// Try sequences of various lengths.
for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
{
// count is number of output elements, plus a handful
// more for sake of detecting buffer overruns.
Sequence<T> in(n, [&](size_t k) -> T { return convert(k ^ n); });
using namespace std;
size_t count = GuardSize;
for (size_t k = 0; k < in.size(); ++k)
count += k == 0 || !pred(in[k], in[k - 1]) ? 1 : 0;
Sequence<T> out(count, [=](size_t) { return trash; });
Sequence<T> expected(count, [=](size_t) { return trash; });
if (check_weakness)
{
auto expected_result = unique_copy(in.begin(), in.end(), expected.begin(), pred);
size_t m = expected_result - expected.begin();
EXPECT_TRUE(n / (n < 10000 ? 4 : 6) <= m && m <= (3 * n + 1) / 4, "weak test for unique_copy");
}
invoke_on_all_policies(run_unique_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(),
expected.end(), count, pred, trash);
}
}
template <typename T>
struct test_non_const
{
template <typename Policy, typename InputIterator, typename OutputInterator>
void
operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter)
{
unique_copy(exec, input_iter, input_iter, out_iter, non_const(std::equal_to<T>()));
}
};
int32_t
main(int32_t argc, char* argv[])
{
test<Number>(Number(42, OddTag()), std::equal_to<Number>(),
[](int32_t j) { return Number(3 * j / 13 ^ (j & 8), OddTag()); });
test<float32_t>(float32_t(42), std::equal_to<float32_t>(),
[](int32_t j) { return float32_t(5 * j / 23 ^ (j / 7)); });
#if !__PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN
test<float32_t>(float32_t(42), [](float32_t x, float32_t y) { return false; },
[](int32_t j) { return float32_t(j); }, false);
#endif
test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
std::cout << done() << std::endl;
return 0;
}

Some files were not shown because too many files have changed in this diff Show More