mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 13:50:11 +00:00
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:
parent
5d409b2278
commit
e637637ae4
4
pstl/.arcconfig
Normal file
4
pstl/.arcconfig
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"repository.callsign" : "PSTL",
|
||||
"conduit_uri" : "https://reviews.llvm.org/"
|
||||
}
|
17
pstl/.clang-format
Normal file
17
pstl/.clang-format
Normal 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
71
pstl/CMakeLists.txt
Normal 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
17
pstl/CREDITS.txt
Normal 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
70
pstl/LICENSE.txt
Normal 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.
|
18
pstl/ParallelSTLConfig.cmake.in
Normal file
18
pstl/ParallelSTLConfig.cmake.in
Normal 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
40
pstl/README.md
Normal 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
102
pstl/build/Makefile
Normal 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
113
pstl/build/Makefile.common
Normal 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
47
pstl/build/Makefile.pstl
Normal 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
48
pstl/build/android.inc
Normal 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))
|
149
pstl/build/android.linux.launcher.sh
Normal file
149
pstl/build/android.linux.launcher.sh
Normal 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
22
pstl/build/clang.inc
Normal 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
28
pstl/build/gcc.inc
Normal 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
24
pstl/build/icc.inc
Normal 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
23
pstl/build/icl.inc
Normal 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
54
pstl/build/jni/Android.mk
Normal 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
|
61
pstl/build/jni/Application.mk
Normal file
61
pstl/build/jni/Application.mk
Normal 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
10
pstl/build/macos.inc
Normal 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
50
pstl/build/mingw.inc
Normal 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
51
pstl/build/unix.inc
Normal 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
54
pstl/build/windows.inc
Normal 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
78
pstl/cmake/FindTBB.cmake
Normal 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)
|
25
pstl/include/pstl/algorithm
Normal file
25
pstl/include/pstl/algorithm
Normal 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 */
|
49
pstl/include/pstl/execution
Normal file
49
pstl/include/pstl/execution
Normal 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 */
|
3557
pstl/include/pstl/internal/algorithm_impl.h
Normal file
3557
pstl/include/pstl/internal/algorithm_impl.h
Normal file
File diff suppressed because it is too large
Load Diff
163
pstl/include/pstl/internal/execution_defs.h
Normal file
163
pstl/include/pstl/internal/execution_defs.h
Normal 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 */
|
156
pstl/include/pstl/internal/execution_impl.h
Normal file
156
pstl/include/pstl/internal/execution_impl.h
Normal 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 */
|
552
pstl/include/pstl/internal/glue_algorithm_defs.h
Normal file
552
pstl/include/pstl/internal/glue_algorithm_defs.h
Normal 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 */
|
1173
pstl/include/pstl/internal/glue_algorithm_impl.h
Normal file
1173
pstl/include/pstl/internal/glue_algorithm_impl.h
Normal file
File diff suppressed because it is too large
Load Diff
53
pstl/include/pstl/internal/glue_execution_defs.h
Normal file
53
pstl/include/pstl/internal/glue_execution_defs.h
Normal 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 */
|
80
pstl/include/pstl/internal/glue_memory_defs.h
Normal file
80
pstl/include/pstl/internal/glue_memory_defs.h
Normal 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 */
|
357
pstl/include/pstl/internal/glue_memory_impl.h
Normal file
357
pstl/include/pstl/internal/glue_memory_impl.h
Normal 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 */
|
116
pstl/include/pstl/internal/glue_numeric_defs.h
Normal file
116
pstl/include/pstl/internal/glue_numeric_defs.h
Normal 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 */
|
224
pstl/include/pstl/internal/glue_numeric_impl.h
Normal file
224
pstl/include/pstl/internal/glue_numeric_impl.h
Normal 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_ */
|
57
pstl/include/pstl/internal/memory_impl.h
Normal file
57
pstl/include/pstl/internal/memory_impl.h
Normal 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 */
|
359
pstl/include/pstl/internal/numeric_impl.h
Normal file
359
pstl/include/pstl/internal/numeric_impl.h
Normal 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 */
|
20
pstl/include/pstl/internal/parallel_backend.h
Normal file
20
pstl/include/pstl/internal/parallel_backend.h
Normal 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 */
|
656
pstl/include/pstl/internal/parallel_backend_tbb.h
Normal file
656
pstl/include/pstl/internal/parallel_backend_tbb.h
Normal 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 */
|
195
pstl/include/pstl/internal/parallel_backend_utils.h
Normal file
195
pstl/include/pstl/internal/parallel_backend_utils.h
Normal 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 */
|
82
pstl/include/pstl/internal/parallel_impl.h
Normal file
82
pstl/include/pstl/internal/parallel_impl.h
Normal 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 */
|
175
pstl/include/pstl/internal/pstl_config.h
Normal file
175
pstl/include/pstl/internal/pstl_config.h
Normal 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 */
|
856
pstl/include/pstl/internal/unseq_backend_simd.h
Normal file
856
pstl/include/pstl/internal/unseq_backend_simd.h
Normal 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 */
|
223
pstl/include/pstl/internal/utils.h
Normal file
223
pstl/include/pstl/internal/utils.h
Normal 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
25
pstl/include/pstl/memory
Normal 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
25
pstl/include/pstl/numeric
Normal 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 */
|
50
pstl/test/pstl_test_config.h
Normal file
50
pstl/test/pstl_test_config.h
Normal 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 */
|
170
pstl/test/test_adjacent_difference.cpp
Normal file
170
pstl/test/test_adjacent_difference.cpp
Normal 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;
|
||||
}
|
112
pstl/test/test_adjacent_find.cpp
Normal file
112
pstl/test/test_adjacent_find.cpp
Normal 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
115
pstl/test/test_all_of.cpp
Normal 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
101
pstl/test/test_any_of.cpp
Normal 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
145
pstl/test/test_copy_if.cpp
Normal 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;
|
||||
}
|
199
pstl/test/test_copy_move.cpp
Normal file
199
pstl/test/test_copy_move.cpp
Normal 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
106
pstl/test/test_count.cpp
Normal 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
166
pstl/test/test_equal.cpp
Normal 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
98
pstl/test/test_fill.cpp
Normal 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
94
pstl/test/test_find.cpp
Normal 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
121
pstl/test/test_find_end.cpp
Normal 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;
|
||||
}
|
110
pstl/test/test_find_first_of.cpp
Normal file
110
pstl/test/test_find_first_of.cpp
Normal 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
107
pstl/test/test_find_if.cpp
Normal 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;
|
||||
}
|
98
pstl/test/test_for_each.cpp
Normal file
98
pstl/test/test_for_each.cpp
Normal 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
101
pstl/test/test_generate.cpp
Normal 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
105
pstl/test/test_includes.cpp
Normal 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;
|
||||
}
|
155
pstl/test/test_inplace_merge.cpp
Normal file
155
pstl/test/test_inplace_merge.cpp
Normal 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
143
pstl/test/test_is_heap.cpp
Normal 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;
|
||||
}
|
99
pstl/test/test_is_partitioned.cpp
Normal file
99
pstl/test/test_is_partitioned.cpp
Normal 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;
|
||||
}
|
98
pstl/test/test_is_sorted.cpp
Normal file
98
pstl/test/test_is_sorted.cpp
Normal 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;
|
||||
}
|
174
pstl/test/test_lexicographical_compare.cpp
Normal file
174
pstl/test/test_lexicographical_compare.cpp
Normal 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
114
pstl/test/test_merge.cpp
Normal 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;
|
||||
}
|
192
pstl/test/test_minmax_element.cpp
Normal file
192
pstl/test/test_minmax_element.cpp
Normal 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
133
pstl/test/test_mismatch.cpp
Normal 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;
|
||||
}
|
99
pstl/test/test_none_of.cpp
Normal file
99
pstl/test/test_none_of.cpp
Normal 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;
|
||||
}
|
176
pstl/test/test_nth_element.cpp
Normal file
176
pstl/test/test_nth_element.cpp
Normal 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;
|
||||
}
|
150
pstl/test/test_partial_sort.cpp
Normal file
150
pstl/test/test_partial_sort.cpp
Normal 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;
|
||||
}
|
190
pstl/test/test_partial_sort_copy.cpp
Normal file
190
pstl/test/test_partial_sort_copy.cpp
Normal 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;
|
||||
}
|
178
pstl/test/test_partition.cpp
Normal file
178
pstl/test/test_partition.cpp
Normal 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;
|
||||
}
|
115
pstl/test/test_partition_copy.cpp
Normal file
115
pstl/test/test_partition_copy.cpp
Normal 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
112
pstl/test/test_reduce.cpp
Normal 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
152
pstl/test/test_remove.cpp
Normal 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;
|
||||
}
|
88
pstl/test/test_remove_copy.cpp
Normal file
88
pstl/test/test_remove_copy.cpp
Normal 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
158
pstl/test/test_replace.cpp
Normal 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;
|
||||
}
|
103
pstl/test/test_replace_copy.cpp
Normal file
103
pstl/test/test_replace_copy.cpp
Normal 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
103
pstl/test/test_reverse.cpp
Normal 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;
|
||||
}
|
132
pstl/test/test_reverse_copy.cpp
Normal file
132
pstl/test/test_reverse_copy.cpp
Normal 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
172
pstl/test/test_rotate.cpp
Normal 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;
|
||||
}
|
145
pstl/test/test_rotate_copy.cpp
Normal file
145
pstl/test/test_rotate_copy.cpp
Normal 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
197
pstl/test/test_scan.cpp
Normal 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
107
pstl/test/test_search_n.cpp
Normal 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
161
pstl/test/test_set.cpp
Normal 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
245
pstl/test/test_sort.cpp
Normal 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;
|
||||
}
|
132
pstl/test/test_swap_ranges.cpp
Normal file
132
pstl/test/test_swap_ranges.cpp
Normal 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;
|
||||
}
|
117
pstl/test/test_transform_binary.cpp
Normal file
117
pstl/test/test_transform_binary.cpp
Normal 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;
|
||||
}
|
134
pstl/test/test_transform_reduce.cpp
Normal file
134
pstl/test/test_transform_reduce.cpp
Normal 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;
|
||||
}
|
174
pstl/test/test_transform_scan.cpp
Normal file
174
pstl/test/test_transform_scan.cpp
Normal 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;
|
||||
}
|
87
pstl/test/test_transform_unary.cpp
Normal file
87
pstl/test/test_transform_unary.cpp
Normal 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;
|
||||
}
|
121
pstl/test/test_uninitialized_construct.cpp
Normal file
121
pstl/test/test_uninitialized_construct.cpp
Normal 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;
|
||||
}
|
143
pstl/test/test_uninitialized_copy_move.cpp
Normal file
143
pstl/test/test_uninitialized_copy_move.cpp
Normal 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;
|
||||
}
|
92
pstl/test/test_uninitialized_fill_destroy.cpp
Normal file
92
pstl/test/test_uninitialized_fill_destroy.cpp
Normal 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
155
pstl/test/test_unique.cpp
Normal 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;
|
||||
}
|
133
pstl/test/test_unique_copy_equal.cpp
Normal file
133
pstl/test/test_unique_copy_equal.cpp
Normal 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
Loading…
Reference in New Issue
Block a user