Add parallel mode.

2007-09-11  Johannes Singler  <singler@ira.uka.de>
	    Leonor Frias Moya  <lfrias@lsi.upc.edu>
            Felix Putze  <kontakt@felix-putze.de>
            Marius Elvert  <marius.elvert@ira.uka.de>
	    Felix Bondarenko  <f.bondarenko@web.de>
	    Robert Geisberger  <robert.geisberger@stud.uni-karlsruhe.de>
	    Robin Dapp  <r.dapp@freenet.de>
  	    Benjamin Kosnik  <bkoz@redhat.com>

	Add parallel mode.
	* include/parallel: New.
	* include/parallel/iterator.h: New.
	* include/parallel/multiway_merge.h: New.
	* include/parallel/parallel.h: New.
	* include/parallel/algorithm
	* include/parallel/find_selectors.h: New.
	* include/parallel/losertree.h: New.
	* include/parallel/list_partition.h: New.
	* include/parallel/types.h: New.
	* include/parallel/for_each.h: New.
	* include/parallel/multiseq_selection.h: New.
	* include/parallel/workstealing.h: New.
	* include/parallel/base.h: New.
	* include/parallel/par_loop.h: New.
	* include/parallel/numeric
	* include/parallel/features.h: New.
	* include/parallel/quicksort.h: New.
	* include/parallel/algorithmfwd.h: New.
	* include/parallel/equally_split.h: New.
	* include/parallel/compiletime_settings.h: New.
	* include/parallel/for_each_selectors.h: New.
	* include/parallel/basic_iterator.h: New.
	* include/parallel/omp_loop_static.h: New.
	* include/parallel/random_shuffle.h: New.
	* include/parallel/balanced_quicksort.h: New.
	* include/parallel/set_operations.h: New.
	* include/parallel/tags.h: New.
	* include/parallel/merge.h: New.
	* include/parallel/tree.h: New.
	* include/parallel/settings.h: New.
	* include/parallel/unique_copy.h: New.
	* include/parallel/multiway_mergesort.h: New.
	* include/parallel/numericfwd.h: New.
	* include/parallel/search.h: New.
	* include/parallel/partition.h: New.
	* include/parallel/compatibility.h: New.
	* include/parallel/algobase.h: New.
	* include/parallel/find.h: New.
	* include/parallel/partial_sum.h: New.
	* include/parallel/algo.h: New.
	* include/parallel/omp_loop.h: New.
	* include/parallel/queue.h: New.
	* include/parallel/timing.h: New.
	* include/parallel/sort.h: New.
	* include/parallel/checkers.h: New.
	* include/parallel/random_number.h: New.
	* include/bits/algorithmfwd.h: New.

	* acinclude.m4 (GLIBCXX_ENABLE_PARALLEL): New.
	* configure.host: Add atomic_flags.
	* configure.ac: Export ATOMIC_FLAGS, call GLIBCXX_ENABLE_PARALLEL.
	* src/Makefile.am: Add parallel_list rules.
	* include/Makefile.am: Add parallel files.
	* testsuite/Makefile.am (check-parallel): Add.
	(check-performance-parallel): Add.
	* config.h.in: Regenerate.
	* configure: Same.
	* libsupc++/Makefile.in: Same.
	* testsuite/Makefile.in: Same.
	* Makefile.in: Same.
	* libmath/Makefile.in: Same.
	* include/Makefile.in: Same.
	* src/Makefile.in: Same.
	* po/Makefile.in: Same.
	
	* config/abi/pre/gnu.ver: Export parallel list bits.

	* docs/html/parallel_mode.html: New.
	* docs/html/documentation.html: Add link.
	* docs/doxygen/user.cfg.in: Adjust for new files and directory.
	* docs/doxygen/doxygroups.cc: Adjust namespace markup.

	* include/debug/set.h: Adjust for _GLIBCXX_STD_D or _P change.
	* include/debug/bitset: Same.
	* include/debug/multiset.h: Same.
	* include/debug/vector: Same.
	* include/debug/map.h: Same.
	* include/debug/deque: Same.
	* include/debug/list: Same.
	* include/debug/debug.h: Same.
	* include/debug/multimap.h: Same.
	* include/std/algorithm: Same.
	* include/std/numeric: Same.
	* include/std/bitset: Same.
	* include/std/string: Same.
	* include/ext/hash_map: Same.
	* include/ext/hash_set: Same.
	* include/bits/stl_list.h: Same.
	* include/bits/stl_map.h: Same.
	* include/bits/stl_algobase.h: Same.
	* include/bits/stl_set.h: Same.
	* include/bits/stl_multimap.h: Same.
	* include/bits/stl_vector.h: Same.
	* include/bits/stl_numeric.h: Same.
	* include/bits/stl_deque.h: Same.
	* include/bits/stl_multiset.h: Same.
	* include/bits/char_traits.h: Same.
	* include/bits/stl_algo.h: Same.
	* include/bits/c++config: Same.
	* include/bits/vector.tcc: Same.
	* include/bits/deque.tcc: Same.
	* include/bits/stl_bvector.h: Same.
	* include/bits/list.tcc: Same.
	* src/list.cc: Same.
	* src/parallel_list.cc: New.

	* testsuite/lib/libstdc++.exp (check_v3_target_parallel_mode): New.
	* testsuite/lib/dg-options.exp (dg-require-parallel-mode): New.
	* scripts/testsuite_flags.in (--cxxparallelflags): New.
	* scripts/check_performance: Adjust.
	* testsuite/25_algorithms/headers/parallel_algorithm.cc: New.
	* testsuite/25_algorithms/headers/algorithm_parallel_mode.cc: New.
	* testsuite/25_algorithms/headers/parallel_algorithm_mixed1.cc: New.
	* testsuite/25_algorithms/headers/parallel_algorithm_mixed2.cc: New.
	* testsuite/26_numerics/headers/numeric/parallel_numeric.cc: New.
	* testsuite/26_numerics/headers/numeric/numeric_parallel_mode.cc: New.
	* testsuite/26_numerics/headers/numeric/
	parallel_numeric_mixed1.cc: New.
	* testsuite/26_numerics/headers/numeric/
	parallel_numeric_mixed2.cc: New.
	

Co-Authored-By: Benjamin Kosnik <bkoz@redhat.com>
Co-Authored-By: Felix Bondarenko <f.bondarenko@web.de>
Co-Authored-By: Felix Putze <kontakt@felix-putze.de>
Co-Authored-By: Leonor Frias Moya <lfrias@lsi.upc.edu>
Co-Authored-By: Marius Elvert <marius.elvert@ira.uka.de>
Co-Authored-By: Robert Geisberger <robert.geisberger@stud.uni-karlsruhe.de>
Co-Authored-By: Robin Dapp <r.dapp@freenet.de>

From-SVN: r128395
This commit is contained in:
Johannes Singler 2007-09-11 22:32:51 +00:00 committed by Benjamin Kosnik
parent f6ee8d7b73
commit c2ba97097b
112 changed files with 21840 additions and 1869 deletions

View File

@ -1,3 +1,134 @@
2007-09-11 Johannes Singler <singler@ira.uka.de>
Leonor Frias Moya <lfrias@lsi.upc.edu>
Felix Putze <kontakt@felix-putze.de>
Marius Elvert <marius.elvert@ira.uka.de>
Felix Bondarenko <f.bondarenko@web.de>
Robert Geisberger <robert.geisberger@stud.uni-karlsruhe.de>
Robin Dapp <r.dapp@freenet.de>
Benjamin Kosnik <bkoz@redhat.com>
Add parallel mode.
* include/parallel: New.
* include/parallel/iterator.h: New.
* include/parallel/multiway_merge.h: New.
* include/parallel/parallel.h: New.
* include/parallel/algorithm
* include/parallel/find_selectors.h: New.
* include/parallel/losertree.h: New.
* include/parallel/list_partition.h: New.
* include/parallel/types.h: New.
* include/parallel/for_each.h: New.
* include/parallel/multiseq_selection.h: New.
* include/parallel/workstealing.h: New.
* include/parallel/base.h: New.
* include/parallel/par_loop.h: New.
* include/parallel/numeric
* include/parallel/features.h: New.
* include/parallel/quicksort.h: New.
* include/parallel/algorithmfwd.h: New.
* include/parallel/equally_split.h: New.
* include/parallel/compiletime_settings.h: New.
* include/parallel/for_each_selectors.h: New.
* include/parallel/basic_iterator.h: New.
* include/parallel/omp_loop_static.h: New.
* include/parallel/random_shuffle.h: New.
* include/parallel/balanced_quicksort.h: New.
* include/parallel/set_operations.h: New.
* include/parallel/tags.h: New.
* include/parallel/merge.h: New.
* include/parallel/tree.h: New.
* include/parallel/settings.h: New.
* include/parallel/unique_copy.h: New.
* include/parallel/multiway_mergesort.h: New.
* include/parallel/numericfwd.h: New.
* include/parallel/search.h: New.
* include/parallel/partition.h: New.
* include/parallel/compatibility.h: New.
* include/parallel/algobase.h: New.
* include/parallel/find.h: New.
* include/parallel/partial_sum.h: New.
* include/parallel/algo.h: New.
* include/parallel/omp_loop.h: New.
* include/parallel/queue.h: New.
* include/parallel/timing.h: New.
* include/parallel/sort.h: New.
* include/parallel/checkers.h: New.
* include/parallel/random_number.h: New.
* include/bits/algorithmfwd.h: New.
* acinclude.m4 (GLIBCXX_ENABLE_PARALLEL): New.
* configure.host: Add atomic_flags.
* configure.ac: Export ATOMIC_FLAGS, call GLIBCXX_ENABLE_PARALLEL.
* src/Makefile.am: Add parallel_list rules.
* include/Makefile.am: Add parallel files.
* testsuite/Makefile.am (check-parallel): Add.
(check-performance-parallel): Add.
* config.h.in: Regenerate.
* configure: Same.
* libsupc++/Makefile.in: Same.
* testsuite/Makefile.in: Same.
* Makefile.in: Same.
* libmath/Makefile.in: Same.
* include/Makefile.in: Same.
* src/Makefile.in: Same.
* po/Makefile.in: Same.
* config/abi/pre/gnu.ver: Export parallel list bits.
* docs/html/parallel_mode.html: New.
* docs/html/documentation.html: Add link.
* docs/doxygen/user.cfg.in: Adjust for new files and directory.
* docs/doxygen/doxygroups.cc: Adjust namespace markup.
* include/debug/set.h: Adjust for _GLIBCXX_STD_D or _P change.
* include/debug/bitset: Same.
* include/debug/multiset.h: Same.
* include/debug/vector: Same.
* include/debug/map.h: Same.
* include/debug/deque: Same.
* include/debug/list: Same.
* include/debug/debug.h: Same.
* include/debug/multimap.h: Same.
* include/std/algorithm: Same.
* include/std/numeric: Same.
* include/std/bitset: Same.
* include/std/string: Same.
* include/ext/hash_map: Same.
* include/ext/hash_set: Same.
* include/bits/stl_list.h: Same.
* include/bits/stl_map.h: Same.
* include/bits/stl_algobase.h: Same.
* include/bits/stl_set.h: Same.
* include/bits/stl_multimap.h: Same.
* include/bits/stl_vector.h: Same.
* include/bits/stl_numeric.h: Same.
* include/bits/stl_deque.h: Same.
* include/bits/stl_multiset.h: Same.
* include/bits/char_traits.h: Same.
* include/bits/stl_algo.h: Same.
* include/bits/c++config: Same.
* include/bits/vector.tcc: Same.
* include/bits/deque.tcc: Same.
* include/bits/stl_bvector.h: Same.
* include/bits/list.tcc: Same.
* src/list.cc: Same.
* src/parallel_list.cc: New.
* testsuite/lib/libstdc++.exp (check_v3_target_parallel_mode): New.
* testsuite/lib/dg-options.exp (dg-require-parallel-mode): New.
* scripts/testsuite_flags.in (--cxxparallelflags): New.
* scripts/check_performance: Adjust.
* testsuite/25_algorithms/headers/parallel_algorithm.cc: New.
* testsuite/25_algorithms/headers/algorithm_parallel_mode.cc: New.
* testsuite/25_algorithms/headers/parallel_algorithm_mixed1.cc: New.
* testsuite/25_algorithms/headers/parallel_algorithm_mixed2.cc: New.
* testsuite/26_numerics/headers/numeric/parallel_numeric.cc: New.
* testsuite/26_numerics/headers/numeric/numeric_parallel_mode.cc: New.
* testsuite/26_numerics/headers/numeric/
parallel_numeric_mixed1.cc: New.
* testsuite/26_numerics/headers/numeric/
parallel_numeric_mixed2.cc: New.
2007-09-11 Daniel Jacobowitz <dan@codesourcery.com>
* testsuite/lib/libstdc++.exp (libstdc++_init): Revert part of

View File

@ -103,6 +103,7 @@ AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
ATOMICITY_SRCDIR = @ATOMICITY_SRCDIR@
ATOMIC_FLAGS = @ATOMIC_FLAGS@
ATOMIC_WORD_SRCDIR = @ATOMIC_WORD_SRCDIR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@ -140,6 +141,8 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
ENABLE_PARALLEL_FALSE = @ENABLE_PARALLEL_FALSE@
ENABLE_PARALLEL_TRUE = @ENABLE_PARALLEL_TRUE@
ENABLE_SYMVERS_DARWIN_FALSE = @ENABLE_SYMVERS_DARWIN_FALSE@
ENABLE_SYMVERS_DARWIN_TRUE = @ENABLE_SYMVERS_DARWIN_TRUE@
ENABLE_SYMVERS_FALSE = @ENABLE_SYMVERS_FALSE@

View File

@ -1725,6 +1725,23 @@ AC_DEFUN([GLIBCXX_ENABLE_CONCEPT_CHECKS], [
fi
])
dnl
dnl Check for parallel mode pre-requisites, including OpenMP support.
dnl
dnl + Usage: GLIBCXX_ENABLE_PARALLEL
dnl
AC_DEFUN([GLIBCXX_ENABLE_PARALLEL], [
enable_parallel=no;
if test -f "${glibcxx_builddir}/../libgomp/omp.h"; then
enable_parallel=yes;
fi
AC_MSG_CHECKING([for parallel mode support])
AC_MSG_RESULT([$enable_parallel])
GLIBCXX_CONDITIONAL(ENABLE_PARALLEL, test $enable_parallel = yes)
])
dnl
dnl Check for which I/O library to use: stdio, or something specific.
@ -2072,7 +2089,7 @@ AC_DEFUN([GLIBCXX_ENABLE_PCH], [
GLIBCXX_CONDITIONAL(GLIBCXX_BUILD_PCH, test $enable_libstdcxx_pch = yes)
if test $enable_libstdcxx_pch = yes; then
glibcxx_PCHFLAGS="-include bits/stdtr1c++.h"
glibcxx_PCHFLAGS="-include bits/stdc++.h"
else
glibcxx_PCHFLAGS=""
fi

View File

@ -63,6 +63,9 @@
/* Define if EBADMSG exists. */
#undef HAVE_EBADMSG
/* Define if ECANCELED exists. */
#undef HAVE_ECANCELED
/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H

View File

@ -770,6 +770,13 @@ GLIBCXX_3.4.10 {
_ZNKSt4hashISsEclESs;
_ZNKSt4hashISt10error_codeEclES0_;
# for parallel mode
_ZNSt9__cxx199815_List_node_base4hook*;
_ZNSt9__cxx199815_List_node_base4swap*;
_ZNSt9__cxx199815_List_node_base6unhookEv;
_ZNSt9__cxx199815_List_node_base7reverseEv;
_ZNSt9__cxx199815_List_node_base8transfer*;
} GLIBCXX_3.4.9;
# Symbols in the support library (libsupc++) have their own tag.

View File

@ -458,7 +458,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS libtool_VERSION multi_basedir build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar glibcxx_builddir glibcxx_srcdir toplevel_srcdir CC ac_ct_CC EXEEXT OBJEXT CXX ac_ct_CXX CFLAGS CXXFLAGS LN_S AS ac_ct_AS AR ac_ct_AR RANLIB ac_ct_RANLIB MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CPP CPPFLAGS EGREP LIBTOOL SED FGREP GREP LD DUMPBIN ac_ct_DUMPBIN NM lt_ECHO LDFLAGS CXXCPP enable_shared enable_static GLIBCXX_HOSTED_TRUE GLIBCXX_HOSTED_FALSE GLIBCXX_BUILD_PCH_TRUE GLIBCXX_BUILD_PCH_FALSE glibcxx_PCHFLAGS CSTDIO_H BASIC_FILE_H BASIC_FILE_CC check_msgfmt glibcxx_MOFILES glibcxx_POFILES glibcxx_localedir USE_NLS CLOCALE_H CMESSAGES_H CCODECVT_CC CCOLLATE_CC CCTYPE_CC CMESSAGES_CC CMONEY_CC CNUMERIC_CC CTIME_H CTIME_CC CLOCALE_CC CLOCALE_INTERNAL_H ALLOCATOR_H ALLOCATOR_NAME C_INCLUDE_DIR GLIBCXX_C_HEADERS_C_TRUE GLIBCXX_C_HEADERS_C_FALSE GLIBCXX_C_HEADERS_C_STD_TRUE GLIBCXX_C_HEADERS_C_STD_FALSE GLIBCXX_C_HEADERS_C_GLOBAL_TRUE GLIBCXX_C_HEADERS_C_GLOBAL_FALSE GLIBCXX_C_HEADERS_COMPATIBILITY_TRUE GLIBCXX_C_HEADERS_COMPATIBILITY_FALSE GLIBCXX_C_HEADERS_EXTRA_TRUE GLIBCXX_C_HEADERS_EXTRA_FALSE DEBUG_FLAGS GLIBCXX_BUILD_DEBUG_TRUE GLIBCXX_BUILD_DEBUG_FALSE EXTRA_CXX_FLAGS glibcxx_thread_h WERROR SECTION_FLAGS SECTION_LDFLAGS OPT_LDFLAGS LIBMATHOBJS LIBICONV LTLIBICONV SYMVER_FILE port_specific_symbol_files ENABLE_SYMVERS_TRUE ENABLE_SYMVERS_FALSE ENABLE_SYMVERS_GNU_TRUE ENABLE_SYMVERS_GNU_FALSE ENABLE_SYMVERS_GNU_NAMESPACE_TRUE ENABLE_SYMVERS_GNU_NAMESPACE_FALSE ENABLE_SYMVERS_DARWIN_TRUE ENABLE_SYMVERS_DARWIN_FALSE ENABLE_VISIBILITY_TRUE ENABLE_VISIBILITY_FALSE GLIBCXX_LDBL_COMPAT_TRUE GLIBCXX_LDBL_COMPAT_FALSE baseline_dir ATOMICITY_SRCDIR ATOMIC_WORD_SRCDIR CPU_DEFINES_SRCDIR ABI_TWEAKS_SRCDIR OS_INC_SRCDIR ERROR_CONSTANTS_SRCDIR glibcxx_prefixdir gxx_include_dir glibcxx_toolexecdir glibcxx_toolexeclibdir GLIBCXX_INCLUDES TOPLEVEL_INCLUDES OPTIMIZE_CXXFLAGS WARN_FLAGS LIBSUPCXX_PICFLAGS LIBOBJS LTLIBOBJS'
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS libtool_VERSION multi_basedir build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar glibcxx_builddir glibcxx_srcdir toplevel_srcdir CC ac_ct_CC EXEEXT OBJEXT CXX ac_ct_CXX CFLAGS CXXFLAGS LN_S AS ac_ct_AS AR ac_ct_AR RANLIB ac_ct_RANLIB MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CPP CPPFLAGS EGREP LIBTOOL SED FGREP GREP LD DUMPBIN ac_ct_DUMPBIN NM lt_ECHO LDFLAGS CXXCPP enable_shared enable_static GLIBCXX_HOSTED_TRUE GLIBCXX_HOSTED_FALSE GLIBCXX_BUILD_PCH_TRUE GLIBCXX_BUILD_PCH_FALSE glibcxx_PCHFLAGS CSTDIO_H BASIC_FILE_H BASIC_FILE_CC check_msgfmt glibcxx_MOFILES glibcxx_POFILES glibcxx_localedir USE_NLS CLOCALE_H CMESSAGES_H CCODECVT_CC CCOLLATE_CC CCTYPE_CC CMESSAGES_CC CMONEY_CC CNUMERIC_CC CTIME_H CTIME_CC CLOCALE_CC CLOCALE_INTERNAL_H ALLOCATOR_H ALLOCATOR_NAME C_INCLUDE_DIR GLIBCXX_C_HEADERS_C_TRUE GLIBCXX_C_HEADERS_C_FALSE GLIBCXX_C_HEADERS_C_STD_TRUE GLIBCXX_C_HEADERS_C_STD_FALSE GLIBCXX_C_HEADERS_C_GLOBAL_TRUE GLIBCXX_C_HEADERS_C_GLOBAL_FALSE GLIBCXX_C_HEADERS_COMPATIBILITY_TRUE GLIBCXX_C_HEADERS_COMPATIBILITY_FALSE GLIBCXX_C_HEADERS_EXTRA_TRUE GLIBCXX_C_HEADERS_EXTRA_FALSE DEBUG_FLAGS GLIBCXX_BUILD_DEBUG_TRUE GLIBCXX_BUILD_DEBUG_FALSE ENABLE_PARALLEL_TRUE ENABLE_PARALLEL_FALSE EXTRA_CXX_FLAGS glibcxx_thread_h WERROR SECTION_FLAGS SECTION_LDFLAGS OPT_LDFLAGS LIBMATHOBJS LIBICONV LTLIBICONV SYMVER_FILE port_specific_symbol_files ENABLE_SYMVERS_TRUE ENABLE_SYMVERS_FALSE ENABLE_SYMVERS_GNU_TRUE ENABLE_SYMVERS_GNU_FALSE ENABLE_SYMVERS_GNU_NAMESPACE_TRUE ENABLE_SYMVERS_GNU_NAMESPACE_FALSE ENABLE_SYMVERS_DARWIN_TRUE ENABLE_SYMVERS_DARWIN_FALSE ENABLE_VISIBILITY_TRUE ENABLE_VISIBILITY_FALSE GLIBCXX_LDBL_COMPAT_TRUE GLIBCXX_LDBL_COMPAT_FALSE baseline_dir ATOMICITY_SRCDIR ATOMIC_WORD_SRCDIR ATOMIC_FLAGS CPU_DEFINES_SRCDIR ABI_TWEAKS_SRCDIR OS_INC_SRCDIR ERROR_CONSTANTS_SRCDIR glibcxx_prefixdir gxx_include_dir glibcxx_toolexecdir glibcxx_toolexeclibdir GLIBCXX_INCLUDES TOPLEVEL_INCLUDES OPTIMIZE_CXXFLAGS WARN_FLAGS LIBSUPCXX_PICFLAGS LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@ -13949,7 +13949,7 @@ echo "${ECHO_T}$enable_libstdcxx_pch" >&6
if test $enable_libstdcxx_pch = yes; then
glibcxx_PCHFLAGS="-include bits/stdtr1c++.h"
glibcxx_PCHFLAGS="-include bits/stdc++.h"
else
glibcxx_PCHFLAGS=""
fi
@ -16468,6 +16468,19 @@ fi;
echo "${ECHO_T}$enable_libstdcxx_debug" >&6
enable_parallel=no;
if test -f "${glibcxx_builddir}/../libgomp/omp.h"; then
enable_parallel=yes;
fi
echo "$as_me:$LINENO: checking for parallel mode support" >&5
echo $ECHO_N "checking for parallel mode support... $ECHO_C" >&6
echo "$as_me:$LINENO: result: $enable_parallel" >&5
echo "${ECHO_T}$enable_parallel" >&6
echo "$as_me:$LINENO: checking for extra compiler flags for building" >&5
echo $ECHO_N "checking for extra compiler flags for building... $ECHO_C" >&6
# Check whether --enable-cxx-flags or --disable-cxx-flags was given.
@ -17279,7 +17292,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
# Fake what AC_TRY_COMPILE does. XXX Look at redoing this new-style.
cat > conftest.$ac_ext << EOF
#line 17282 "configure"
#line 17295 "configure"
int main()
{
// NB: _Atomic_word not necessarily int.
@ -93897,6 +93910,7 @@ done
# Propagate the target-specific source directories through the build chain.
ATOMICITY_SRCDIR=config/${atomicity_dir}
ATOMIC_WORD_SRCDIR=config/${atomic_word_dir}
ATOMIC_FLAGS=${atomic_flags}
CPU_DEFINES_SRCDIR=config/${cpu_defines_dir}
OS_INC_SRCDIR=config/${os_include_dir}
ERROR_CONSTANTS_SRCDIR=config/${error_constants_dir}
@ -93909,6 +93923,7 @@ ABI_TWEAKS_SRCDIR=config/${abi_tweaks_dir}
# Determine cross-compile flags and AM_CONDITIONALs.
#AC_SUBST(GLIBCXX_IS_NATIVE)
#AM_CONDITIONAL(CANADIAN, test $CANADIAN = yes)
@ -94004,6 +94019,17 @@ fi
if test $enable_parallel = yes; then
ENABLE_PARALLEL_TRUE=
ENABLE_PARALLEL_FALSE='#'
else
ENABLE_PARALLEL_TRUE='#'
ENABLE_PARALLEL_FALSE=
fi
if test $enable_symvers != no; then
ENABLE_SYMVERS_TRUE=
ENABLE_SYMVERS_FALSE='#'
@ -94429,6 +94455,13 @@ echo "$as_me: error: conditional \"GLIBCXX_BUILD_DEBUG\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
if test -z "${ENABLE_PARALLEL_TRUE}" && test -z "${ENABLE_PARALLEL_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"ENABLE_PARALLEL\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
echo "$as_me: error: conditional \"ENABLE_PARALLEL\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
if test -z "${ENABLE_SYMVERS_TRUE}" && test -z "${ENABLE_SYMVERS_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"ENABLE_SYMVERS\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
@ -95474,6 +95507,8 @@ s,@GLIBCXX_C_HEADERS_EXTRA_FALSE@,$GLIBCXX_C_HEADERS_EXTRA_FALSE,;t t
s,@DEBUG_FLAGS@,$DEBUG_FLAGS,;t t
s,@GLIBCXX_BUILD_DEBUG_TRUE@,$GLIBCXX_BUILD_DEBUG_TRUE,;t t
s,@GLIBCXX_BUILD_DEBUG_FALSE@,$GLIBCXX_BUILD_DEBUG_FALSE,;t t
s,@ENABLE_PARALLEL_TRUE@,$ENABLE_PARALLEL_TRUE,;t t
s,@ENABLE_PARALLEL_FALSE@,$ENABLE_PARALLEL_FALSE,;t t
s,@EXTRA_CXX_FLAGS@,$EXTRA_CXX_FLAGS,;t t
s,@glibcxx_thread_h@,$glibcxx_thread_h,;t t
s,@WERROR@,$WERROR,;t t
@ -95500,6 +95535,7 @@ s,@GLIBCXX_LDBL_COMPAT_FALSE@,$GLIBCXX_LDBL_COMPAT_FALSE,;t t
s,@baseline_dir@,$baseline_dir,;t t
s,@ATOMICITY_SRCDIR@,$ATOMICITY_SRCDIR,;t t
s,@ATOMIC_WORD_SRCDIR@,$ATOMIC_WORD_SRCDIR,;t t
s,@ATOMIC_FLAGS@,$ATOMIC_FLAGS,;t t
s,@CPU_DEFINES_SRCDIR@,$CPU_DEFINES_SRCDIR,;t t
s,@ABI_TWEAKS_SRCDIR@,$ABI_TWEAKS_SRCDIR,;t t
s,@OS_INC_SRCDIR@,$OS_INC_SRCDIR,;t t

View File

@ -107,6 +107,7 @@ GLIBCXX_ENABLE_C99([yes])
GLIBCXX_ENABLE_CONCEPT_CHECKS([no])
GLIBCXX_ENABLE_DEBUG_FLAGS(["-g3 -O0"])
GLIBCXX_ENABLE_DEBUG([no])
GLIBCXX_ENABLE_PARALLEL
GLIBCXX_ENABLE_CXX_FLAGS
GLIBCXX_ENABLE_FULLY_DYNAMIC_STRING([no])
@ -327,12 +328,14 @@ GLIBCXX_CONFIGURE_TESTSUITE
# Propagate the target-specific source directories through the build chain.
ATOMICITY_SRCDIR=config/${atomicity_dir}
ATOMIC_WORD_SRCDIR=config/${atomic_word_dir}
ATOMIC_FLAGS=${atomic_flags}
CPU_DEFINES_SRCDIR=config/${cpu_defines_dir}
OS_INC_SRCDIR=config/${os_include_dir}
ERROR_CONSTANTS_SRCDIR=config/${error_constants_dir}
ABI_TWEAKS_SRCDIR=config/${abi_tweaks_dir}
AC_SUBST(ATOMICITY_SRCDIR)
AC_SUBST(ATOMIC_WORD_SRCDIR)
AC_SUBST(ATOMIC_FLAGS)
AC_SUBST(CPU_DEFINES_SRCDIR)
AC_SUBST(ABI_TWEAKS_SRCDIR)
AC_SUBST(OS_INC_SRCDIR)

View File

@ -39,6 +39,9 @@
# atomic_word_dir location of atomic_word.h
# defaults to generic.
#
# atomic_flags extra flags to pass to use atomic instructions
# defaults to nothing.
#
# cpu_defines_dir location of cpu_defines.h
# defaults to generic.
#
@ -71,6 +74,7 @@
c_model=c_global
c_compatibility=no
atomic_word_dir=cpu/generic
atomic_flags=""
atomicity_dir="cpu/generic"
cpu_defines_dir="cpu/generic"
try_cpu=generic
@ -130,7 +134,8 @@ case "${host_cpu}" in
esac
# Set specific CPU overrides for atomic_word_dir. Most can just use generic.
# Set specific CPU overrides for atomic_word_dir and atomic_flags.
# Most can just use generic.
# THIS TABLE IS SORTED. KEEP IT THAT WAY.
case "${host_cpu}" in
alpha*)
@ -142,11 +147,15 @@ case "${host_cpu}" in
ia64)
atomic_word_dir=cpu/ia64
;;
i[567]86 | x86_64)
atomic_flags="-march=native"
;;
powerpc* | rs6000)
atomic_word_dir=cpu/powerpc
;;
sparc* | ultrasparc)
atomic_word_dir=cpu/sparc
atomic_flags="-mcpu=v9"
;;
esac

View File

@ -45,7 +45,7 @@
* export. Used only when anonymous namespaces cannot be substituted.
*/
/** @namespace __gnu_debug
* @brief GNU debug mode classes for public use.
* @brief GNU debug classes for public use.
*/
// // // // // // // // // // // // // // // // // // // // // // // //
/** @addtogroup SGIextensions STL extensions from SGI

View File

@ -478,6 +478,7 @@ INPUT = @srcdir@/docs/doxygen/doxygroups.cc \
include/@host_alias@/bits \
include/bits \
include/debug \
include/parallel \
include/ext \
include/tr1 \
include/tr1_impl \
@ -562,6 +563,8 @@ INPUT = @srcdir@/docs/doxygen/doxygroups.cc \
include/ext/slist \
include/ext/pb_ds \
include/ext/pb_ds/detail \
include/parallel/algorithm \
include/parallel/numeric \
include/tr1/array \
include/tr1/ccomplex \
include/tr1/cctype \

View File

@ -222,13 +222,15 @@
</ul>
</li>
<li>Extensions to the Standard Library
<li>Extensions
<ul>
<li><a href="ext/howto.html#4">Compile-time checks</a></li>
<li><a href="debug_mode.html">Debug mode</a></li>
<li><a href="parallel_mode.html">Parallel mode</a></li>
<li><a href="ext/pb_ds/index.html">Policy Based Data Structures</a></li>
<li><a href="ext/howto.html#1">Ropes and trees and hashes, oh my!</a></li>
<li><a href="ext/howto.html#2">Added members and types</a></li>
<li><a href="ext/mt_allocator.html"><code>__mt_alloc</code> </a></li>
<li><a href="ext/howto.html#4">Compile-time checks</a></li>
<li><a href="ext/howto.html#5">LWG Issues</a></li>
<li><a href="ext/../18_support/howto.html#6">Demangling</a></li>
</ul>

View File

@ -0,0 +1,457 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta name="AUTHOR" content="bkoz@gcc.gnu.org (Benjamin Kosnik)" />
<meta name="KEYWORDS" content="c++, libstdc++, gdb, g++, debug" />
<meta name="DESCRIPTION" content="The libstdc++ parallel mode." />
<meta name="GENERATOR" content="emacs and ten fingers" />
<title>The libstdc++ parallel mode</title>
<link rel="StyleSheet" href="lib3styles.css" type="text/css" />
<link rel="Copyright" href="17_intro/license.html" type="text/html" />
</head>
<body>
<h1 class="centered"><a name="top">The libstdc++ parallel mode</a></h1>
<p class="fineprint"><em>
The latest version of this document is always available at
<a href="http://gcc.gnu.org/onlinedocs/libstdc++/parallel_mode.html">
http://gcc.gnu.org/onlinedocs/libstdc++/parallel_mode.html</a>.
</em></p>
<p><em>
To the <a href="http://gcc.gnu.org/libstdc++/">libstdc++-v3 homepage</a>.
</em></p>
<!-- ####################################################### -->
<hr />
<p> The libstdc++ parallel mode is an experimental parallel
implementation of many algorithms the C++ Standard Library.
</p>
<p>
Several of the standard algorithms, for instance
<code>std::search</code>, are made parallel using OpenMP
annotations. These parallel mode constructs and can be invoked by
explicit source declaration or by compiling existing sources with a
specific compiler flag.
</p>
<h3 class="left"><a name="parallel">The libstdc++ parallel mode</a></h3>
<p>The libstdc++ parallel mode performs parallization of algorithms,
function objects, classes, and functions in the C++ Standard.</p>
<h4 class="left">Using the libstdc++ parallel mode</h4>
<p>To use the libstdc++ parallel mode, compile your application with
the compiler flag <code>-D_GLIBCXX_PARALLEL -fopenmp</code>. This
will link in <code>libgomp</code>, the GNU OpenMP <a
href="http://gcc.gnu.org/onlinedocs/libgomp">implementation</a>,
whose presence is mandatory. In addition, hardware capable of atomic
operations is de rigueur. Actually activating these atomic
operations may require explicit compiler flags on some targets
(like sparc and x86), such as <code>-march=i686</code>,
<code>-march=native</code> or <code>-mcpu=v9</code>.
</p>
<p>Note that the <code>_GLIBCXX_PARALLEL</code> define may change the
sizes and behavior of standard class templates such as
<code>std::search</code>, and therefore one can only link code
compiled with parallel mode and code compiled without parallel mode
if no instantiation of a container is passed between the two
translation units. Parallel mode functionality has distinct linkage,
and cannot be confused with normal mode symbols.</p>
<p>The following library components in the include
<code>&lt;numeric&gt;</code> are included in the parallel mode:</p>
<ul>
<li><code>std::accumulate</code></li>
<li><code>std::adjacent_difference</code></li>
<li><code>std::inner_product</code></li>
<li><code>std::partial_sum</code></li>
</ul>
<p>The following library components in the include
<code>&lt;algorithm&gt;</code> are included in the parallel mode:</p>
<ul>
<li><code>std::adjacent_find</code></li>
<li><code>std::count</code></li>
<li><code>std::count_if</code></li>
<li><code>std::equal</code></li>
<li><code>std::find</code></li>
<li><code>std::find_if</code></li>
<li><code>std::find_first_of</code></li>
<li><code>std::for_each</code></li>
<li><code>std::generate</code></li>
<li><code>std::generate_n</code></li>
<li><code>std::lexicographical_compare</code></li>
<li><code>std::mismatch</code></li>
<li><code>std::search</code></li>
<li><code>std::search_n</code></li>
<li><code>std::transform</code></li>
<li><code>std::replace</code></li>
<li><code>std::replace_if</code></li>
<li><code>std::max_element</code></li>
<li><code>std::merge</code></li>
<li><code>std::min_element</code></li>
<li><code>std::nth_element</code></li>
<li><code>std::partial_sort</code></li>
<li><code>std::partition</code></li>
<li><code>std::random_shuffle</code></li>
<li><code>std::set_union</code></li>
<li><code>std::set_intersection</code></li>
<li><code>std::set_symmetric_difference</code></li>
<li><code>std::set_difference</code></li>
<li><code>std::sort</code></li>
<li><code>std::stable_sort</code></li>
<li><code>std::unique_copy</code></li>
</ul>
<h4 class="left">Using the parallel algorithms without parallel mode</h4>
<p>When it is not feasible to recompile your entire application, or
only specific algorithms need to be parallel-aware, individual
parallel algorithms can be made available explicitly. These
parallel algorithms are functionally equivalent to the standard
drop-in algorithms used in parallel mode, but they are available in
a separate namespace as GNU extensions and may be used in programs
compiled with either release mode or with parallel mode. The
following table provides the names and headers of the parallel
algorithms:
</p>
<table title="Parallel algorithms" border="1">
<tr>
<th>Algorithm</th>
<th>Header</th>
<th>Parallel algorithm</th>
<th>Parallel header</th>
</tr>
<tr>
<td>std::accumulate</td>
<td>&lt;numeric&gt;</td>
<td>__gnu_parallel::accumulate</td>
<td>&lt;parallel/numeric&gt;</td>
</tr>
<tr>
<td>std::adjacent_difference</td>
<td>&lt;numeric&gt;</td>
<td>__gnu_parallel::adjacent_difference</td>
<td>&lt;parallel/numeric&gt;</td>
</tr>
<tr>
<td>std::inner_product</td>
<td>&lt;numeric&gt;</td>
<td>__gnu_parallel::inner_product</td>
<td>&lt;parallel/numeric&gt;</td>
</tr>
<tr>
<td>std::partial_sum</td>
<td>&lt;numeric&gt;</td>
<td>__gnu_parallel::partial_sum</td>
<td>&lt;parallel/numeric&gt;</td>
</tr>
<tr>
<td>std::adjacent_find</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::adjacent_find</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::count</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::count</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::count_if</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::count_if</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::equal</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::equal</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::find</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::find</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::find_if</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::find_if</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::find_first_of</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::find_first_of</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::for_each</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::for_each</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::generate</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::generate</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::generate_n</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::generate_n</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::lexicographical_compare</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::lexicographical_compare</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::mismatch</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::mismatch</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::search</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::search</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::search_n</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::search_n</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::transform</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::transform</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::replace</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::replace</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::replace_if</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::replace_if</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::max_element</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::max_element</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::merge</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::merge</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::min_element</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::min_element</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::nth_element</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::nth_element</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::partial_sort</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::partial_sort</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::partition</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::partition</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::random_shuffle</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::random_shuffle</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::set_union</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::set_union</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::set_intersection</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::set_intersection</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::set_symmetric_difference</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::set_symmetric_difference</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::set_difference</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::set_difference</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::sort</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::sort</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::stable_sort</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::stable_sort</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
<tr>
<td>std::unique_copy</td>
<td>&lt;algorithm&gt;</td>
<td>__gnu_parallel::unique_copy</td>
<td>&lt;parallel/algorithm&gt;</td>
</tr>
</table>
<h4 class="left">Parallel mode semantics</h4>
<p> Something about exception safety, interaction with threads,
etc. Goal is to have the usual constraints of the STL with respect to
exception safety and threads, but add in support for parallel
computing.</p>
<p> Something about compile-time settings and configuration, ie using
<code>__gnu_parallel::Settings</code>. XXX Up in the air.</p>
<h4 class="left">Interface basics and relevant namespaces</h4>
<p> Two namespaces contain the parallel mode:
<code>std::__parallel</code> and <code>__gnu_parallel</code>.
</p>
<p> One namespace contain versions of code that are explicitly sequential:
<code>__gnu_serial</code>.
</p>
<p> Parallel implementations of the sequential standard components are
defined in <code>namespace std::__parallel</code>. For instance,
<code>std::transform</code> from &lt;algorithm&gt; has a parallel
counterpart in <code>std::__parallel::transform</code> from
&lt;parallel/algorithm&gt;. In addition, these parallel
implementatations are injected into <code>namespace
__gnu_parallel</code> with using declarations.
</p>
<p> Support and infrastructure is in <code>namespace __gnu_parallel</code>.
</p>
<p> More information, and an organized index of types and functions
related to the parallel mode on a per-namespace basis, can be found in
the generated source documentation.
</p>
<h4 class="left">Testing</h4>
<p> Both the normal conformance and regression tests and the
supplemental performance tests work.</p>
<p> To run the conformance and regression tests with the parallel mode
active,</p>
<code>make check-parallel</code>
<p>The log and summary files for conformance testing are in the
<code>testsuite/parallel</code> directory.</p>
<p> To run the performance tests with the parallel mode active, </p>
<code>make check-performance-parallel</code>
<p>The result file for performance testing are in the
<code>testsuite</code> directory, in the file
<code>libstdc++_performance.sum</code>. In addition, the policy-based
containers have their own visualizations, which have additional
software dependencies than the usual bare-boned text file, and can be
generated by using the <code>make doc-performance</code> rule in the
testsuite's Makefile.</p>
<p>Return <a href="#top">to the top of the page</a> or
<a href="http://gcc.gnu.org/libstdc++/">to the libstdc++ homepage</a>.
</p>
<!-- ####################################################### -->
<hr />
<p class="fineprint"><em>
See <a href="17_intro/license.html">license.html</a> for copying conditions.
Comments and suggestions are welcome, and may be sent to
<a href="mailto:libstdc++@gcc.gnu.org">the libstdc++ mailing list</a>.
</em></p>
</body>
</html>

View File

@ -70,6 +70,7 @@ std_headers = \
bits_srcdir = ${glibcxx_srcdir}/include/bits
bits_builddir = ./bits
bits_headers = \
${bits_srcdir}/algorithmfwd.h \
${bits_srcdir}/allocator.h \
${bits_srcdir}/basic_ios.h \
${bits_srcdir}/basic_ios.tcc \
@ -730,6 +731,58 @@ debug_headers = \
${debug_srcdir}/string \
${debug_srcdir}/vector
# Parallel mode headers
parallel_srcdir = ${glibcxx_srcdir}/include/parallel
parallel_builddir = ./parallel
parallel_headers = \
${parallel_srcdir}/algorithm \
${parallel_srcdir}/algobase.h \
${parallel_srcdir}/algo.h \
${parallel_srcdir}/algorithm \
${parallel_srcdir}/algorithmfwd.h \
${parallel_srcdir}/balanced_quicksort.h \
${parallel_srcdir}/base.h \
${parallel_srcdir}/basic_iterator.h \
${parallel_srcdir}/checkers.h \
${parallel_srcdir}/compatibility.h \
${parallel_srcdir}/compiletime_settings.h \
${parallel_srcdir}/equally_split.h \
${parallel_srcdir}/features.h \
${parallel_srcdir}/find.h \
${parallel_srcdir}/find_selectors.h \
${parallel_srcdir}/for_each.h \
${parallel_srcdir}/for_each_selectors.h \
${parallel_srcdir}/iterator.h \
${parallel_srcdir}/list_partition.h \
${parallel_srcdir}/losertree.h \
${parallel_srcdir}/merge.h \
${parallel_srcdir}/multiseq_selection.h \
${parallel_srcdir}/multiway_merge.h \
${parallel_srcdir}/multiway_mergesort.h \
${parallel_srcdir}/numeric \
${parallel_srcdir}/numericfwd.h \
${parallel_srcdir}/omp_loop.h \
${parallel_srcdir}/omp_loop_static.h \
${parallel_srcdir}/parallel.h \
${parallel_srcdir}/par_loop.h \
${parallel_srcdir}/partial_sum.h \
${parallel_srcdir}/partition.h \
${parallel_srcdir}/queue.h \
${parallel_srcdir}/quicksort.h \
${parallel_srcdir}/random_number.h \
${parallel_srcdir}/random_shuffle.h \
${parallel_srcdir}/search.h \
${parallel_srcdir}/set_operations.h \
${parallel_srcdir}/settings.h \
${parallel_srcdir}/sort.h \
${parallel_srcdir}/tags.h \
${parallel_srcdir}/timing.h \
${parallel_srcdir}/tree.h \
${parallel_srcdir}/types.h \
${parallel_srcdir}/unique_copy.h \
${parallel_srcdir}/workstealing.h
# Some of the different "C" header models need extra files.
# Some "C" header schemes require the "C" compatibility headers.
# For --enable-cheaders=c_std
@ -791,7 +844,8 @@ pch1_output_anchor = ${host_builddir}/stdc++.h
pch1_output_installdir = ${host_installdir}/stdc++.h.gch
pch1a_output = ${pch1_output_builddir}/O0g.gch
pch1b_output = ${pch1_output_builddir}/O2g.gch
pch1_output = ${pch1a_output} ${pch1b_output}
pch1c_output = ${pch1_output_builddir}/O2gp.gch
pch1_output = ${pch1a_output} ${pch1b_output} ${pch1c_output}
pch2_source = ${glibcxx_srcdir}/include/precompiled/stdtr1c++.h
pch2_output_builddir = ${host_builddir}/stdtr1c++.h.gch
@ -823,7 +877,7 @@ endif
allstamped = \
stamp-std stamp-bits stamp-c_base stamp-c_base_extra \
stamp-c_compatibility stamp-backward stamp-ext stamp-pb \
stamp-tr1 stamp-tr1-impl stamp-debug stamp-host
stamp-tr1 stamp-tr1-impl stamp-debug stamp-parallel stamp-host
# List of all files that are created by explicit building, editing, or
# catenation.
@ -980,6 +1034,15 @@ stamp-debug: ${debug_headers}
fi ;\
$(STAMP) stamp-debug
stamp-parallel: ${parallel_headers}
@if [ ! -d "${parallel_builddir}" ]; then \
mkdir -p ${parallel_builddir} ;\
fi ;\
if [ ! -f stamp-parallel ]; then \
(cd ${parallel_builddir} && @LN_S@ $? . || true) ;\
fi ;\
$(STAMP) stamp-parallel
stamp-${host_alias}:
@if [ ! -d ${host_builddir} ]; then \
mkdir -p ${host_builddir} ;\
@ -1091,7 +1154,7 @@ ${host_builddir}/gthr-default.h: ${toplevel_srcdir}/gcc/${glibcxx_thread_h} \
-e 's,^#include "\(.*\)",#include <bits/\1>,g' \
< ${toplevel_srcdir}/gcc/${glibcxx_thread_h} > $@
# Build two precompiled C++ includes, stdc++.h.gch/*.gch
# Build three precompiled C++ includes, stdc++.h.gch/*.gch
${pch1a_output}: ${allstamped} ${host_builddir}/c++config.h ${pch1_source}
if [ ! -d "${pch1_output_builddir}" ]; then \
mkdir -p ${pch1_output_builddir}; \
@ -1106,6 +1169,14 @@ ${pch1b_output}: ${allstamped} ${host_builddir}/c++config.h ${pch1_source}
$(CXX) $(PCHFLAGS) $(AM_CPPFLAGS) -O2 -g ${pch1_source} -o $@
touch ${pch1_output_anchor}
${pch1c_output}: ${allstamped} ${host_builddir}/c++config.h ${pch1_source}
if [ ! -d "${pch1_output_builddir}" ]; then \
mkdir -p ${pch1_output_builddir}; \
fi; \
CXX_PARALLEL_FLAGS="-fgomp -march=native";
$(CXX) $(PCHFLAGS) $(AM_CPPFLAGS) -O2 -g $(CXX_PARALLEL_FLAGS) ${pch1_source} -o $@
touch ${pch1_output_anchor}
# Build a precompiled TR1 include, stdtr1c++.h.gch/O2.gch
${pch2_output}: ${pch2_source} ${pch1_output}
if [ ! -d "${pch2_output_builddir}" ]; then \
@ -1217,6 +1288,9 @@ install-headers:
$(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${debug_builddir}
for file in ${debug_headers}; do \
$(INSTALL_DATA) $${file} $(DESTDIR)${gxx_include_dir}/${debug_builddir}; done
$(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${parallel_builddir}
for file in ${parallel_headers}; do \
$(INSTALL_DATA) $${file} $(DESTDIR)${gxx_include_dir}/${parallel_builddir}; done
$(mkinstalldirs) $(DESTDIR)${host_installdir}
for file in ${host_headers} ${host_headers_extra} \
${thread_host_headers}; do \

View File

@ -71,6 +71,7 @@ AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
ATOMICITY_SRCDIR = @ATOMICITY_SRCDIR@
ATOMIC_FLAGS = @ATOMIC_FLAGS@
ATOMIC_WORD_SRCDIR = @ATOMIC_WORD_SRCDIR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@ -108,6 +109,8 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
ENABLE_PARALLEL_FALSE = @ENABLE_PARALLEL_FALSE@
ENABLE_PARALLEL_TRUE = @ENABLE_PARALLEL_TRUE@
ENABLE_SYMVERS_DARWIN_FALSE = @ENABLE_SYMVERS_DARWIN_FALSE@
ENABLE_SYMVERS_DARWIN_TRUE = @ENABLE_SYMVERS_DARWIN_TRUE@
ENABLE_SYMVERS_FALSE = @ENABLE_SYMVERS_FALSE@
@ -316,6 +319,7 @@ std_headers = \
bits_srcdir = ${glibcxx_srcdir}/include/bits
bits_builddir = ./bits
bits_headers = \
${bits_srcdir}/algorithmfwd.h \
${bits_srcdir}/allocator.h \
${bits_srcdir}/basic_ios.h \
${bits_srcdir}/basic_ios.tcc \
@ -965,6 +969,58 @@ debug_headers = \
${debug_srcdir}/string \
${debug_srcdir}/vector
# Parallel mode headers
parallel_srcdir = ${glibcxx_srcdir}/include/parallel
parallel_builddir = ./parallel
parallel_headers = \
${parallel_srcdir}/algorithm \
${parallel_srcdir}/algobase.h \
${parallel_srcdir}/algo.h \
${parallel_srcdir}/algorithm \
${parallel_srcdir}/algorithmfwd.h \
${parallel_srcdir}/balanced_quicksort.h \
${parallel_srcdir}/base.h \
${parallel_srcdir}/basic_iterator.h \
${parallel_srcdir}/checkers.h \
${parallel_srcdir}/compatibility.h \
${parallel_srcdir}/compiletime_settings.h \
${parallel_srcdir}/equally_split.h \
${parallel_srcdir}/features.h \
${parallel_srcdir}/find.h \
${parallel_srcdir}/find_selectors.h \
${parallel_srcdir}/for_each.h \
${parallel_srcdir}/for_each_selectors.h \
${parallel_srcdir}/iterator.h \
${parallel_srcdir}/list_partition.h \
${parallel_srcdir}/losertree.h \
${parallel_srcdir}/merge.h \
${parallel_srcdir}/multiseq_selection.h \
${parallel_srcdir}/multiway_merge.h \
${parallel_srcdir}/multiway_mergesort.h \
${parallel_srcdir}/numeric \
${parallel_srcdir}/numericfwd.h \
${parallel_srcdir}/omp_loop.h \
${parallel_srcdir}/omp_loop_static.h \
${parallel_srcdir}/parallel.h \
${parallel_srcdir}/par_loop.h \
${parallel_srcdir}/partial_sum.h \
${parallel_srcdir}/partition.h \
${parallel_srcdir}/queue.h \
${parallel_srcdir}/quicksort.h \
${parallel_srcdir}/random_number.h \
${parallel_srcdir}/random_shuffle.h \
${parallel_srcdir}/search.h \
${parallel_srcdir}/set_operations.h \
${parallel_srcdir}/settings.h \
${parallel_srcdir}/sort.h \
${parallel_srcdir}/tags.h \
${parallel_srcdir}/timing.h \
${parallel_srcdir}/tree.h \
${parallel_srcdir}/types.h \
${parallel_srcdir}/unique_copy.h \
${parallel_srcdir}/workstealing.h
@GLIBCXX_C_HEADERS_EXTRA_FALSE@c_base_headers_extra =
# Some of the different "C" header models need extra files.
@ -1020,7 +1076,8 @@ pch1_output_anchor = ${host_builddir}/stdc++.h
pch1_output_installdir = ${host_installdir}/stdc++.h.gch
pch1a_output = ${pch1_output_builddir}/O0g.gch
pch1b_output = ${pch1_output_builddir}/O2g.gch
pch1_output = ${pch1a_output} ${pch1b_output}
pch1c_output = ${pch1_output_builddir}/O2gp.gch
pch1_output = ${pch1a_output} ${pch1b_output} ${pch1c_output}
pch2_source = ${glibcxx_srcdir}/include/precompiled/stdtr1c++.h
pch2_output_builddir = ${host_builddir}/stdtr1c++.h.gch
pch2_output_anchor = ${host_builddir}/stdtr1c++.h
@ -1047,7 +1104,7 @@ PCHFLAGS = -Winvalid-pch -Wno-deprecated -x c++-header $(CXXFLAGS)
allstamped = \
stamp-std stamp-bits stamp-c_base stamp-c_base_extra \
stamp-c_compatibility stamp-backward stamp-ext stamp-pb \
stamp-tr1 stamp-tr1-impl stamp-debug stamp-host
stamp-tr1 stamp-tr1-impl stamp-debug stamp-parallel stamp-host
# List of all files that are created by explicit building, editing, or
@ -1374,6 +1431,15 @@ stamp-debug: ${debug_headers}
fi ;\
$(STAMP) stamp-debug
stamp-parallel: ${parallel_headers}
@if [ ! -d "${parallel_builddir}" ]; then \
mkdir -p ${parallel_builddir} ;\
fi ;\
if [ ! -f stamp-parallel ]; then \
(cd ${parallel_builddir} && @LN_S@ $? . || true) ;\
fi ;\
$(STAMP) stamp-parallel
stamp-${host_alias}:
@if [ ! -d ${host_builddir} ]; then \
mkdir -p ${host_builddir} ;\
@ -1476,7 +1542,7 @@ ${host_builddir}/gthr-default.h: ${toplevel_srcdir}/gcc/${glibcxx_thread_h} \
-e 's,^#include "\(.*\)",#include <bits/\1>,g' \
< ${toplevel_srcdir}/gcc/${glibcxx_thread_h} > $@
# Build two precompiled C++ includes, stdc++.h.gch/*.gch
# Build three precompiled C++ includes, stdc++.h.gch/*.gch
${pch1a_output}: ${allstamped} ${host_builddir}/c++config.h ${pch1_source}
if [ ! -d "${pch1_output_builddir}" ]; then \
mkdir -p ${pch1_output_builddir}; \
@ -1491,6 +1557,14 @@ ${pch1b_output}: ${allstamped} ${host_builddir}/c++config.h ${pch1_source}
$(CXX) $(PCHFLAGS) $(AM_CPPFLAGS) -O2 -g ${pch1_source} -o $@
touch ${pch1_output_anchor}
${pch1c_output}: ${allstamped} ${host_builddir}/c++config.h ${pch1_source}
if [ ! -d "${pch1_output_builddir}" ]; then \
mkdir -p ${pch1_output_builddir}; \
fi; \
CXX_PARALLEL_FLAGS="-fgomp -march=native";
$(CXX) $(PCHFLAGS) $(AM_CPPFLAGS) -O2 -g $(CXX_PARALLEL_FLAGS) ${pch1_source} -o $@
touch ${pch1_output_anchor}
# Build a precompiled TR1 include, stdtr1c++.h.gch/O2.gch
${pch2_output}: ${pch2_source} ${pch1_output}
if [ ! -d "${pch2_output_builddir}" ]; then \
@ -1599,6 +1673,9 @@ install-headers:
$(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${debug_builddir}
for file in ${debug_headers}; do \
$(INSTALL_DATA) $${file} $(DESTDIR)${gxx_include_dir}/${debug_builddir}; done
$(mkinstalldirs) $(DESTDIR)${gxx_include_dir}/${parallel_builddir}
for file in ${parallel_headers}; do \
$(INSTALL_DATA) $${file} $(DESTDIR)${gxx_include_dir}/${parallel_builddir}; done
$(mkinstalldirs) $(DESTDIR)${host_installdir}
for file in ${host_headers} ${host_headers_extra} \
${thread_host_headers}; do \

View File

@ -0,0 +1,597 @@
// <algorithm> declarations -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING. If not, write to the Free
// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
// USA.
/** @file bits/algorithmfwd.h
* This is an internal header file, included by other library headers.
* You should not attempt to use it directly.
*/
/*
adjacent_find
binary_search
copy
copy_backward
count
count_if
equal
equal_range
fill
fill_n
find
find_end
find_first_of
find_if
for_each
generate
generate_n
includes
inplace_merge
iter_swap
lexicographical_compare
lower_bound
make_heap
max
max_element
merge
min
min_element
mismatch
next_permutation
nth_element
parital_sort
partial_sort_copy
partition
pop_heap
prev_permutation
push_heap
random_shuffle
remove
remove_copy
remove_copy_if
remove_if
replace
replace_copy
replace_copy_if
replace_if
reverse
reverse_copy
rotate
rotate_copy
search
search_n
set_differernce
set_intersection
set_symmetric_difference
set_union
sort
sort_heap
stable_partition
stable_sort
stable_sort
swap
swap_ranges
transform
unique
unique_copy
upper_bound
*/
#ifndef _GLIBCXX_ALGORITHMFWD_H
#define _GLIBCXX_ALGORITHMFWD_H 1
#pragma GCC system_header
#include <bits/c++config.h>
#include <bits/stl_pair.h>
#include <bits/stl_iterator_base_types.h>
_GLIBCXX_BEGIN_NAMESPACE(std)
// adjacent_find
template<typename _FIter, typename _Tp>
bool
binary_search(_FIter, _FIter, const _Tp&);
template<typename _FIter, typename _Tp, typename _Compare>
bool
binary_search(_FIter, _FIter, const _Tp&, _Compare);
template<typename _IIter, typename _OIter>
_OIter
copy(_IIter, _IIter, _OIter);
template<typename _BIter1, typename _BIter2>
_BIter2
copy_backward (_BIter1, _BIter1, _BIter2);
// count
// count_if
template<typename _FIter, typename _Tp>
pair<_FIter, _FIter>
equal_range(_FIter, _FIter, const _Tp&);
template<typename _FIter, typename _Tp, typename _Compare>
pair<_FIter, _FIter>
equal_range(_FIter, _FIter, const _Tp&, _Compare);
template<typename _FIter, typename _Tp>
void
fill(_FIter, _FIter, const _Tp&);
/*
XXX NB: return type different from ISO C++.
template<typename _OIter, typename _Size, typename _Tp>
void
fill_n(_OIter, _Size, const _Tp&);
*/
template<typename _OIter, typename _Size, typename _Tp>
_OIter
fill_n(_OIter, _Size, const _Tp&);
// find
// find_end
// find_first_of
// find_if
// for_each
// generate
// generate_n
template<typename _IIter1, typename _IIter2>
bool
includes(_IIter1, _IIter1, _IIter2, _IIter2);
template<typename _IIter1, typename _IIter2, typename _Compare>
bool
includes(_IIter1, _IIter1, _IIter2, _IIter2, _Compare);
template<typename _BIter>
void
inplace_merge(_BIter, _BIter, _BIter);
template<typename _BIter, typename _Compare>
void
inplace_merge(_BIter, _BIter, _BIter, _Compare);
template<typename _FIter1, typename _FIter2>
void
iter_swap(_FIter1, _FIter2);
// Specializations for char and unsigned char.
inline bool
lexicographical_compare(const unsigned char*, const unsigned char*,
const unsigned char*, const unsigned char*);
inline bool
lexicographical_compare(const char*, const char*, const char*, const char*);
template<typename _FIter, typename _Tp>
_FIter
lower_bound(_FIter, _FIter, const _Tp&);
template<typename _FIter, typename _Tp, typename _Compare>
_FIter
lower_bound(_FIter, _FIter, const _Tp&, _Compare);
template<typename _RAIter>
void
make_heap(_RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
make_heap(_RAIter, _RAIter, _Compare);
template<typename _Tp>
const _Tp&
max(const _Tp&, const _Tp&);
template<typename _Tp, typename _Compare>
const _Tp&
max(const _Tp&, const _Tp&, _Compare);
// max_element
// merge
template<typename _Tp>
const _Tp&
min(const _Tp&, const _Tp&);
template<typename _Tp, typename _Compare>
const _Tp&
min(const _Tp&, const _Tp&, _Compare);
// min_element
// mismatch
template<typename _BIter>
bool
next_permutation(_BIter, _BIter);
template<typename _BIter, typename _Compare>
bool
next_permutation(_BIter, _BIter, _Compare);
// nth_element
// partial_sort
template<typename _IIter, typename _RAIter>
_RAIter
partial_sort_copy(_IIter, _IIter, _RAIter, _RAIter);
template<typename _IIter, typename _RAIter, typename _Compare>
_RAIter
partial_sort_copy(_IIter, _IIter, _RAIter, _RAIter, _Compare);
template<typename _RAIter>
void
pop_heap(_RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
pop_heap(_RAIter, _RAIter, _Compare);
template<typename _BIter>
bool
prev_permutation(_BIter, _BIter);
template<typename _BIter, typename _Compare>
bool
prev_permutation(_BIter, _BIter, _Compare);
template<typename _RAIter>
void
push_heap(_RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
push_heap(_RAIter, _RAIter, _Compare);
// random_shuffle
template<typename _FIter, typename _Tp>
_FIter
remove(_FIter, _FIter, const _Tp&);
template<typename _FIter, typename _Predicate>
_FIter
remove_if(_FIter, _FIter, _Predicate);
template<typename _IIter, typename _OIter, typename _Tp>
_OIter
remove_copy(_IIter, _IIter, _OIter, const _Tp&);
template<typename _IIter, typename _OIter, typename _Predicate>
_OIter
remove_copy_if(_IIter, _IIter, _OIter, _Predicate);
// replace
template<typename _IIter, typename _OIter, typename _Tp>
_OIter
replace_copy(_IIter, _IIter, _OIter, const _Tp&, const _Tp&);
template<typename _Iter, typename _OIter, typename _Predicate, typename _Tp>
_OIter
replace_copy_if(_Iter, _Iter, _OIter, _Predicate, const _Tp&);
// replace_if
template<typename _BIter>
void
reverse(_BIter, _BIter);
template<typename _BIter, typename _OIter>
_OIter
reverse_copy(_BIter, _BIter, _OIter);
template<typename _FIter>
void
rotate(_FIter, _FIter, _FIter);
template<typename _FIter, typename _OIter>
_OIter
rotate_copy (_FIter, _FIter, _FIter, _OIter);
// search
// search_n
// set_difference
// set_intersection
// set_symmetric_difference
// set_union
template<typename _RAIter>
void
sort_heap(_RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
sort_heap(_RAIter, _RAIter, _Compare);
template<typename _BIter, typename _Predicate>
_BIter
stable_partition(_BIter, _BIter, _Predicate);
template<typename _Tp>
void
swap(_Tp&, _Tp& b);
template<typename _FIter1, typename _FIter2>
_FIter2
swap_ranges(_FIter1 first1, _FIter1, _FIter2);
// transform
template<typename _FIter>
_FIter
unique(_FIter, _FIter);
template<typename _FIter, typename _BinaryPredicate>
_FIter
unique(_FIter, _FIter, _BinaryPredicate);
// unique_copy
template<typename _FIter, typename _Tp>
_FIter
upper_bound(_FIter, _FIter, const _Tp&);
template<typename _FIter, typename _Tp, typename _Compare>
_FIter
upper_bound(_FIter, _FIter, const _Tp&, _Compare);
_GLIBCXX_END_NAMESPACE
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_P)
template<typename _FIter>
_FIter
adjacent_find(_FIter, _FIter);
template<typename _FIter, typename _BinaryPredicate>
_FIter
adjacent_find(_FIter, _FIter, _BinaryPredicate);
template<typename _IIter, typename _Tp>
typename iterator_traits<_IIter>::difference_type
count(_IIter, _IIter, const _Tp&);
template<typename _IIter, typename _Predicate>
typename iterator_traits<_IIter>::difference_type
count_if(_IIter, _IIter, _Predicate);
template<typename _IIter1, typename _IIter2>
bool
equal(_IIter1, _IIter1, _IIter2);
template<typename _IIter1, typename _IIter2, typename _BinaryPredicate>
bool
equal(_IIter1, _IIter1, _IIter2, _BinaryPredicate);
template<typename _IIter, typename _Tp>
_IIter
find(_IIter, _IIter, const _Tp&);
template<typename _FIter1, typename _FIter2>
_FIter1
find_end(_FIter1, _FIter1, _FIter2, _FIter2);
template<typename _FIter1, typename _FIter2, typename _BinaryPredicate>
_FIter1
find_end(_FIter1, _FIter1, _FIter2, _FIter2, _BinaryPredicate);
template<typename _FIter1, typename _FIter2>
_FIter1
find_first_of(_FIter1, _FIter1, _FIter2, _FIter2);
template<typename _FIter1, typename _FIter2, typename _BinaryPredicate>
_FIter1
find_first_of(_FIter1, _FIter1, _FIter2, _FIter2, _BinaryPredicate);
template<typename _IIter, typename _Predicate>
_IIter
find_if(_IIter, _IIter, _Predicate);
template<typename _IIter, typename _Funct>
_Funct
for_each(_IIter, _IIter, _Funct);
template<typename _FIter, typename _Generator>
void
generate(_FIter, _FIter, _Generator);
template<typename _OIter, typename _Size, typename _Generator>
void
generate_n(_OIter, _Size, _Generator);
template<typename _IIter1, typename _IIter2>
bool
lexicographical_compare(_IIter1, _IIter1, _IIter2, _IIter2);
template<typename _IIter1, typename _IIter2, typename _Compare>
bool
lexicographical_compare(_IIter1, _IIter1, _IIter2, _IIter2, _Compare);
template<typename _FIter>
_FIter
max_element(_FIter, _FIter);
template<typename _FIter, typename _Compare>
_FIter
max_element(_FIter, _FIter, _Compare);
template<typename _IIter1, typename _IIter2, typename _OIter>
_OIter
merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter);
template<typename _IIter1, typename _IIter2, typename _OIter,
typename _Compare>
_OIter
merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare);
template<typename _FIter>
_FIter
min_element(_FIter, _FIter);
template<typename _FIter, typename _Compare>
_FIter
min_element(_FIter, _FIter, _Compare);
template<typename _IIter1, typename _IIter2>
pair<_IIter1, _IIter2>
mismatch(_IIter1, _IIter1, _IIter2);
template<typename _IIter1, typename _IIter2, typename _BinaryPredicate>
pair<_IIter1, _IIter2>
mismatch(_IIter1, _IIter1, _IIter2, _BinaryPredicate);
template<typename _RAIter>
void
nth_element(_RAIter, _RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
nth_element(_RAIter, _RAIter, _RAIter, _Compare);
template<typename _RAIter>
void
partial_sort(_RAIter, _RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
partial_sort(_RAIter, _RAIter, _RAIter, _Compare);
template<typename _BIter, typename _Predicate>
_BIter
partition(_BIter, _BIter, _Predicate);
template<typename _RAIter>
void
random_shuffle(_RAIter, _RAIter);
template<typename _RAIter, typename _Generator>
void
random_shuffle(_RAIter, _RAIter, _Generator&);
template<typename _FIter, typename _Tp>
void
replace(_FIter, _FIter, const _Tp&, const _Tp&);
template<typename _FIter, typename _Predicate, typename _Tp>
void
replace_if(_FIter, _FIter, _Predicate, const _Tp&);
template<typename _FIter1, typename _FIter2>
_FIter1
search(_FIter1, _FIter1, _FIter2, _FIter2);
template<typename _FIter1, typename _FIter2, typename _BinaryPredicate>
_FIter1
search(_FIter1, _FIter1, _FIter2, _FIter2, _BinaryPredicate);
template<typename _FIter, typename _Size, typename _Tp>
_FIter
search_n(_FIter, _FIter, _Size, const _Tp&);
template<typename _FIter, typename _Size, typename _Tp,
typename _BinaryPredicate>
_FIter
search_n(_FIter, _FIter, _Size, const _Tp&, _BinaryPredicate);
template<typename _IIter1, typename _IIter2, typename _OIter>
_OIter
set_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter);
template<typename _IIter1, typename _IIter2, typename _OIter,
typename _Compare>
_OIter
set_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare);
template<typename _IIter1, typename _IIter2, typename _OIter>
_OIter
set_intersection(_IIter1, _IIter1, _IIter2, _IIter2, _OIter);
template<typename _IIter1, typename _IIter2, typename _OIter,
typename _Compare>
_OIter
set_intersection(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare);
template<typename _IIter1, typename _IIter2, typename _OIter>
_OIter
set_symmetric_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter);
template<typename _IIter1, typename _IIter2, typename _OIter,
typename _Compare>
_OIter
set_symmetric_difference(_IIter1, _IIter1, _IIter2, _IIter2,
_OIter, _Compare);
template<typename _IIter1, typename _IIter2, typename _OIter>
_OIter
set_union(_IIter1, _IIter1, _IIter2, _IIter2, _OIter);
template<typename _IIter1, typename _IIter2, typename _OIter,
typename _Compare>
_OIter
set_union(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare);
template<typename _RAIter>
void
sort(_RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
sort(_RAIter, _RAIter, _Compare);
template<typename _RAIter>
void
stable_sort(_RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
stable_sort(_RAIter, _RAIter, _Compare);
template<typename _IIter, typename _OIter, typename _UnaryOperation>
_OIter
transform(_IIter, _IIter, _OIter, _UnaryOperation);
template<typename _IIter1, typename _IIter2, typename _OIter,
typename _BinaryOperation>
_OIter
transform(_IIter1, _IIter1, _IIter2, _OIter, _BinaryOperation);
template<typename _IIter, typename _OIter>
_OIter
unique_copy(_IIter, _IIter, _OIter);
template<typename _IIter, typename _OIter, typename _BinaryPredicate>
_OIter
unique_copy(_IIter, _IIter, _OIter, _BinaryPredicate);
_GLIBCXX_END_NESTED_NAMESPACE
#ifdef _GLIBCXX_NAMESPACE_ASSOCIATION_PARALLEL
# include <parallel/algorithmfwd.h>
#endif
#endif

View File

@ -45,16 +45,7 @@
// The current version of the C++ library in compressed ISO date format.
#define __GLIBCXX__
// Macro used to indicate that the native "C" includes, when compiled
// as "C++", have declarations in namespace std and not the global
// namespace. Note, this is unrelated to possible "C" compatibility
// includes that inject C90/C99 names into the global namespace.
// XXX May not be necessary
#if __cplusplus == 199711L
# define _GLIBCXX_NAMESPACE_GLOBAL_INJECTION 1
#endif
// Macros for visibility.
// Macros for visibility support.
#define _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY
#if _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY
@ -63,36 +54,178 @@
# define _GLIBCXX_VISIBILITY(V)
#endif
// Macros for controlling various namespace association schemes and modes.
// Guide to libstdc++ namespaces.
/*
namespace std
{
namespace __debug { }
namespace __parallel { }
namespace __norm { } // __normative, __shadow, __replaced
namespace __cxx1998 { }
namespace tr1 { }
}
namespace __gnu_cxx
{
namespace __debug { }
namespace __norm { }
}
*/
// Macros for activating various namespace association modes.
// _GLIBCXX_NAMESPACE_ASSOCIATION_DEBUG
// _GLIBCXX_NAMESPACE_ASSOCIATION_VERSION
// _GLIBCXX_NAMESPACE_ASSOCIATION_CXX200x
// _GLIBCXX_NAMESPACE_ASSOCIATION_PARALLEL
// _GLIBCXX_NAMESPACE_ASSOCIATION_VERSION
#ifdef _GLIBCXX_DEBUG
# define _GLIBCXX_NAMESPACE_ASSOCIATION_DEBUG 1
#endif
#ifdef _GLIBCXX_PARALLEL
# define _GLIBCXX_NAMESPACE_ASSOCIATION_PARALLEL 1
#endif
#define _GLIBCXX_NAMESPACE_ASSOCIATION_VERSION
// Macros for namespace scope.
// Defined if any namespace association modes are active.
#if _GLIBCXX_NAMESPACE_ASSOCIATION_DEBUG \
|| _GLIBCXX_NAMESPACE_ASSOCIATION_PARALLEL \
|| _GLIBCXX_NAMESPACE_ASSOCIATION_VERSION
# define _GLIBCXX_USE_NAMESPACE_ASSOCIATION 1
#endif
// Macros for namespace scope. Either namespace std:: or __gnu_cxx::,
// or the name of some nested namespace within it.
// _GLIBCXX_STD
// _GLIBCXX_STD_D
// _GLIBCXX_STD_P
// _GLIBCXX_EXT
// _GLIBCXX_EXT_D
// _GLIBCXX_EXT_P
//
// Macros for enclosing namepaces and possibly nested namespaces.
// _GLIBCXX_BEGIN_NAMESPACE
// _GLIBCXX_END_NAMESPACE
// _GLIBCXX_BEGIN_NESTED_NAMESPACE
// _GLIBCXX_END_NESTED_NAMESPACE
#if _GLIBCXX_NAMESPACE_ASSOCIATION_VERSION
// _GLIBCXX_BEGIN_POTENTIAL_NESTED_NAMESPACE
// _GLIBCXX_END_POTENTIAL_NESTED_NAMESPACE
#ifndef _GLIBCXX_USE_NAMESPACE_ASSOCIATION
# define _GLIBCXX_STD_D _GLIBCXX_STD
# define _GLIBCXX_STD_P _GLIBCXX_STD
# define _GLIBCXX_STD std
# define _GLIBCXX_EXT_D _GLIBCXX_EXT
# define _GLIBCXX_EXT_P _GLIBCXX_EXT
# define _GLIBCXX_EXT __gnu_cxx
# define _GLIBCXX_BEGIN_NESTED_NAMESPACE(X, Y) _GLIBCXX_BEGIN_NAMESPACE(X)
# define _GLIBCXX_END_NESTED_NAMESPACE _GLIBCXX_END_NAMESPACE
# define _GLIBCXX_BEGIN_NAMESPACE(X) namespace X _GLIBCXX_VISIBILITY(default) {
# define _GLIBCXX_END_NAMESPACE }
#else
# if _GLIBCXX_NAMESPACE_ASSOCIATION_VERSION // && not anything else
# define _GLIBCXX_STD_D _GLIBCXX_STD
# define _GLIBCXX_STD_P _GLIBCXX_STD
# define _GLIBCXX_STD _6
# define _GLIBCXX_EXT _6
# define _GLIBCXX_BEGIN_NAMESPACE(X) _GLIBCXX_BEGIN_NESTED_NAMESPACE(X, _6)
# define _GLIBCXX_END_NAMESPACE _GLIBCXX_END_NESTED_NAMESPACE
# endif
// debug
# if _GLIBCXX_NAMESPACE_ASSOCIATION_DEBUG && !_GLIBCXX_NAMESPACE_ASSOCIATION_PARALLEL
# define _GLIBCXX_STD_D __norm
# define _GLIBCXX_STD_P _GLIBCXX_STD
# define _GLIBCXX_STD __cxx1998
# define _GLIBCXX_EXT_D __norm
# define _GLIBCXX_EXT_P _GLIBCXX_EXT
# define _GLIBCXX_EXT __cxx1998
# define _GLIBCXX_BEGIN_NAMESPACE(X) namespace X _GLIBCXX_VISIBILITY(default) {
# define _GLIBCXX_END_NAMESPACE }
# define _GLIBCXX_EXTERN_TEMPLATE 0
# endif
// parallel
# if _GLIBCXX_NAMESPACE_ASSOCIATION_PARALLEL && !_GLIBCXX_NAMESPACE_ASSOCIATION_DEBUG
# define _GLIBCXX_STD_D _GLIBCXX_STD
# define _GLIBCXX_STD_P __norm
# define _GLIBCXX_STD __cxx1998
# define _GLIBCXX_EXT_D _GLIBCXX_EXT
# define _GLIBCXX_EXT_P __norm
# define _GLIBCXX_EXT __cxx1998
# define _GLIBCXX_BEGIN_NAMESPACE(X) namespace X _GLIBCXX_VISIBILITY(default) {
# define _GLIBCXX_END_NAMESPACE }
# define _GLIBCXX_EXTERN_TEMPLATE 0
# endif
// debug + parallel
# if _GLIBCXX_NAMESPACE_ASSOCIATION_PARALLEL && _GLIBCXX_NAMESPACE_ASSOCIATION_DEBUG
# define _GLIBCXX_STD_D __norm
# define _GLIBCXX_STD_P __norm
# define _GLIBCXX_STD __cxx1998
# define _GLIBCXX_EXT_D __norm
# define _GLIBCXX_EXT_P __norm
# define _GLIBCXX_EXT __gnu_cxx
# define _GLIBCXX_BEGIN_NAMESPACE(X) namespace X _GLIBCXX_VISIBILITY(default) {
# define _GLIBCXX_END_NAMESPACE }
# define _GLIBCXX_EXTERN_TEMPLATE 0
# endif
# if __NO_INLINE__ && !__GXX_WEAK__
# warning currently using namepace associated mode which may fail \
without inlining due to lack of weak symbols
# endif
# define _GLIBCXX_BEGIN_NESTED_NAMESPACE(X, Y) namespace X { namespace Y _GLIBCXX_VISIBILITY(default) {
# define _GLIBCXX_END_NESTED_NAMESPACE } }
# define _GLIBCXX_BEGIN_NAMESPACE(X) _GLIBCXX_BEGIN_NESTED_NAMESPACE(X, _6)
# define _GLIBCXX_END_NAMESPACE _GLIBCXX_END_NESTED_NAMESPACE
#else
# define _GLIBCXX_BEGIN_NAMESPACE(X) namespace X _GLIBCXX_VISIBILITY(default) {
# define _GLIBCXX_END_NAMESPACE }
# if _GLIBCXX_NAMESPACE_ASSOCIATION_DEBUG
# define _GLIBCXX_BEGIN_NESTED_NAMESPACE(X, Y) namespace X { namespace Y _GLIBCXX_VISIBILITY(default) {
# define _GLIBCXX_END_NESTED_NAMESPACE } }
# else
# define _GLIBCXX_BEGIN_NESTED_NAMESPACE(X, Y) _GLIBCXX_BEGIN_NAMESPACE(X)
# define _GLIBCXX_END_NESTED_NAMESPACE _GLIBCXX_END_NAMESPACE
# endif
#endif
// Namespace associations for debug mode.
#if _GLIBCXX_NAMESPACE_ASSOCIATION_DEBUG
namespace std
{
namespace __norm { }
namespace __debug { }
namespace __cxx1998 { }
using namespace __debug __attribute__ ((strong));
using namespace __cxx1998 __attribute__ ((strong));
}
namespace __gnu_cxx
{
namespace __norm { }
namespace __debug { }
namespace __cxx1998 { }
using namespace __debug __attribute__ ((strong));
using namespace __cxx1998 __attribute__ ((strong));
}
#endif
// Namespace associations for parallel mode.
#if _GLIBCXX_NAMESPACE_ASSOCIATION_PARALLEL
namespace std
{
namespace __norm { }
namespace __parallel { }
namespace __cxx1998 { }
using namespace __parallel __attribute__ ((strong));
using namespace __cxx1998 __attribute__ ((strong));
}
namespace __gnu_cxx
{
namespace __norm { }
namespace __parallel { }
namespace __cxx1998 { }
using namespace __parallel __attribute__ ((strong));
using namespace __cxx1998 __attribute__ ((strong));
}
#endif
// Namespace associations for versioning mode.
@ -119,38 +252,6 @@ namespace std
}
#endif
// Namespace associations for debug mode.
#if _GLIBCXX_NAMESPACE_ASSOCIATION_DEBUG
namespace std
{
namespace __norm { }
namespace __debug { }
using namespace __debug __attribute__ ((strong));
}
namespace __gnu_cxx
{
namespace __norm { }
namespace __debug { }
using namespace __debug __attribute__ ((strong));
}
# define _GLIBCXX_STD __norm
# define _GLIBCXX_EXT __norm
# define _GLIBCXX_EXTERN_TEMPLATE 0
# if __NO_INLINE__ && !__GXX_WEAK__
# warning debug mode without inlining may fail due to lack of weak symbols
# endif
#else
#if _GLIBCXX_NAMESPACE_ASSOCIATION_VERSION
# define _GLIBCXX_STD _6
# define _GLIBCXX_EXT _6
#else
# define _GLIBCXX_STD std
# define _GLIBCXX_EXT __gnu_cxx
#endif
#endif
// Define if compatibility should be provided for -mlong-double-64.
#undef _GLIBCXX_LONG_DOUBLE_COMPAT
@ -193,6 +294,14 @@ _GLIBCXX_END_NAMESPACE
# define _GLIBCXX_WEAK_DEFINITION
#endif
// Macro used to indicate that the native "C" includes, when compiled
// as "C++", have declarations in namespace std and not the global
// namespace. Note, this is unrelated to possible "C" compatibility
// includes that inject C90/C99 names into the global namespace.
#if __cplusplus == 199711L
# define _GLIBCXX_NAMESPACE_GLOBAL_INJECTION 1
#endif
// The remainder of the prewritten config is automatic; all the
// user hooks are listed above.

View File

@ -43,7 +43,7 @@
#pragma GCC system_header
#include <bits/stl_algobase.h> // For copy, fill_n
#include <bits/algorithmfwd.h> // std::copy, std::fill_n
#include <bits/postypes.h> // For streampos
#include <cstdio> // For EOF
#include <cwchar> // For WEOF, wmemmove, wmemset, etc.
@ -194,6 +194,7 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
char_traits<_CharT>::
copy(char_type* __s1, const char_type* __s2, std::size_t __n)
{
// NB: Inline std::copy so no recursive dependencies.
std::copy(__s2, __s2 + __n, __s1);
return __s1;
}
@ -203,6 +204,7 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
char_traits<_CharT>::
assign(char_type* __s, std::size_t __n, char_type __a)
{
// NB: Inline std::fill_n so no recursive dependencies.
std::fill_n(__s, __n, __a);
return __s;
}

View File

@ -62,7 +62,7 @@
#ifndef _DEQUE_TCC
#define _DEQUE_TCC 1
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
template <typename _Tp, typename _Alloc>
deque<_Tp, _Alloc>&

View File

@ -62,7 +62,7 @@
#ifndef _LIST_TCC
#define _LIST_TCC 1
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
template<typename _Tp, typename _Alloc>
void

File diff suppressed because it is too large Load Diff

View File

@ -65,11 +65,10 @@
#include <bits/c++config.h>
#include <cstddef>
#include <bits/functexcept.h>
#include <bits/stl_pair.h>
#include <bits/cpp_type_traits.h>
#include <ext/type_traits.h>
#include <ext/numeric_traits.h>
#include <bits/stl_iterator_base_types.h>
#include <bits/algorithmfwd.h>
#include <bits/stl_iterator_base_funcs.h>
#include <bits/stl_iterator.h>
#include <bits/concept_check.h>
@ -596,7 +595,6 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
__niter_base<_ForwardIterator>::__b(__last), __value);
}
template<bool>
struct __fill_n
{
@ -678,7 +676,6 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
__value));
}
template<bool _BoolType>
struct __equal
{
@ -719,6 +716,90 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
return std::__equal<__simple>::equal(__first1, __last1, __first2);
}
template<typename, typename>
struct __lc_rai
{
template<typename _II1, typename _II2>
static _II1
__newlast1(_II1, _II1 __last1, _II2, _II2)
{ return __last1; }
template<typename _II>
static bool
__cnd2(_II __first, _II __last)
{ return __first != __last; }
};
template<>
struct __lc_rai<random_access_iterator_tag, random_access_iterator_tag>
{
template<typename _RAI1, typename _RAI2>
static _RAI1
__newlast1(_RAI1 __first1, _RAI1 __last1,
_RAI2 __first2, _RAI2 __last2)
{
const typename iterator_traits<_RAI1>::difference_type
__diff1 = __last1 - __first1;
const typename iterator_traits<_RAI2>::difference_type
__diff2 = __last2 - __first2;
return __diff2 < __diff1 ? __first1 + __diff2 : __last1;
}
template<typename _RAI>
static bool
__cnd2(_RAI, _RAI)
{ return true; }
};
// XXX should these be enabled-if'd for signed/unsigned types instead?
inline bool
lexicographical_compare(const unsigned char* __first1,
const unsigned char* __last1,
const unsigned char* __first2,
const unsigned char* __last2)
{
__glibcxx_requires_valid_range(__first1, __last1);
__glibcxx_requires_valid_range(__first2, __last2);
const size_t __len1 = __last1 - __first1;
const size_t __len2 = __last2 - __first2;
const int __result = __builtin_memcmp(__first1, __first2,
std::min(__len1, __len2));
return __result != 0 ? __result < 0 : __len1 < __len2;
}
inline bool
lexicographical_compare(const char* __first1, const char* __last1,
const char* __first2, const char* __last2)
{
__glibcxx_requires_valid_range(__first1, __last1);
__glibcxx_requires_valid_range(__first2, __last2);
if (__gnu_cxx::__numeric_traits<char>::__is_signed)
{
typedef const signed char* value_type;
value_type __f1 = reinterpret_cast<value_type>(__first1);
value_type __l1 = reinterpret_cast<value_type>(__last1);
value_type __f2 = reinterpret_cast<value_type>(__first2);
value_type __l2 = reinterpret_cast<value_type>(__last2);
return _GLIBCXX_STD_P::lexicographical_compare(__f1, __l1, __f2, __l2);
}
else
{
typedef const unsigned char* value_type;
value_type __f1 = reinterpret_cast<value_type>(__first1);
value_type __l1 = reinterpret_cast<value_type>(__last1);
value_type __f2 = reinterpret_cast<value_type>(__first2);
value_type __l2 = reinterpret_cast<value_type>(__last2);
return _GLIBCXX_STD_P::lexicographical_compare(__f1, __l1, __f2, __l2);
}
}
_GLIBCXX_END_NAMESPACE
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_P)
/**
* @brief Tests a range for element-wise equality.
* @param first1 An input iterator.
@ -752,24 +833,23 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
* @param first1 An input iterator.
* @param last1 An input iterator.
* @param first2 An input iterator.
* @param binary_pred A binary predicate @link s20_3_1_base functor@endlink.
* @return A boolean true or false.
* @param binary_pred A binary predicate @link s20_3_1_base
* functor@endlink.
* @return A boolean true or false.
*
* This compares the elements of two ranges using the binary_pred
* parameter, and returns true or
* false depending on whether all of the corresponding elements of the
* ranges are equal.
*/
template<typename _InputIterator1, typename _InputIterator2,
typename _BinaryPredicate>
template<typename _IIter1, typename _IIter2, typename _BinaryPredicate>
inline bool
equal(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2,
_BinaryPredicate __binary_pred)
equal(_IIter1 __first1, _IIter1 __last1,
_IIter2 __first2, _BinaryPredicate __binary_pred)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>)
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>)
__glibcxx_function_requires(_InputIteratorConcept<_IIter1>)
__glibcxx_function_requires(_InputIteratorConcept<_IIter2>)
__glibcxx_requires_valid_range(__first1, __last1);
for (; __first1 != __last1; ++__first1, ++__first2)
@ -778,43 +858,6 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
return true;
}
template<typename, typename>
struct __lc_rai
{
template<typename _II1, typename _II2>
static _II1
__newlast1(_II1, _II1 __last1, _II2, _II2)
{ return __last1; }
template<typename _II>
static bool
__cnd2(_II __first, _II __last)
{ return __first != __last; }
};
template<>
struct __lc_rai<random_access_iterator_tag,
random_access_iterator_tag>
{
template<typename _RAI1, typename _RAI2>
static _RAI1
__newlast1(_RAI1 __first1, _RAI1 __last1,
_RAI2 __first2, _RAI2 __last2)
{
const typename iterator_traits<_RAI1>::difference_type
__diff1 = __last1 - __first1;
const typename iterator_traits<_RAI2>::difference_type
__diff2 = __last2 - __first2;
return __diff2 < __diff1 ? __first1 + __diff2 : __last1;
}
template<typename _RAI>
static bool
__cnd2(_RAI, _RAI)
{ return true; }
};
/**
* @brief Performs "dictionary" comparison on ranges.
* @param first1 An input iterator.
@ -831,7 +874,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
*/
template<typename _II1, typename _II2>
bool
lexicographical_compare(_II1 __first1, _II1 __last1,
lexicographical_compare(_II1 __first1, _II1 __last1,
_II2 __first2, _II2 __last2)
{
typedef typename iterator_traits<_II1>::iterator_category _Category1;
@ -882,6 +925,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
{
typedef typename iterator_traits<_II1>::iterator_category _Category1;
typedef typename iterator_traits<_II2>::iterator_category _Category2;
typedef __lc_rai<_Category1, _Category2> __rai_type;
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_II1>)
@ -889,12 +933,8 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
__glibcxx_requires_valid_range(__first1, __last1);
__glibcxx_requires_valid_range(__first2, __last2);
__last1 = __lc_rai<_Category1, _Category2>::__newlast1(__first1,
__last1,
__first2,
__last2);
for (; __first1 != __last1
&& __lc_rai<_Category1, _Category2>::__cnd2(__first2, __last2);
__last1 = __rai_type::__newlast1(__first1, __last1, __first2, __last2);
for (; __first1 != __last1 && __rai_type::__cnd2(__first2, __last2);
++__first1, ++__first2)
{
if (__comp(*__first1, *__first2))
@ -905,41 +945,82 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
return __first1 == __last1 && __first2 != __last2;
}
inline bool
lexicographical_compare(const unsigned char* __first1,
const unsigned char* __last1,
const unsigned char* __first2,
const unsigned char* __last2)
{
__glibcxx_requires_valid_range(__first1, __last1);
__glibcxx_requires_valid_range(__first2, __last2);
const size_t __len1 = __last1 - __first1;
const size_t __len2 = __last2 - __first2;
const int __result = __builtin_memcmp(__first1, __first2,
std::min(__len1, __len2));
return __result != 0 ? __result < 0 : __len1 < __len2;
}
/**
* @brief Finds the places in ranges which don't match.
* @param first1 An input iterator.
* @param last1 An input iterator.
* @param first2 An input iterator.
* @return A pair of iterators pointing to the first mismatch.
*
* This compares the elements of two ranges using @c == and returns a pair
* of iterators. The first iterator points into the first range, the
* second iterator points into the second range, and the elements pointed
* to by the iterators are not equal.
*/
template<typename _InputIterator1, typename _InputIterator2>
pair<_InputIterator1, _InputIterator2>
mismatch(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>)
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>)
__glibcxx_function_requires(_EqualOpConcept<
typename iterator_traits<_InputIterator1>::value_type,
typename iterator_traits<_InputIterator2>::value_type>)
__glibcxx_requires_valid_range(__first1, __last1);
inline bool
lexicographical_compare(const char* __first1, const char* __last1,
const char* __first2, const char* __last2)
{
__glibcxx_requires_valid_range(__first1, __last1);
__glibcxx_requires_valid_range(__first2, __last2);
while (__first1 != __last1 && *__first1 == *__first2)
{
++__first1;
++__first2;
}
return pair<_InputIterator1, _InputIterator2>(__first1, __first2);
}
if (__gnu_cxx::__numeric_traits<char>::__is_signed)
return std::lexicographical_compare((const signed char*) __first1,
(const signed char*) __last1,
(const signed char*) __first2,
(const signed char*) __last2);
else
return std::lexicographical_compare((const unsigned char*) __first1,
(const unsigned char*) __last1,
(const unsigned char*) __first2,
(const unsigned char*) __last2);
}
/**
* @brief Finds the places in ranges which don't match.
* @param first1 An input iterator.
* @param last1 An input iterator.
* @param first2 An input iterator.
* @param binary_pred A binary predicate @link s20_3_1_base
* functor@endlink.
* @return A pair of iterators pointing to the first mismatch.
*
* This compares the elements of two ranges using the binary_pred
* parameter, and returns a pair
* of iterators. The first iterator points into the first range, the
* second iterator points into the second range, and the elements pointed
* to by the iterators are not equal.
*/
template<typename _InputIterator1, typename _InputIterator2,
typename _BinaryPredicate>
pair<_InputIterator1, _InputIterator2>
mismatch(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _BinaryPredicate __binary_pred)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>)
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>)
__glibcxx_requires_valid_range(__first1, __last1);
_GLIBCXX_END_NAMESPACE
while (__first1 != __last1 && bool(__binary_pred(*__first1, *__first2)))
{
++__first1;
++__first2;
}
return pair<_InputIterator1, _InputIterator2>(__first1, __first2);
}
_GLIBCXX_END_NESTED_NAMESPACE
// NB: This file is included within many other C++ includes, as a way
// of getting the base algorithms. So, make sure that parallel bits
// come in too if requested.
#ifdef _GLIBCXX_PARALLEL
//# include <parallel/algorithm>
# include <parallel/algobase.h>
#endif
#endif

View File

@ -62,7 +62,7 @@
#ifndef _STL_BVECTOR_H
#define _STL_BVECTOR_H 1
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
typedef unsigned long _Bit_type;
enum { _S_word_bit = int(__CHAR_BIT__ * sizeof(_Bit_type)) };
@ -432,7 +432,7 @@ _GLIBCXX_END_NESTED_NAMESPACE
// Declare a partial specialization of vector<T, Alloc>.
#include <bits/stl_vector.h>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
/**
* @brief A specialization of vector for booleans which offers fixed time

View File

@ -66,7 +66,7 @@
#include <bits/stl_iterator_base_types.h>
#include <bits/stl_iterator_base_funcs.h>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
/**
* @if maint

View File

@ -64,7 +64,7 @@
#include <bits/concept_check.h>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
// Supporting structures are split into common and templated types; the
// latter publicly inherits from the former in an effort to reduce code

View File

@ -65,7 +65,7 @@
#include <bits/functexcept.h>
#include <bits/concept_check.h>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
/**
* @brief A standard container made up of (key,value) pairs, which can be

View File

@ -64,7 +64,7 @@
#include <bits/concept_check.h>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
/**
* @brief A standard container made up of (key,value) pairs, which can be

View File

@ -64,7 +64,7 @@
#include <bits/concept_check.h>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
/**
* @brief A standard container made up of elements, which can be retrieved

View File

@ -65,7 +65,7 @@
#include <bits/concept_check.h>
#include <debug/debug.h>
_GLIBCXX_BEGIN_NAMESPACE(std)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_P)
/**
* @brief Accumulate values in a range.
@ -336,6 +336,6 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
return ++__result;
}
_GLIBCXX_END_NAMESPACE
_GLIBCXX_END_NESTED_NAMESPACE
#endif /* _STL_NUMERIC_H */

View File

@ -64,7 +64,7 @@
#include <bits/concept_check.h>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
/**
* @brief A standard container made up of unique keys, which can be

View File

@ -66,7 +66,7 @@
#include <bits/functexcept.h>
#include <bits/concept_check.h>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
/**
* @if maint

View File

@ -62,7 +62,7 @@
#ifndef _VECTOR_TCC
#define _VECTOR_TCC 1
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
template<typename _Tp, typename _Alloc>
void

View File

@ -45,10 +45,10 @@ namespace __debug
{
template<size_t _Nb>
class bitset
: public _GLIBCXX_STD::bitset<_Nb>,
: public _GLIBCXX_STD_D::bitset<_Nb>,
public __gnu_debug::_Safe_sequence_base
{
typedef _GLIBCXX_STD::bitset<_Nb> _Base;
typedef _GLIBCXX_STD_D::bitset<_Nb> _Base;
typedef __gnu_debug::_Safe_sequence_base _Safe_base;
public:

View File

@ -113,6 +113,7 @@ namespace std
#else
# define _GLIBCXX_DEBUG_PEDASSERT(_Condition)
#endif
# define _GLIBCXX_DEBUG_ONLY(_Statement) _Statement
# define __glibcxx_requires_cond(_Cond,_Msg) _GLIBCXX_DEBUG_VERIFY(_Cond,_Msg)

View File

@ -45,10 +45,10 @@ namespace __debug
{
template<typename _Tp, typename _Allocator = std::allocator<_Tp> >
class deque
: public _GLIBCXX_STD::deque<_Tp, _Allocator>,
: public _GLIBCXX_STD_D::deque<_Tp, _Allocator>,
public __gnu_debug::_Safe_sequence<deque<_Tp, _Allocator> >
{
typedef _GLIBCXX_STD::deque<_Tp, _Allocator> _Base;
typedef _GLIBCXX_STD_D::deque<_Tp, _Allocator> _Base;
typedef __gnu_debug::_Safe_sequence<deque> _Safe_base;
public:

View File

@ -73,10 +73,10 @@ namespace __debug
{
template<typename _Tp, typename _Allocator = std::allocator<_Tp> >
class list
: public _GLIBCXX_STD::list<_Tp, _Allocator>,
: public _GLIBCXX_STD_D::list<_Tp, _Allocator>,
public __gnu_debug::_Safe_sequence<list<_Tp, _Allocator> >
{
typedef _GLIBCXX_STD::list<_Tp, _Allocator> _Base;
typedef _GLIBCXX_STD_D::list<_Tp, _Allocator> _Base;
typedef __gnu_debug::_Safe_sequence<list> _Safe_base;
public:

View File

@ -46,10 +46,10 @@ namespace __debug
template<typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
typename _Allocator = std::allocator<std::pair<const _Key, _Tp> > >
class map
: public _GLIBCXX_STD::map<_Key, _Tp, _Compare, _Allocator>,
: public _GLIBCXX_STD_D::map<_Key, _Tp, _Compare, _Allocator>,
public __gnu_debug::_Safe_sequence<map<_Key, _Tp, _Compare, _Allocator> >
{
typedef _GLIBCXX_STD::map<_Key, _Tp, _Compare, _Allocator> _Base;
typedef _GLIBCXX_STD_D::map<_Key, _Tp, _Compare, _Allocator> _Base;
typedef __gnu_debug::_Safe_sequence<map> _Safe_base;
public:

View File

@ -46,10 +46,10 @@ namespace __debug
template<typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
typename _Allocator = std::allocator<std::pair<const _Key, _Tp> > >
class multimap
: public _GLIBCXX_STD::multimap<_Key, _Tp, _Compare, _Allocator>,
: public _GLIBCXX_STD_D::multimap<_Key, _Tp, _Compare, _Allocator>,
public __gnu_debug::_Safe_sequence<multimap<_Key,_Tp,_Compare,_Allocator> >
{
typedef _GLIBCXX_STD::multimap<_Key, _Tp, _Compare, _Allocator> _Base;
typedef _GLIBCXX_STD_D::multimap<_Key, _Tp, _Compare, _Allocator> _Base;
typedef __gnu_debug::_Safe_sequence<multimap> _Safe_base;
public:

View File

@ -46,10 +46,10 @@ namespace __debug
template<typename _Key, typename _Compare = std::less<_Key>,
typename _Allocator = std::allocator<_Key> >
class multiset
: public _GLIBCXX_STD::multiset<_Key, _Compare, _Allocator>,
: public _GLIBCXX_STD_D::multiset<_Key, _Compare, _Allocator>,
public __gnu_debug::_Safe_sequence<multiset<_Key, _Compare, _Allocator> >
{
typedef _GLIBCXX_STD::multiset<_Key, _Compare, _Allocator> _Base;
typedef _GLIBCXX_STD_D::multiset<_Key, _Compare, _Allocator> _Base;
typedef __gnu_debug::_Safe_sequence<multiset> _Safe_base;
public:

View File

@ -46,10 +46,10 @@ namespace __debug
template<typename _Key, typename _Compare = std::less<_Key>,
typename _Allocator = std::allocator<_Key> >
class set
: public _GLIBCXX_STD::set<_Key,_Compare,_Allocator>,
: public _GLIBCXX_STD_D::set<_Key,_Compare,_Allocator>,
public __gnu_debug::_Safe_sequence<set<_Key, _Compare, _Allocator> >
{
typedef _GLIBCXX_STD::set<_Key,_Compare,_Allocator> _Base;
typedef _GLIBCXX_STD_D::set<_Key,_Compare,_Allocator> _Base;
typedef __gnu_debug::_Safe_sequence<set> _Safe_base;
public:

View File

@ -47,10 +47,10 @@ namespace __debug
template<typename _Tp,
typename _Allocator = std::allocator<_Tp> >
class vector
: public _GLIBCXX_STD::vector<_Tp, _Allocator>,
: public _GLIBCXX_STD_D::vector<_Tp, _Allocator>,
public __gnu_debug::_Safe_sequence<vector<_Tp, _Allocator> >
{
typedef _GLIBCXX_STD::vector<_Tp, _Allocator> _Base;
typedef _GLIBCXX_STD_D::vector<_Tp, _Allocator> _Base;
typedef __gnu_debug::_Safe_sequence<vector> _Safe_base;
typedef typename _Base::const_iterator _Base_const_iterator;

View File

@ -65,7 +65,7 @@
#include <ext/hashtable.h>
#include <bits/concept_check.h>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(__gnu_cxx, _GLIBCXX_EXT)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(__gnu_cxx, _GLIBCXX_EXT_D)
using std::equal_to;
using std::allocator;

View File

@ -65,7 +65,7 @@
#include <ext/hashtable.h>
#include <bits/concept_check.h>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(__gnu_cxx, _GLIBCXX_EXT)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(__gnu_cxx, _GLIBCXX_EXT_D)
using std::equal_to;
using std::allocator;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,256 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/algobase.h
* @brief Parallel STL function calls corresponding to the
* stl_algobase.h header. The functions defined here mainly do case
* switches and call the actual parallelized versions in other files.
* Inlining policy: Functions that basically only contain one
* function call, are declared inline.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler and Felix Putze.
#ifndef _GLIBCXX_PARALLEL_ALGOBASE_H
#define _GLIBCXX_PARALLEL_ALGOBASE_H 1
#include <parallel/algorithmfwd.h>
#include <bits/stl_algobase.h>
#include <parallel/base.h>
#include <parallel/tags.h>
#include <parallel/settings.h>
#include <parallel/find.h>
#include <parallel/find_selectors.h>
#include <parallel/for_each.h>
#include <parallel/for_each_selectors.h>
namespace std
{
namespace __parallel
{
// Sequential fallback
template<typename InputIterator1, typename InputIterator2>
inline bool
equal(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, __gnu_parallel::sequential_tag)
{
return _GLIBCXX_STD_P::equal<InputIterator1, InputIterator2>(begin1, end1, begin2);
}
// Sequential fallback
template<typename InputIterator1, typename InputIterator2, typename Predicate>
inline bool
equal(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, Predicate pred, __gnu_parallel::sequential_tag)
{ return _GLIBCXX_STD_P::equal(begin1, end1, begin2, pred); }
// Public interface
template<typename InputIterator1, typename InputIterator2>
inline bool
equal(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2)
{ return mismatch(begin1, end1, begin2).first == end1; }
// Public interface
template<typename InputIterator1, typename InputIterator2, typename Predicate>
inline bool
equal(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, Predicate pred)
{ return mismatch(begin1, end1, begin2, pred).first == end1; }
// NB: lexicographical_compare equires mismatch.
// Sequential fallback
template<typename InputIterator1, typename InputIterator2>
inline pair<InputIterator1, InputIterator2>
mismatch(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, __gnu_parallel::sequential_tag)
{
return _GLIBCXX_STD_P::mismatch<InputIterator1, InputIterator2>(begin1, end1, begin2);
}
// Sequential fallback
template<typename InputIterator1, typename InputIterator2, typename Predicate>
inline pair<InputIterator1, InputIterator2>
mismatch(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, Predicate pred, __gnu_parallel::sequential_tag)
{ return _GLIBCXX_STD_P::mismatch(begin1, end1, begin2, pred); }
// Sequential fallback for input iterator case
template<typename InputIterator1, typename InputIterator2, typename Predicate, typename IteratorTag1, typename IteratorTag2>
inline pair<InputIterator1, InputIterator2>
mismatch_switch(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, Predicate pred, IteratorTag1, IteratorTag2)
{ return _GLIBCXX_STD_P::mismatch(begin1, end1, begin2, pred); }
// Parallel mismatch for random access iterators
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Predicate>
pair<RandomAccessIterator1, RandomAccessIterator2>
mismatch_switch(RandomAccessIterator1 begin1, RandomAccessIterator1 end1, RandomAccessIterator2 begin2, Predicate pred, random_access_iterator_tag, random_access_iterator_tag)
{
if (_GLIBCXX_PARALLEL_CONDITION(true))
{
RandomAccessIterator1 res_first =
__gnu_parallel::find_template(begin1, end1, begin2, pred, __gnu_parallel::mismatch_selector()).first;
return make_pair(res_first, begin2 + (res_first - begin1));
}
else
return _GLIBCXX_STD_P::mismatch(begin1, end1, begin2, pred);
}
// Public interface
template<typename InputIterator1, typename InputIterator2>
inline pair<InputIterator1, InputIterator2>
mismatch(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2)
{
typedef std::iterator_traits<InputIterator1> iterator1_traits;
typedef std::iterator_traits<InputIterator2> iterator2_traits;
typedef typename iterator1_traits::value_type value1_type;
typedef typename iterator2_traits::value_type value2_type;
typedef typename iterator1_traits::iterator_category iterator1_category;
typedef typename iterator2_traits::iterator_category iterator2_category;
return mismatch_switch(begin1, end1, begin2, __gnu_parallel::equal_to<value1_type, value2_type>(), iterator1_category(), iterator2_category());
}
// Public interface
template<typename InputIterator1, typename InputIterator2, typename Predicate>
inline pair<InputIterator1, InputIterator2>
mismatch(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2,
Predicate pred)
{
typedef std::iterator_traits<InputIterator1> iterator1_traits;
typedef std::iterator_traits<InputIterator2> iterator2_traits;
typedef typename iterator1_traits::iterator_category iterator1_category;
typedef typename iterator2_traits::iterator_category iterator2_category;
return mismatch_switch(begin1, end1, begin2, pred, iterator1_category(), iterator2_category());
}
// Sequential fallback
template<typename InputIterator1, typename InputIterator2>
inline bool
lexicographical_compare(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, InputIterator2 end2, __gnu_parallel::sequential_tag)
{
return _GLIBCXX_STD_P::lexicographical_compare<InputIterator1, InputIterator2>(begin1, end1, begin2, end2);
}
// Sequential fallback
template<typename InputIterator1, typename InputIterator2, typename Predicate>
inline bool
lexicographical_compare(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, InputIterator2 end2, Predicate pred, __gnu_parallel::sequential_tag)
{
return _GLIBCXX_STD_P::lexicographical_compare(begin1, end1, begin2, end2, pred);
}
// Sequential fallback for input iterator case
template<typename InputIterator1, typename InputIterator2, typename Predicate, typename IteratorTag1, typename IteratorTag2>
inline bool
lexicographical_compare_switch(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, InputIterator2 end2, Predicate pred, IteratorTag1, IteratorTag2)
{
return _GLIBCXX_STD_P::lexicographical_compare(begin1, end1, begin2, end2, pred);
}
// Parallel lexicographical_compare for random access iterators
// Limitation: Both valuetypes must be the same
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Predicate>
bool
lexicographical_compare_switch(RandomAccessIterator1 begin1, RandomAccessIterator1 end1, RandomAccessIterator2 begin2, RandomAccessIterator2 end2, Predicate pred, random_access_iterator_tag, random_access_iterator_tag)
{
if (_GLIBCXX_PARALLEL_CONDITION(true))
{
typedef iterator_traits<RandomAccessIterator1> traits1_type;
typedef typename traits1_type::value_type value1_type;
typedef iterator_traits<RandomAccessIterator2> traits2_type;
typedef typename traits2_type::value_type value2_type;
typedef __gnu_parallel::equal_from_less<Predicate, value1_type, value2_type> equal_type;
// Longer sequence in first place.
if ((end1 - begin1) < (end2 - begin2))
{
typedef pair<RandomAccessIterator1, RandomAccessIterator2> pair_type;
pair_type mm = mismatch_switch(begin1, end1, begin2, equal_type(pred), random_access_iterator_tag(), random_access_iterator_tag());
// Less because shorter.
const bool lbs = mm.first == end1;
// Less because differing elements less.
const bool lbdel = pred(*mm.first, *mm.second);
return lbs || lbdel;
}
else
{
typedef pair<RandomAccessIterator2, RandomAccessIterator1> pair_type;
pair_type mm = mismatch_switch(begin2, end2, begin1, equal_type(pred), random_access_iterator_tag(), random_access_iterator_tag());
// Less because shorter.
const bool lbs = mm.first != end2;
// Less because differing element less.
const bool lbdel = pred(*mm.second, *mm.first);
return lbs && lbdel;
}
}
else
return _GLIBCXX_STD_P::lexicographical_compare(begin1, end1, begin2, end2, pred);
}
// Public interface
template<typename InputIterator1, typename InputIterator2>
inline bool
lexicographical_compare(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, InputIterator2 end2)
{
typedef iterator_traits<InputIterator1> traits1_type;
typedef typename traits1_type::value_type value1_type;
typedef typename traits1_type::iterator_category iterator1_category;
typedef iterator_traits<InputIterator2> traits2_type;
typedef typename traits2_type::value_type value2_type;
typedef typename traits2_type::iterator_category iterator2_category;
typedef __gnu_parallel::less<value1_type, value2_type> less_type;
return lexicographical_compare_switch(begin1, end1, begin2, end2, less_type(), iterator1_category(), iterator2_category());
}
// Public interface
template<typename InputIterator1, typename InputIterator2, typename Predicate>
inline bool
lexicographical_compare(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, InputIterator2 end2, Predicate pred)
{
typedef iterator_traits<InputIterator1> traits1_type;
typedef typename traits1_type::iterator_category iterator1_category;
typedef iterator_traits<InputIterator2> traits2_type;
typedef typename traits2_type::iterator_category iterator2_category;
return lexicographical_compare_switch(begin1, end1, begin2, end2, pred, iterator1_category(), iterator2_category());
}
} // end namespace
} // end namespace
#endif /* _GLIBCXX_ALGOBASE_H */

View File

@ -0,0 +1,45 @@
// Algorithm extensions -*- C++ -*-
// Copyright (C) 2007
// Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING. If not, write to the Free
// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
// USA.
// As a special exception, you may use this file as part of a free software
// library without restriction. Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License. This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
/** @file parallel/algorithm
* This file is a GNU extension to the Standard C++ Library.
*/
#ifndef _PARALLEL_ALGORITHM
#define _PARALLEL_ALGORITHM 1
#pragma GCC system_header
#include <algorithm>
#include <parallel/algorithmfwd.h>
#include <parallel/algobase.h>
#include <parallel/algo.h>
#endif

View File

@ -0,0 +1,719 @@
// <algorithm> parallel extensions -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/algorithmfwd.h
* This file is a GNU parallel extension to the Standard C++ Library.
*/
#ifndef _GLIBCXX_PARALLEL_ALGORITHMFWD_H
#define _GLIBCXX_PARALLEL_ALGORITHMFWD_H 1
#pragma GCC system_header
#include <parallel/tags.h>
#include <parallel/settings.h>
namespace std
{
namespace __parallel
{
template<typename _FIter>
inline _FIter
adjacent_find(_FIter, _FIter, __gnu_parallel::sequential_tag);
template<typename _FIter, typename BinaryPredicate>
inline _FIter
adjacent_find(_FIter, _FIter, BinaryPredicate, __gnu_parallel::sequential_tag);
template<typename _FIter>
inline _FIter
adjacent_find(_FIter, _FIter);
template<typename _FIter, typename BinaryPredicate>
inline _FIter
adjacent_find(_FIter, _FIter, BinaryPredicate);
template<typename _RAIter>
_RAIter
adjacent_find_switch(_RAIter, _RAIter, random_access_iterator_tag);
template<typename _FIter, typename IteratorTag>
inline _FIter
adjacent_find_switch(_FIter, _FIter, IteratorTag);
template<typename _FIter, typename BinaryPredicate, typename IteratorTag>
inline _FIter
adjacent_find_switch(_FIter, _FIter, BinaryPredicate, IteratorTag);
template<typename _RAIter, typename BinaryPredicate>
_RAIter
adjacent_find_switch(_RAIter, _RAIter, BinaryPredicate, random_access_iterator_tag);
template<typename _IIter, typename T>
inline typename iterator_traits<_IIter>::difference_type
count(_IIter, _IIter, const T& value, __gnu_parallel::sequential_tag);
template<typename _IIter, typename T>
inline typename iterator_traits<_IIter>::difference_type
count(_IIter, _IIter, const T& value, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_unbalanced);
template<typename _RAIter, typename T>
typename iterator_traits<_RAIter>::difference_type
count_switch(_RAIter, _RAIter, const T& value, random_access_iterator_tag, __gnu_parallel::parallelism);
template<typename _IIter, typename T, typename IteratorTag>
typename iterator_traits<_IIter>::difference_type
count_switch(_IIter, _IIter, const T& value, IteratorTag, __gnu_parallel::parallelism);
template<typename _IIter, typename Predicate>
inline typename iterator_traits<_IIter>::difference_type
count_if(_IIter, _IIter, Predicate, __gnu_parallel::sequential_tag);
template<typename _IIter, typename Predicate>
inline typename iterator_traits<_IIter>::difference_type
count_if(_IIter, _IIter, Predicate, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_unbalanced);
template<typename _RAIter, typename Predicate>
typename iterator_traits<_RAIter>::difference_type
count_if_switch(_RAIter, _RAIter, Predicate, random_access_iterator_tag, __gnu_parallel::parallelism);
template<typename _IIter, typename Predicate, typename IteratorTag>
typename iterator_traits<_IIter>::difference_type
count_if_switch(_IIter, _IIter, Predicate, IteratorTag, __gnu_parallel::parallelism);
// algobase.h
template<typename _IIter1, typename _IIter2>
inline bool
equal(_IIter1, _IIter1, _IIter2, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename Predicate>
inline bool
equal(_IIter1, _IIter1, _IIter2, Predicate, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2>
inline bool
equal(_IIter1, _IIter1, _IIter2);
template<typename _IIter1, typename _IIter2, typename Predicate>
inline bool
equal(_IIter1, _IIter1, _IIter2, Predicate);
template<typename _IIter, typename T>
inline _IIter
find(_IIter, _IIter, const T&, __gnu_parallel::sequential_tag);
template<typename _IIter, typename T>
inline _IIter
find(_IIter, _IIter, const T& val);
template<typename _IIter, typename T, typename IteratorTag>
inline _IIter
find_switch(_IIter, _IIter, const T&, IteratorTag);
template<typename _RAIter, typename T>
_RAIter
find_switch(_RAIter, _RAIter, const T&, random_access_iterator_tag);
template<typename _IIter, typename Predicate>
inline _IIter
find_if(_IIter, _IIter, Predicate, __gnu_parallel::sequential_tag);
template<typename _IIter, typename Predicate>
inline _IIter
find_if (_IIter, _IIter, Predicate);
template<typename _IIter, typename Predicate, typename IteratorTag>
inline _IIter
find_if_switch(_IIter, _IIter, Predicate, IteratorTag);
template<typename _RAIter, typename Predicate>
_RAIter
find_if_switch(_RAIter, _RAIter, Predicate, random_access_iterator_tag);
template<typename _IIter, typename _FIter>
inline _IIter
find_first_of(_IIter, _IIter, _FIter, _FIter, __gnu_parallel::sequential_tag);
template<typename _IIter, typename _FIter, typename BinaryPredicate>
inline _IIter
find_first_of(_IIter, _IIter, _FIter, _FIter, BinaryPredicate, __gnu_parallel::sequential_tag);
template<typename _IIter, typename _FIter, typename BinaryPredicate>
inline _IIter
find_first_of(_IIter, _IIter, _FIter, _FIter, BinaryPredicate);
template<typename _IIter, typename _FIter>
_IIter
find_first_of(_IIter, _IIter, _FIter, _FIter);
template<typename _IIter, typename _FIter, typename IteratorTag1, typename IteratorTag2>
inline _IIter
find_first_of_switch(_IIter, _IIter, _FIter, _FIter, IteratorTag1, IteratorTag2);
template<typename _RAIter, typename _FIter, typename BinaryPredicate, typename IteratorTag>
inline _RAIter
find_first_of_switch(_RAIter, _RAIter, _FIter, _FIter, BinaryPredicate, random_access_iterator_tag, IteratorTag);
template<typename _IIter, typename _FIter, typename BinaryPredicate, typename IteratorTag1, typename IteratorTag2>
inline _IIter
find_first_of_switch(_IIter, _IIter, _FIter, _FIter, BinaryPredicate, IteratorTag1, IteratorTag2);
template<typename _IIter, typename Function>
inline Function
for_each(_IIter, _IIter, Function f, __gnu_parallel::sequential_tag);
template<typename Iterator, typename Function>
inline Function
for_each(Iterator, Iterator, Function f, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _IIter, typename Function, typename IteratorTag>
Function
for_each_switch(_IIter, _IIter, Function f, IteratorTag, __gnu_parallel::parallelism);
template<typename _RAIter, typename Function>
Function
for_each_switch(_RAIter, _RAIter, Function f, random_access_iterator_tag, __gnu_parallel::parallelism);
template<typename _FIter, typename Generator>
inline void
generate(_FIter, _FIter, Generator, __gnu_parallel::sequential_tag);
template<typename _FIter, typename Generator>
inline void
generate(_FIter, _FIter, Generator, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _FIter, typename Generator, typename IteratorTag>
void
generate_switch(_FIter, _FIter, Generator, IteratorTag, __gnu_parallel::parallelism);
template<typename _RAIter, typename Generator>
void
generate_switch(_RAIter, _RAIter, Generator, random_access_iterator_tag, __gnu_parallel::parallelism);
template<typename _OIter, typename Size, typename Generator>
inline _OIter
generate_n(_OIter, Size, Generator, __gnu_parallel::sequential_tag);
template<typename _OIter, typename Size, typename Generator>
inline _OIter
generate_n(_OIter, Size, Generator, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _OIter, typename Size, typename Generator, typename IteratorTag>
_OIter
generate_n_switch(_OIter, Size, Generator, IteratorTag, __gnu_parallel::parallelism);
template<typename _RAIter, typename Size, typename Generator>
_RAIter
generate_n_switch(_RAIter, Size, Generator, random_access_iterator_tag, __gnu_parallel::parallelism);
template<typename _IIter1, typename _IIter2>
inline bool
lexicographical_compare(_IIter1, _IIter1, _IIter2, _IIter2, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename Predicate>
inline bool
lexicographical_compare(_IIter1, _IIter1, _IIter2, _IIter2, Predicate, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2>
inline bool
lexicographical_compare(_IIter1, _IIter1, _IIter2, _IIter2);
template<typename _IIter1, typename _IIter2, typename Predicate>
inline bool
lexicographical_compare(_IIter1, _IIter1, _IIter2, _IIter2, Predicate);
template<typename _IIter1, typename _IIter2, typename Predicate, typename IteratorTag1, typename IteratorTag2>
inline bool
lexicographical_compare_switch(_IIter1, _IIter1, _IIter2, _IIter2, Predicate, IteratorTag1, IteratorTag2);
template<typename _RAIter1, typename _RAIter2, typename Predicate>
bool
lexicographical_compare_switch(_RAIter1, _RAIter1, _RAIter2, _RAIter2, Predicate, random_access_iterator_tag, random_access_iterator_tag);
// algo.h
template<typename _IIter1, typename _IIter2>
inline pair<_IIter1, _IIter2>
mismatch(_IIter1, _IIter1, _IIter2, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename Predicate>
inline pair<_IIter1, _IIter2>
mismatch(_IIter1, _IIter1, _IIter2, Predicate, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2>
inline pair<_IIter1, _IIter2>
mismatch(_IIter1, _IIter1, _IIter2);
template<typename _IIter1, typename _IIter2, typename Predicate>
inline pair<_IIter1, _IIter2>
mismatch(_IIter1, _IIter1, _IIter2, Predicate);
template<typename _IIter1, typename _IIter2, typename Predicate, typename IteratorTag1, typename IteratorTag2>
inline pair<_IIter1, _IIter2>
mismatch_switch(_IIter1, _IIter1, _IIter2, Predicate, IteratorTag1, IteratorTag2);
template<typename _RAIter1, typename _RAIter2, typename Predicate>
pair<_RAIter1, _RAIter2>
mismatch_switch(_RAIter1, _RAIter1, _RAIter2, Predicate, random_access_iterator_tag, random_access_iterator_tag);
template<typename _FIter1, typename _FIter2>
inline _FIter1
search(_FIter1, _FIter1, _FIter2, _FIter2, __gnu_parallel::sequential_tag);
template<typename _FIter1, typename _FIter2>
inline _FIter1
search(_FIter1, _FIter1, _FIter2, _FIter2);
template<typename _FIter1, typename _FIter2, typename BinaryPredicate>
inline _FIter1
search(_FIter1, _FIter1, _FIter2, _FIter2, BinaryPredicate, __gnu_parallel::sequential_tag);
template<typename _FIter1, typename _FIter2, typename BinaryPredicate>
inline _FIter1
search(_FIter1, _FIter1, _FIter2, _FIter2, BinaryPredicate);
template<typename _RAIter1, typename _RAIter2>
_RAIter1
search_switch(_RAIter1, _RAIter1, _RAIter2, _RAIter2, random_access_iterator_tag, random_access_iterator_tag);
template<typename _FIter1, typename _FIter2, typename IteratorTag1, typename IteratorTag2>
inline _FIter1
search_switch(_FIter1, _FIter1, _FIter2, _FIter2, IteratorTag1, IteratorTag2);
template<typename _RAIter1, typename _RAIter2, typename BinaryPredicate>
_RAIter1
search_switch(_RAIter1, _RAIter1, _RAIter2, _RAIter2, BinaryPredicate , random_access_iterator_tag, random_access_iterator_tag);
template<typename _FIter1, typename _FIter2, typename BinaryPredicate, typename IteratorTag1, typename IteratorTag2>
inline _FIter1
search_switch(_FIter1, _FIter1, _FIter2, _FIter2, BinaryPredicate, IteratorTag1, IteratorTag2);
template<typename _FIter, typename Integer, typename T>
inline _FIter
search_n(_FIter, _FIter, Integer, const T&, __gnu_parallel::sequential_tag);
template<typename _FIter, typename Integer, typename T, typename BinaryPredicate>
inline _FIter
search_n(_FIter, _FIter, Integer, const T&, BinaryPredicate, __gnu_parallel::sequential_tag);
template<typename _FIter, typename Integer, typename T>
inline _FIter
search_n(_FIter, _FIter, Integer, const T& val);
template<typename _FIter, typename Integer, typename T, typename BinaryPredicate>
inline _FIter
search_n(_FIter, _FIter, Integer, const T&, BinaryPredicate);
template<typename _RAIter, typename Integer, typename T, typename BinaryPredicate>
_RAIter
search_n_switch(_RAIter, _RAIter, Integer, const T&, BinaryPredicate, random_access_iterator_tag);
template<typename _FIter, typename Integer, typename T, typename BinaryPredicate, typename IteratorTag>
inline _FIter
search_n_switch(_FIter, _FIter, Integer, const T&, BinaryPredicate, IteratorTag);
template<typename _IIter, typename _OIter, typename UnaryOperation>
inline _OIter
transform(_IIter, _IIter, _OIter, UnaryOperation, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter, typename BinaryOperation>
inline _OIter
transform(_IIter1, _IIter1, _IIter2, _OIter, BinaryOperation binary_op, __gnu_parallel::sequential_tag);
template<typename _IIter, typename _OIter, typename UnaryOperation>
inline _OIter
transform(_IIter, _IIter, _OIter, UnaryOperation, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _IIter1, typename _IIter2, typename _OIter, typename BinaryOperation>
inline _OIter
transform(_IIter1, _IIter1, _IIter2, _OIter, BinaryOperation binary_op, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _RAIter1, typename _RAIter3, typename UnaryOperation>
_RAIter3
transform1_switch(_RAIter1, _RAIter1, _RAIter3, UnaryOperation, random_access_iterator_tag, random_access_iterator_tag, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _RAIter1, typename _RAIter3, typename UnaryOperation, typename IteratorTag1, typename IteratorTag2>
inline _RAIter3
transform1_switch(_RAIter1, _RAIter1, _RAIter3, UnaryOperation, IteratorTag1, IteratorTag2, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _RAIter1, typename _RAIter2, typename _RAIter3, typename BinaryOperation>
_RAIter3
transform2_switch(_RAIter1, _RAIter1, _RAIter2, _RAIter3, BinaryOperation binary_op, random_access_iterator_tag, random_access_iterator_tag, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _RAIter1, typename _RAIter2, typename _RAIter3, typename BinaryOperation, typename tag1, typename tag2, typename tag3>
inline _RAIter3
transform2_switch(_RAIter1, _RAIter1, _RAIter2, _RAIter3, BinaryOperation binary_op, tag1, tag2, tag3, __gnu_parallel::parallelism);
template<typename _FIter, typename T>
inline void
replace(_FIter, _FIter, const T&, const T&, __gnu_parallel::sequential_tag);
template<typename _FIter, typename T>
inline void
replace(_FIter, _FIter, const T&, const T&, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _FIter, typename T, typename IteratorTag>
void
replace_switch(_FIter, _FIter, const T&, const T&, IteratorTag, __gnu_parallel::parallelism);
template<typename _RAIter, typename T>
void
replace_switch(_RAIter, _RAIter, const T&, const T&, random_access_iterator_tag, __gnu_parallel::parallelism);
template<typename _FIter, typename Predicate, typename T>
inline void
replace_if(_FIter, _FIter, Predicate, const T&, __gnu_parallel::sequential_tag);
template<typename _FIter, typename Predicate, typename T>
inline void
replace_if(_FIter, _FIter, Predicate, const T&, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _FIter, typename Predicate, typename T, typename IteratorTag>
void
replace_if_switch(_FIter, _FIter, Predicate, const T&, IteratorTag, __gnu_parallel::parallelism);
template<typename _RAIter, typename Predicate, typename T>
void
replace_if_switch(_RAIter, _RAIter, Predicate, const T&, random_access_iterator_tag, __gnu_parallel::parallelism);
template<typename _FIter>
inline _FIter
max_element(_FIter, _FIter, __gnu_parallel::sequential_tag);
template<typename _FIter, typename _Compare>
inline _FIter
max_element(_FIter, _FIter, _Compare, __gnu_parallel::sequential_tag);
template<typename _FIter>
inline _FIter
max_element(_FIter, _FIter, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _FIter, typename _Compare>
inline _FIter
max_element(_FIter, _FIter, _Compare, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _FIter, typename _Compare, typename IteratorTag>
_FIter
max_element_switch(_FIter, _FIter, _Compare, IteratorTag, __gnu_parallel::parallelism);
template<typename _RAIter, typename _Compare>
_RAIter
max_element_switch(_RAIter, _RAIter, _Compare, random_access_iterator_tag, __gnu_parallel::parallelism);
template<typename _IIter1, typename _IIter2, typename _OIter>
inline _OIter
merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter, typename _Compare>
inline _OIter
merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter, typename _Compare>
inline _OIter
merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare);
template<typename _IIter1, typename _IIter2, typename _OIter>
inline _OIter
merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter);
template<typename _IIter1, typename _IIter2, typename _OIter, typename _Compare, typename IteratorTag1, typename IteratorTag2, typename IteratorTag3>
inline _OIter
merge_switch(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare, IteratorTag1, IteratorTag2, IteratorTag3);
template<typename _IIter1, typename _IIter2, typename _OIter, typename _Compare>
_OIter
merge_switch(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare, random_access_iterator_tag, random_access_iterator_tag, random_access_iterator_tag);
template<typename _FIter>
inline _FIter
min_element(_FIter, _FIter, __gnu_parallel::sequential_tag);
template<typename _FIter, typename _Compare>
inline _FIter
min_element(_FIter, _FIter, _Compare, __gnu_parallel::sequential_tag);
template<typename _FIter>
inline _FIter
min_element(_FIter, _FIter, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _FIter, typename _Compare>
inline _FIter
min_element(_FIter, _FIter, _Compare, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _FIter, typename _Compare, typename IteratorTag>
_FIter
min_element_switch(_FIter, _FIter, _Compare, IteratorTag, __gnu_parallel::parallelism);
template<typename _RAIter, typename _Compare>
_RAIter
min_element_switch(_RAIter, _RAIter, _Compare, random_access_iterator_tag, __gnu_parallel::parallelism);
template<typename _RAIter>
inline void
nth_element(_RAIter, _RAIter, _RAIter, __gnu_parallel::sequential_tag);
template<typename _RAIter, typename _Compare>
void
nth_element(_RAIter, _RAIter, _RAIter, _Compare, __gnu_parallel::sequential_tag);
template<typename _RAIter, typename _Compare>
inline void
nth_element(_RAIter, _RAIter, _RAIter, _Compare);
template<typename _RAIter>
void
nth_element(_RAIter, _RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
partial_sort(_RAIter, _RAIter, _RAIter, _Compare, __gnu_parallel::sequential_tag);
template<typename _RAIter>
void
partial_sort(_RAIter, _RAIter, _RAIter, __gnu_parallel::sequential_tag);
template<typename _RAIter, typename _Compare>
void
partial_sort(_RAIter, _RAIter, _RAIter, _Compare);
template<typename _RAIter>
void
partial_sort(_RAIter, _RAIter, _RAIter);
template<typename _FIter, typename Predicate>
inline _FIter
partition(_FIter, _FIter, Predicate, __gnu_parallel::sequential_tag);
template<typename _FIter, typename Predicate>
inline _FIter
partition(_FIter, _FIter, Predicate);
template<typename _FIter, typename Predicate, typename IteratorTag>
inline _FIter
partition_switch(_FIter, _FIter, Predicate, IteratorTag);
template<typename _RAIter, typename Predicate>
_RAIter
partition_switch(_RAIter, _RAIter, Predicate, random_access_iterator_tag);
template<typename _RAIter>
inline void
random_shuffle(_RAIter, _RAIter, __gnu_parallel::sequential_tag);
template<typename _RAIter, typename RandomNumberGenerator>
inline void
random_shuffle(_RAIter, _RAIter, RandomNumberGenerator& rand, __gnu_parallel::sequential_tag);
template<typename _RAIter>
inline void
random_shuffle(_RAIter, _RAIter);
template<typename _RAIter, typename RandomNumberGenerator>
void
random_shuffle(_RAIter, _RAIter, RandomNumberGenerator& rand);
template<typename _IIter1, typename _IIter2, typename _OIter>
inline _OIter
set_union(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter, typename Predicate>
inline _OIter
set_union(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter>
inline _OIter
set_union(_IIter1, _IIter1, _IIter2, _IIter2, _OIter);
template<typename _IIter1, typename _IIter2, typename _OIter, typename Predicate>
inline _OIter
set_union(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate);
template<typename _IIter1, typename _IIter2, typename Predicate, typename _OIter, typename IteratorTag1, typename IteratorTag2, typename IteratorTag3>
inline _OIter
set_union_switch(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate, IteratorTag1, IteratorTag2, IteratorTag3);
template<typename _RAIter1, typename _RAIter2, typename Output_RAIter, typename Predicate>
Output_RAIter
set_union_switch(_RAIter1, _RAIter1, _RAIter2, _RAIter2, Output_RAIter, Predicate, random_access_iterator_tag, random_access_iterator_tag, random_access_iterator_tag);
template<typename _IIter1, typename _IIter2, typename _OIter>
inline _OIter
set_intersection(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter, typename Predicate>
inline _OIter
set_intersection(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter>
inline _OIter
set_intersection(_IIter1, _IIter1, _IIter2, _IIter2, _OIter);
template<typename _IIter1, typename _IIter2, typename _OIter, typename Predicate>
inline _OIter
set_intersection(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate);
template<typename _IIter1, typename _IIter2, typename Predicate, typename _OIter, typename IteratorTag1, typename IteratorTag2, typename IteratorTag3>
inline _OIter
set_intersection_switch(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate, IteratorTag1, IteratorTag2, IteratorTag3);
template<typename _RAIter1, typename _RAIter2, typename Output_RAIter, typename Predicate>
Output_RAIter
set_intersection_switch(_RAIter1, _RAIter1, _RAIter2, _RAIter2, Output_RAIter, Predicate, random_access_iterator_tag, random_access_iterator_tag, random_access_iterator_tag);
template<typename _IIter1, typename _IIter2, typename _OIter>
inline _OIter
set_symmetric_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter, typename Predicate>
inline _OIter
set_symmetric_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter>
inline _OIter
set_symmetric_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter);
template<typename _IIter1, typename _IIter2, typename _OIter, typename Predicate>
inline _OIter
set_symmetric_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate);
template<typename _IIter1, typename _IIter2, typename Predicate, typename _OIter, typename IteratorTag1, typename IteratorTag2, typename IteratorTag3>
inline _OIter
set_symmetric_difference_switch(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate, IteratorTag1, IteratorTag2, IteratorTag3);
template<typename _RAIter1, typename _RAIter2, typename Output_RAIter, typename Predicate>
Output_RAIter
set_symmetric_difference_switch(_RAIter1, _RAIter1, _RAIter2, _RAIter2, Output_RAIter, Predicate, random_access_iterator_tag, random_access_iterator_tag, random_access_iterator_tag);
template<typename _IIter1, typename _IIter2, typename _OIter>
inline _OIter
set_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter, typename Predicate>
inline _OIter
set_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename _OIter>
inline _OIter
set_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter);
template<typename _IIter1, typename _IIter2, typename _OIter, typename Predicate>
inline _OIter
set_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate);
template<typename _IIter1, typename _IIter2, typename Predicate, typename _OIter, typename IteratorTag1, typename IteratorTag2, typename IteratorTag3>
inline _OIter
set_difference_switch(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, Predicate, IteratorTag1, IteratorTag2, IteratorTag3);
template<typename _RAIter1, typename _RAIter2, typename Output_RAIter, typename Predicate>
Output_RAIter
set_difference_switch(_RAIter1, _RAIter1, _RAIter2, _RAIter2, Output_RAIter, Predicate, random_access_iterator_tag, random_access_iterator_tag, random_access_iterator_tag);
template<typename _RAIter>
inline void
sort(_RAIter, _RAIter, __gnu_parallel::sequential_tag);
template<typename _RAIter, typename _Compare>
inline void
sort(_RAIter, _RAIter, _Compare, __gnu_parallel::sequential_tag);
template<typename _RAIter>
inline void
sort(_RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
sort(_RAIter, _RAIter, _Compare);
template<typename _RAIter>
inline void
stable_sort(_RAIter, _RAIter, __gnu_parallel::sequential_tag);
template<typename _RAIter, typename _Compare>
inline void
stable_sort(_RAIter, _RAIter, _Compare, __gnu_parallel::sequential_tag);
template<typename _RAIter>
void
stable_sort(_RAIter, _RAIter);
template<typename _RAIter, typename _Compare>
void
stable_sort(_RAIter, _RAIter, _Compare);
template<typename _IIter, typename _OIter>
inline _OIter
unique_copy(_IIter, _IIter, _OIter, __gnu_parallel::sequential_tag);
template<typename _IIter, typename _OIter, typename Predicate>
inline _OIter
unique_copy(_IIter, _IIter, _OIter, Predicate, __gnu_parallel::sequential_tag);
template<typename _IIter, typename _OIter>
inline _OIter
unique_copy(_IIter, _IIter, _OIter);
template<typename _IIter, typename _OIter, typename Predicate>
inline _OIter
unique_copy(_IIter, _IIter, _OIter, Predicate);
template<typename _IIter, typename _OIter, typename Predicate, typename IteratorTag1, typename IteratorTag2>
inline _OIter
unique_copy_switch(_IIter, _IIter, _OIter, Predicate, IteratorTag1, IteratorTag2);
template<typename _RAIter, typename RandomAccess_OIter, typename Predicate>
RandomAccess_OIter
unique_copy_switch(_RAIter, _RAIter, RandomAccess_OIter, Predicate, random_access_iterator_tag, random_access_iterator_tag);
} // end namespace __parallel
} // end namespace std
// NB: cannot use _GLIBCXX_STD_P directly here, as it is both scoped
// (std::__norm) and unscoped (std::).
namespace __gnu_sequential
{
#ifdef _GLIBCXX_PARALLEL
using std::__norm::partition;
using std::__norm::sort;
using std::__norm::stable_sort;
using std::__norm::random_shuffle;
#else
using std::partition;
using std::sort;
using std::stable_sort;
using std::random_shuffle;
#endif
}
#endif

View File

@ -0,0 +1,451 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/balanced_quicksort.h
* @brief Implementation of a dynamically load-balanced parallel quicksort.
*
* It works in-place and needs only logarithmic extra memory.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_BAL_QUICKSORT_H
#define _GLIBCXX_PARALLEL_BAL_QUICKSORT_H 1
#include <parallel/basic_iterator.h>
#include <bits/stl_algo.h>
#include <parallel/settings.h>
#include <parallel/partition.h>
#include <parallel/random_number.h>
#include <parallel/queue.h>
#include <functional>
#if _GLIBCXX_ASSERTIONS
#include <parallel/checkers.h>
#endif
namespace __gnu_parallel
{
/** @brief Information local to one thread in the parallel quicksort run. */
template<typename RandomAccessIterator>
struct QSBThreadLocal
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::difference_type difference_type;
/** @brief Continuous part of the sequence, described by an
iterator pair. */
typedef std::pair<RandomAccessIterator, RandomAccessIterator> Piece;
/** @brief Initial piece to work on. */
Piece initial;
/** @brief Work-stealing queue. */
RestrictedBoundedConcurrentQueue<Piece> leftover_parts;
/** @brief Number of threads involved in this algorithm. */
thread_index_t num_threads;
/** @brief Pointer to a counter of elements left over to sort. */
volatile difference_type* elements_leftover;
/** @brief The complete sequence to sort. */
Piece global;
/** @brief Constructor.
* @param queue_size Size of the work-stealing queue. */
QSBThreadLocal(int queue_size) : leftover_parts(queue_size) { }
};
/** @brief Initialize the thread local storage.
* @param tls Array of thread-local storages.
* @param queue_size Size of the work-stealing queue. */
template<typename RandomAccessIterator>
inline void
qsb_initialize(QSBThreadLocal<RandomAccessIterator>** tls, int queue_size)
{
int iam = omp_get_thread_num();
tls[iam] = new QSBThreadLocal<RandomAccessIterator>(queue_size);
}
/** @brief Balanced quicksort divide step.
* @param begin Begin iterator of subsequence.
* @param end End iterator of subsequence.
* @param comp Comparator.
* @param num_threads Number of threads that are allowed to work on
* this part.
* @pre @c (end-begin)>=1 */
template<typename RandomAccessIterator, typename Comparator>
inline typename std::iterator_traits<RandomAccessIterator>::difference_type
qsb_divide(RandomAccessIterator begin, RandomAccessIterator end,
Comparator comp, int num_threads)
{
_GLIBCXX_PARALLEL_ASSERT(num_threads > 0);
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
RandomAccessIterator pivot_pos = median_of_three_iterators(begin, begin + (end - begin) / 2, end - 1, comp);
#if defined(_GLIBCXX_ASSERTIONS)
// Must be in between somewhere.
difference_type n = end - begin;
_GLIBCXX_PARALLEL_ASSERT((!comp(*pivot_pos, *begin) && !comp(*(begin + n / 2), *pivot_pos))
|| (!comp(*pivot_pos, *begin) && !comp(*end, *pivot_pos))
|| (!comp(*pivot_pos, *(begin + n / 2)) && !comp(*begin, *pivot_pos))
|| (!comp(*pivot_pos, *(begin + n / 2)) && !comp(*end, *pivot_pos))
|| (!comp(*pivot_pos, *end) && !comp(*begin, *pivot_pos))
|| (!comp(*pivot_pos, *end) && !comp(*(begin + n / 2), *pivot_pos)));
#endif
// Swap pivot value to end.
if (pivot_pos != (end - 1))
std::swap(*pivot_pos, *(end - 1));
pivot_pos = end - 1;
__gnu_parallel::binder2nd<Comparator, value_type, value_type, bool> pred(comp, *pivot_pos);
// Divide, returning end - begin - 1 in the worst case.
difference_type split_pos = parallel_partition(begin, end - 1, pred, num_threads);
// Swap back pivot to middle.
std::swap(*(begin + split_pos), *pivot_pos);
pivot_pos = begin + split_pos;
#if _GLIBCXX_ASSERTIONS
RandomAccessIterator r;
for (r = begin; r != pivot_pos; r++)
_GLIBCXX_PARALLEL_ASSERT(comp(*r, *pivot_pos));
for (; r != end; r++)
_GLIBCXX_PARALLEL_ASSERT(!comp(*r, *pivot_pos));
#endif
return split_pos;
}
/** @brief Quicksort conquer step.
* @param tls Array of thread-local storages.
* @param begin Begin iterator of subsequence.
* @param end End iterator of subsequence.
* @param comp Comparator.
* @param iam Number of the thread processing this function.
* @param num_threads Number of threads that are allowed to work on this part. */
template<typename RandomAccessIterator, typename Comparator>
inline void
qsb_conquer(QSBThreadLocal<RandomAccessIterator>** tls,
RandomAccessIterator begin, RandomAccessIterator end,
Comparator comp, thread_index_t iam, thread_index_t num_threads)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
difference_type n = end - begin;
if (num_threads <= 1 || n < 2)
{
tls[iam]->initial.first = begin;
tls[iam]->initial.second = end;
qsb_local_sort_with_helping(tls, comp, iam);
return;
}
// Divide step.
difference_type split_pos = qsb_divide(begin, end, comp, num_threads);
#if _GLIBCXX_ASSERTIONS
_GLIBCXX_PARALLEL_ASSERT(0 <= split_pos && split_pos < (end - begin));
#endif
thread_index_t num_threads_leftside = std::max<thread_index_t>(1, std::min<thread_index_t>(num_threads - 1, split_pos * num_threads / n));
#pragma omp atomic
*tls[iam]->elements_leftover -= (difference_type)1;
// Conquer step.
#pragma omp parallel sections num_threads(2)
{
#pragma omp section
qsb_conquer(tls, begin, begin + split_pos, comp, iam, num_threads_leftside);
// The pivot_pos is left in place, to ensure termination.
#pragma omp section
qsb_conquer(tls, begin + split_pos + 1, end, comp,
iam + num_threads_leftside, num_threads - num_threads_leftside);
}
}
/**
* @brief Quicksort step doing load-balanced local sort.
* @param tls Array of thread-local storages.
* @param comp Comparator.
* @param iam Number of the thread processing this function.
*/
template<typename RandomAccessIterator, typename Comparator>
inline void
qsb_local_sort_with_helping(QSBThreadLocal<RandomAccessIterator>** tls,
Comparator& comp, int iam)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
typedef std::pair<RandomAccessIterator, RandomAccessIterator> Piece;
QSBThreadLocal<RandomAccessIterator>& tl = *tls[iam];
difference_type base_case_n = Settings::sort_qsb_base_case_maximal_n;
if (base_case_n < 2)
base_case_n = 2;
thread_index_t num_threads = tl.num_threads;
// Every thread has its own random number generator.
random_number rng(iam + 1);
Piece current = tl.initial;
difference_type elements_done = 0;
#if _GLIBCXX_ASSERTIONS
difference_type total_elements_done = 0;
#endif
for (;;)
{
// Invariant: current must be a valid (maybe empty) range.
RandomAccessIterator begin = current.first, end = current.second;
difference_type n = end - begin;
if (n > base_case_n)
{
// Divide.
RandomAccessIterator pivot_pos = begin + rng(n);
// Swap pivot_pos value to end.
if (pivot_pos != (end - 1))
std::swap(*pivot_pos, *(end - 1));
pivot_pos = end - 1;
__gnu_parallel::binder2nd<Comparator, value_type, value_type, bool> pred(comp, *pivot_pos);
// Divide, leave pivot unchanged in last place.
RandomAccessIterator split_pos1, split_pos2;
split_pos1 = __gnu_sequential::partition(begin, end - 1, pred);
// Left side: < pivot_pos; right side: >= pivot_pos.
#if _GLIBCXX_ASSERTIONS
_GLIBCXX_PARALLEL_ASSERT(begin <= split_pos1 && split_pos1 < end);
#endif
// Swap pivot back to middle.
if (split_pos1 != pivot_pos)
std::swap(*split_pos1, *pivot_pos);
pivot_pos = split_pos1;
// In case all elements are equal, split_pos1 == 0.
if ((split_pos1 + 1 - begin) < (n >> 7)
|| (end - split_pos1) < (n >> 7))
{
// Very unequal split, one part smaller than one 128th
// elements not stricly larger than the pivot.
__gnu_parallel::unary_negate<__gnu_parallel::binder1st<Comparator, value_type, value_type, bool>, value_type> pred(__gnu_parallel::binder1st<Comparator, value_type, value_type, bool>(comp, *pivot_pos));
// Find other end of pivot-equal range.
split_pos2 = __gnu_sequential::partition(split_pos1 + 1, end, pred);
}
else
{
// Only skip the pivot.
split_pos2 = split_pos1 + 1;
}
// Elements equal to pivot are done.
elements_done += (split_pos2 - split_pos1);
#if _GLIBCXX_ASSERTIONS
total_elements_done += (split_pos2 - split_pos1);
#endif
// Always push larger part onto stack.
if (((split_pos1 + 1) - begin) < (end - (split_pos2)))
{
// Right side larger.
if ((split_pos2) != end)
tl.leftover_parts.push_front(std::make_pair(split_pos2, end));
//current.first = begin; //already set anyway
current.second = split_pos1;
continue;
}
else
{
// Left side larger.
if (begin != split_pos1)
tl.leftover_parts.push_front(std::make_pair(begin, split_pos1));
current.first = split_pos2;
//current.second = end; //already set anyway
continue;
}
}
else
{
__gnu_sequential::sort(begin, end, comp);
elements_done += n;
#if _GLIBCXX_ASSERTIONS
total_elements_done += n;
#endif
// Prefer own stack, small pieces.
if (tl.leftover_parts.pop_front(current))
continue;
#pragma omp atomic
*tl.elements_leftover -= elements_done;
elements_done = 0;
#if _GLIBCXX_ASSERTIONS
double search_start = omp_get_wtime();
#endif
// Look for new work.
bool success = false;
while (*tl.elements_leftover > 0 && !success
#if _GLIBCXX_ASSERTIONS
// Possible dead-lock.
&& (omp_get_wtime() < (search_start + 1.0))
#endif
)
{
thread_index_t victim;
victim = rng(num_threads);
// Large pieces.
success = (victim != iam) && tls[victim]->leftover_parts.pop_back(current);
if (!success)
yield();
#if !defined(__ICC) && !defined(__ECC)
#pragma omp flush
#endif
}
#if _GLIBCXX_ASSERTIONS
if (omp_get_wtime() >= (search_start + 1.0))
{
sleep(1);
_GLIBCXX_PARALLEL_ASSERT(omp_get_wtime() < (search_start + 1.0));
}
#endif
if (!success)
{
#if _GLIBCXX_ASSERTIONS
_GLIBCXX_PARALLEL_ASSERT(*tl.elements_leftover == 0);
#endif
return;
}
}
}
}
/** @brief Top-level quicksort routine.
* @param begin Begin iterator of sequence.
* @param end End iterator of sequence.
* @param comp Comparator.
* @param n Length of the sequence to sort.
* @param num_threads Number of threads that are allowed to work on
* this part.
*/
template<typename RandomAccessIterator, typename Comparator>
inline void
parallel_sort_qsb(RandomAccessIterator begin, RandomAccessIterator end,
Comparator comp,
typename std::iterator_traits<RandomAccessIterator>::difference_type n, int num_threads)
{
_GLIBCXX_CALL(end - begin)
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
typedef std::pair<RandomAccessIterator, RandomAccessIterator> Piece;
typedef QSBThreadLocal<RandomAccessIterator> tls_type;
if (n <= 1)
return;
// At least one element per processor.
if (num_threads > n)
num_threads = static_cast<thread_index_t>(n);
tls_type** tls = new tls_type*[num_threads];
#pragma omp parallel num_threads(num_threads)
// Initialize variables per processor.
qsb_initialize(tls, num_threads * (thread_index_t)(log2(n) + 1));
// There can never be more than ceil(log2(n)) ranges on the stack, because
// 1. Only one processor pushes onto the stack
// 2. The largest range has at most length n
// 3. Each range is larger than half of the range remaining
volatile difference_type elements_leftover = n;
for (int i = 0; i < num_threads; i++)
{
tls[i]->elements_leftover = &elements_leftover;
tls[i]->num_threads = num_threads;
tls[i]->global = std::make_pair(begin, end);
// Just in case nothing is left to assign.
tls[i]->initial = std::make_pair(end, end);
}
// Initial splitting, recursively.
int old_nested = omp_get_nested();
omp_set_nested(true);
// Main recursion call.
qsb_conquer(tls, begin, begin + n, comp, 0, num_threads);
omp_set_nested(old_nested);
#if _GLIBCXX_ASSERTIONS
// All stack must be empty.
Piece dummy;
for (int i = 1; i < num_threads; i++)
_GLIBCXX_PARALLEL_ASSERT(!tls[i]->leftover_parts.pop_back(dummy));
#endif
for (int i = 0; i < num_threads; i++)
delete tls[i];
delete[] tls;
}
} // namespace __gnu_parallel
#endif

View File

@ -0,0 +1,358 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/base.h
* @brief Sequential helper functions.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_BASE_H
#define _GLIBCXX_PARALLEL_BASE_H 1
#include <parallel/features.h>
#include <functional>
#include <parallel/basic_iterator.h>
#include <parallel/parallel.h>
#include <cstdio>
namespace __gnu_parallel
{
// XXX remove std::duplicates from here if possible,
// XXX but keep minimal dependencies.
/** @brief Calculates the rounded-down logrithm of @c n for base 2.
* @param n Argument.
* @return Returns 0 for argument 0.
*/
template<typename Size>
inline Size
log2(Size n)
{
Size k;
for (k = 0; n != 1; n >>= 1)
++k;
return k;
}
/** @brief Encode two integers into one __gnu_parallel::lcas_t.
* @param a First integer, to be encoded in the most-significant @c
* lcas_t_bits/2 bits.
* @param b Second integer, to be encoded in the least-significant
* @c lcas_t_bits/2 bits.
* @return __gnu_parallel::lcas_t value encoding @c a and @c b.
* @see decode2
*/
inline lcas_t
encode2(int a, int b) //must all be non-negative, actually
{
return (((lcas_t)a) << (lcas_t_bits / 2)) | (((lcas_t)b) << 0);
}
/** @brief Decode two integers from one __gnu_parallel::lcas_t.
* @param x __gnu_parallel::lcas_t to decode integers from.
* @param a First integer, to be decoded from the most-significant
* @c lcas_t_bits/2 bits of @c x.
* @param b Second integer, to be encoded in the least-significant
* @c lcas_t_bits/2 bits of @c x.
* @see encode2
*/
inline void
decode2(lcas_t x, int& a, int& b)
{
a = (int)((x >> (lcas_t_bits / 2)) & lcas_t_mask);
b = (int)((x >> 0 ) & lcas_t_mask);
}
/** @brief Constructs predicate for equality from strict weak
* ordering predicate
*/
// XXX comparator at the end, as per others
template<typename Comparator, typename T1, typename T2>
class equal_from_less : public std::binary_function<T1, T2, bool>
{
private:
Comparator& comp;
public:
equal_from_less(Comparator& _comp) : comp(_comp) { }
bool operator()(const T1& a, const T2& b)
{
// FIXME: wrong in general (T1 != T2)
return !comp(a, b) && !comp(b, a);
}
};
/** @brief Similar to std::equal_to, but allows two different types. */
template<typename T1, typename T2>
struct equal_to : std::binary_function<T1, T2, bool>
{
bool operator()(const T1& t1, const T2& t2) const
{ return t1 == t2; }
};
/** @brief Similar to std::binder1st, but giving the argument types explicitly. */
template<typename _Predicate, typename argument_type>
class unary_negate
: public std::unary_function<argument_type, bool>
{
protected:
_Predicate _M_pred;
public:
explicit
unary_negate(const _Predicate& __x) : _M_pred(__x) { }
bool
operator()(const argument_type& __x)
{ return !_M_pred(__x); }
};
/** @brief Similar to std::binder1st, but giving the argument types explicitly. */
template<typename _Operation, typename first_argument_type, typename second_argument_type, typename result_type>
class binder1st
: public std::unary_function<second_argument_type, result_type>
{
protected:
_Operation op;
first_argument_type value;
public:
binder1st(const _Operation& __x,
const first_argument_type& __y)
: op(__x), value(__y) { }
result_type
operator()(const second_argument_type& __x)
{ return op(value, __x); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 109. Missing binders for non-const sequence elements
result_type
operator()(second_argument_type& __x) const
{ return op(value, __x); }
};
/** @brief Similar to std::binder2nd, but giving the argument types explicitly. */
template<typename _Operation, typename first_argument_type, typename second_argument_type, typename result_type>
class binder2nd
: public std::unary_function<first_argument_type, result_type>
{
protected:
_Operation op;
second_argument_type value;
public:
binder2nd(const _Operation& __x,
const second_argument_type& __y)
: op(__x), value(__y) { }
result_type
operator()(const first_argument_type& __x) const
{ return op(__x, value); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 109. Missing binders for non-const sequence elements
result_type
operator()(first_argument_type& __x)
{ return op(__x, value); }
};
/** @brief Similar to std::less, but allows two different types. */
template<typename T1, typename T2>
struct less : std::binary_function<T1, T2, bool>
{
bool operator()(const T1& t1, const T2& t2) const
{ return t1 < t2; }
};
template<typename T, typename _DifferenceTp>
class pseudo_sequence;
/** @brief Iterator associated with __gnu_parallel::pseudo_sequence.
* If features the usual random-access iterator functionality.
* @param T Sequence value type.
* @param difference_type Sequence difference type.
*/
template<typename T, typename _DifferenceTp>
class pseudo_sequence_iterator
{
public:
typedef _DifferenceTp difference_type;
private:
typedef pseudo_sequence_iterator<T, _DifferenceTp> type;
const T& val;
difference_type pos;
public:
pseudo_sequence_iterator(const T& val, difference_type pos)
: val(val), pos(pos) { }
// Pre-increment operator.
type&
operator++()
{
++pos;
return *this;
}
// Post-increment operator.
const type
operator++(int)
{ return type(pos++); }
const T&
operator*() const
{ return val; }
const T&
operator[](difference_type) const
{ return val; }
bool
operator==(const type& i2)
{ return pos == i2.pos; }
difference_type
operator!=(const type& i2)
{ return pos != i2.pos; }
difference_type
operator-(const type& i2)
{ return pos - i2.pos; }
};
/** @brief Sequence that conceptually consists of multiple copies of
the same element.
* The copies are not stored explicitly, of course.
* @param T Sequence value type.
* @param difference_type Sequence difference type.
*/
template<typename T, typename _DifferenceTp>
class pseudo_sequence
{
typedef pseudo_sequence<T, _DifferenceTp> type;
public:
typedef _DifferenceTp difference_type;
typedef pseudo_sequence_iterator<T, uint64> iterator; //better case down to uint64, than up to _DifferenceTp
/** @brief Constructor.
* @param val Element of the sequence.
* @param count Number of (virtual) copies.
*/
pseudo_sequence(const T& val, difference_type count)
: val(val), count(count) { }
/** @brief Begin iterator. */
iterator
begin() const
{ return iterator(val, 0); }
/** @brief End iterator. */
iterator
end() const
{ return iterator(val, count); }
private:
const T& val;
difference_type count;
};
/** @brief Functor that does nothing */
template<typename _ValueTp>
class void_functor
{
inline void
operator()(const _ValueTp& v) const { }
};
/** @brief Compute the median of three referenced elements,
according to @c comp.
* @param a First iterator.
* @param b Second iterator.
* @param c Third iterator.
* @param comp Comparator.
*/
template<typename RandomAccessIterator, typename Comparator>
RandomAccessIterator
median_of_three_iterators(RandomAccessIterator a, RandomAccessIterator b,
RandomAccessIterator c, Comparator& comp)
{
if (comp(*a, *b))
if (comp(*b, *c))
return b;
else
if (comp(*a, *c))
return c;
else
return a;
else
{
// Just swap a and b.
if (comp(*a, *c))
return a;
else
if (comp(*b, *c))
return c;
else
return b;
}
}
// Avoid the use of assert, because we're trying to keep the <cassert>
// include out of the mix. (Same as debug mode).
inline void
__replacement_assert(const char* __file, int __line,
const char* __function, const char* __condition)
{
std::printf("%s:%d: %s: Assertion '%s' failed.\n", __file, __line,
__function, __condition);
__builtin_abort();
}
#define _GLIBCXX_PARALLEL_ASSERT(_Condition) \
do \
{ \
if (!(_Condition)) \
__gnu_parallel::__replacement_assert(__FILE__, __LINE__, \
__PRETTY_FUNCTION__, #_Condition); \
} while (false)
} //namespace __gnu_parallel
#endif

View File

@ -0,0 +1,48 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/basic_iterator.h
* @brief Includes the original header files concerned with iterators
* except for stream iterators.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_BASIC_ITERATOR_H
#define _GLIBCXX_PARALLEL_BASIC_ITERATOR_H 1
#include <bits/c++config.h>
#include <cstddef>
#include <bits/stl_iterator_base_types.h>
#include <bits/stl_iterator_base_funcs.h>
#include <bits/stl_iterator.h>
#endif /* _GLIBCXX_BASIC_ITERATOR_H */

View File

@ -0,0 +1,148 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/checkers.h
* @brief Routines for checking the correctness of algorithm results.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_CHECKERS
#define _GLIBCXX_PARALLEL_CHECKERS 1
#include <functional>
#include <cstdio>
#include <bits/stl_algobase.h>
namespace __gnu_parallel
{
/**
* @brief Check whether @c [begin, @c end) is sorted according to @c comp.
* @param begin Begin iterator of sequence.
* @param end End iterator of sequence.
* @param comp Comparator.
* @return @c true if sorted, @c false otherwise.
*/
// XXX Comparator default template argument
template<typename InputIterator, typename Comparator>
bool
is_sorted(InputIterator begin, InputIterator end, Comparator comp = std::less<typename std::iterator_traits<InputIterator>::value_type>())
{
if (begin == end)
return true;
InputIterator current(begin), recent(begin);
unsigned long long position = 1;
for (current++; current != end; current++)
{
if (comp(*current, *recent))
{
printf("is_sorted: check failed before position %i.\n", position);
return false;
}
recent = current;
position++;
}
return true;
}
/**
* @brief Check whether @c [begin, @c end) is sorted according to @c comp.
* Prints the position in case an misordered pair is found.
* @param begin Begin iterator of sequence.
* @param end End iterator of sequence.
* @param first_failure The first failure is returned in this variable.
* @param comp Comparator.
* @return @c true if sorted, @c false otherwise.
*/
// XXX Comparator default template argument
template<typename InputIterator, typename Comparator>
bool
is_sorted_failure(InputIterator begin, InputIterator end, InputIterator& first_failure, Comparator comp = std::less<typename std::iterator_traits<InputIterator>::value_type>())
{
if (begin == end)
return true;
InputIterator current(begin), recent(begin);
unsigned long long position = 1;
for (current++; current != end; current++)
{
if (comp(*current, *recent))
{
first_failure = current;
printf("is_sorted: check failed before position %lld.\n", position);
return false;
}
recent = current;
position++;
}
first_failure = end;
return true;
}
/**
* @brief Check whether @c [begin, @c end) is sorted according to @c comp.
* Prints all misordered pair, including the surrounding two elements.
* @param begin Begin iterator of sequence.
* @param end End iterator of sequence.
* @param comp Comparator.
* @return @c true if sorted, @c false otherwise.
*/
template<typename InputIterator, typename Comparator>
bool
// XXX Comparator default template argument
is_sorted_print_failures(InputIterator begin, InputIterator end, Comparator comp = std::less<typename std::iterator_traits<InputIterator>::value_type>())
{
if (begin == end)
return true;
InputIterator recent(begin);
bool ok = true;
for (InputIterator pos(begin + 1); pos != end; pos++)
{
if (comp(*pos, *recent))
{
printf("%ld: %d %d %d %d\n", pos - begin, *(pos - 2),
*(pos- 1), *pos, *(pos + 1));
ok = false;
}
recent = pos;
}
return ok;
}
}
#endif

View File

@ -0,0 +1,338 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/compatibility.h
* @brief Compatibility layer, mostly concerned with atomic operations.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze.
#ifndef _GLIBCXX_PARALLEL_COMPATIBILITY_H
#define _GLIBCXX_PARALLEL_COMPATIBILITY_H 1
#include <parallel/types.h>
#include <parallel/base.h>
#if defined(__SUNPRO_CC) && defined(__sparc)
#include <sys/atomic.h>
#endif
#if !defined(_WIN32)
#include <sched.h>
#endif
#if defined(_MSC_VER)
#include <Windows.h>
#include <intrin.h>
#undef max
#undef min
#endif
namespace __gnu_parallel
{
#if defined(__ICC)
template<typename must_be_int = int>
int32 faa32(int32* x, int32 inc)
{
asm volatile("lock xadd %0,%1"
: "=r" (inc), "=m" (*x)
: "0" (inc)
: "memory");
return inc;
}
#if defined(__x86_64)
template<typename must_be_int = int>
int64 faa64(int64* x, int64 inc)
{
asm volatile("lock xadd %0,%1"
: "=r" (inc), "=m" (*x)
: "0" (inc)
: "memory");
return inc;
}
#endif
#endif
// atomic functions only work on integers
/** @brief Add a value to a variable, atomically.
*
* Implementation is heavily platform-dependent.
* @param ptr Pointer to a 32-bit signed integer.
* @param addend Value to add.
*/
inline int32
fetch_and_add_32(volatile int32* ptr, int32 addend)
{
#if defined(__ICC) //x86 version
return _InterlockedExchangeAdd((void*)ptr, addend);
#elif defined(__ECC) //IA-64 version
return _InterlockedExchangeAdd((void*)ptr, addend);
#elif defined(__ICL) || defined(_MSC_VER)
return _InterlockedExchangeAdd(reinterpret_cast<volatile long*>(ptr), addend);
#elif defined(__GNUC__)
return __sync_fetch_and_add(ptr, addend);
#elif defined(__SUNPRO_CC) && defined(__sparc)
volatile int32 before, after;
do
{
before = *ptr;
after = before + addend;
} while (atomic_cas_32((volatile unsigned int*)ptr, before, after) != before);
return before;
#else //fallback, slow
#pragma message("slow fetch_and_add_32")
int32 res;
#pragma omp critical
{
res = *ptr;
*(ptr) += addend;
}
return res;
#endif
}
/** @brief Add a value to a variable, atomically.
*
* Implementation is heavily platform-dependent.
* @param ptr Pointer to a 64-bit signed integer.
* @param addend Value to add.
*/
inline int64
fetch_and_add_64(volatile int64* ptr, int64 addend)
{
#if defined(__ICC) && defined(__x86_64) //x86 version
return faa64<int>((int64*)ptr, addend);
#elif defined(__ECC) //IA-64 version
return _InterlockedExchangeAdd64((void*)ptr, addend);
#elif defined(__ICL) || defined(_MSC_VER)
#ifndef _WIN64
_GLIBCXX_PARALLEL_ASSERT(false); //not available in this case
return 0;
#else
return _InterlockedExchangeAdd64(ptr, addend);
#endif
#elif defined(__GNUC__) && defined(__x86_64)
return __sync_fetch_and_add(ptr, addend);
#elif defined(__GNUC__) && defined(__i386) && \
(defined(__i686) || defined(__pentium4) || defined(__athlon))
return __sync_fetch_and_add(ptr, addend);
#elif defined(__SUNPRO_CC) && defined(__sparc)
volatile int64 before, after;
do
{
before = *ptr;
after = before + addend;
} while (atomic_cas_64((volatile unsigned long long*)ptr, before, after) != before);
return before;
#else //fallback, slow
#if defined(__GNUC__) && defined(__i386)
// XXX doesn't work with -march=native
//#warning "please compile with -march=i686 or better"
#endif
#pragma message("slow fetch_and_add_64")
int64 res;
#pragma omp critical
{
res = *ptr;
*(ptr) += addend;
}
return res;
#endif
}
/** @brief Add a value to a variable, atomically.
*
* Implementation is heavily platform-dependent.
* @param ptr Pointer to a signed integer.
* @param addend Value to add.
*/
template<typename T>
inline T
fetch_and_add(volatile T* ptr, T addend)
{
if (sizeof(T) == sizeof(int32))
return (T)fetch_and_add_32((volatile int32*) ptr, (int32)addend);
else if (sizeof(T) == sizeof(int64))
return (T)fetch_and_add_64((volatile int64*) ptr, (int64)addend);
else
_GLIBCXX_PARALLEL_ASSERT(false);
}
#if defined(__ICC)
template<typename must_be_int = int>
inline int32
cas32(volatile int32* ptr, int32 old, int32 nw)
{
int32 before;
__asm__ __volatile__("lock; cmpxchgl %1,%2"
: "=a"(before)
: "q"(nw), "m"(*(volatile long long*)(ptr)), "0"(old)
: "memory");
return before;
}
#if defined(__x86_64)
template<typename must_be_int = int>
inline int64
cas64(volatile int64 *ptr, int64 old, int64 nw)
{
int64 before;
__asm__ __volatile__("lock; cmpxchgq %1,%2"
: "=a"(before)
: "q"(nw), "m"(*(volatile long long*)(ptr)), "0"(old)
: "memory");
return before;
}
#endif
#endif
/** @brief Compare @c *ptr and @c comparand. If equal, let @c
* *ptr=replacement and return @c true, return @c false otherwise.
*
* Implementation is heavily platform-dependent.
* @param ptr Pointer to 32-bit signed integer.
* @param comparand Compare value.
* @param replacement Replacement value.
*/
inline bool
compare_and_swap_32(volatile int32* ptr, int32 comparand, int32 replacement)
{
#if defined(__ICC) //x86 version
return _InterlockedCompareExchange((void*)ptr, replacement, comparand) == comparand;
#elif defined(__ECC) //IA-64 version
return _InterlockedCompareExchange((void*)ptr, replacement, comparand) == comparand;
#elif defined(__ICL) || defined(_MSC_VER)
return _InterlockedCompareExchange(reinterpret_cast<volatile long*>(ptr), replacement, comparand) == comparand;
#elif defined(__GNUC__)
return __sync_bool_compare_and_swap(ptr, comparand, replacement);
#elif defined(__SUNPRO_CC) && defined(__sparc)
return atomic_cas_32((volatile unsigned int*)ptr, comparand, replacement) == comparand;
#else
#pragma message("slow compare_and_swap_32")
bool res = false;
#pragma omp critical
{
if (*ptr == comparand)
{
*ptr = replacement;
res = true;
}
}
return res;
#endif
}
/** @brief Compare @c *ptr and @c comparand. If equal, let @c
* *ptr=replacement and return @c true, return @c false otherwise.
*
* Implementation is heavily platform-dependent.
* @param ptr Pointer to 64-bit signed integer.
* @param comparand Compare value.
* @param replacement Replacement value.
*/
inline bool
compare_and_swap_64(volatile int64* ptr, int64 comparand, int64 replacement)
{
#if defined(__ICC) && defined(__x86_64) //x86 version
return cas64<int>(ptr, comparand, replacement) == comparand;
#elif defined(__ECC) //IA-64 version
return _InterlockedCompareExchange64((void*)ptr, replacement, comparand) == comparand;
#elif defined(__ICL) || defined(_MSC_VER)
#ifndef _WIN64
_GLIBCXX_PARALLEL_ASSERT(false); //not available in this case
return 0;
#else
return _InterlockedCompareExchange64(ptr, replacement, comparand) == comparand;
#endif
#elif defined(__GNUC__) && defined(__x86_64)
return __sync_bool_compare_and_swap(ptr, comparand, replacement);
#elif defined(__GNUC__) && defined(__i386) && \
(defined(__i686) || defined(__pentium4) || defined(__athlon))
return __sync_bool_compare_and_swap(ptr, comparand, replacement);
#elif defined(__SUNPRO_CC) && defined(__sparc)
return atomic_cas_64((volatile unsigned long long*)ptr, comparand, replacement) == comparand;
#else
#if defined(__GNUC__) && defined(__i386)
// XXX -march=native
//#warning "please compile with -march=i686 or better"
#endif
#pragma message("slow compare_and_swap_64")
bool res = false;
#pragma omp critical
{
if (*ptr == comparand)
{
*ptr = replacement;
res = true;
}
}
return res;
#endif
}
/** @brief Compare @c *ptr and @c comparand. If equal, let @c
* *ptr=replacement and return @c true, return @c false otherwise.
*
* Implementation is heavily platform-dependent.
* @param ptr Pointer to signed integer.
* @param comparand Compare value.
* @param replacement Replacement value. */
template<typename T>
inline bool
compare_and_swap(volatile T* ptr, T comparand, T replacement)
{
if (sizeof(T) == sizeof(int32))
return compare_and_swap_32((volatile int32*) ptr, (int32)comparand, (int32)replacement);
else if (sizeof(T) == sizeof(int64))
return compare_and_swap_64((volatile int64*) ptr, (int64)comparand, (int64)replacement);
else
_GLIBCXX_PARALLEL_ASSERT(false);
}
/** @brief Yield the control to another thread, without waiting for
the end to the time slice. */
inline void
yield()
{
#ifdef _WIN32
Sleep(0);
#else
sched_yield();
#endif
}
} // end namespace
#endif

View File

@ -0,0 +1,76 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/compiletime_settings.h
* @brief Defines on options concerning debugging and performance, at
* compile-time.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#include <cstdio>
/** @brief Determine verbosity level of the parallel mode.
* Level 1 prints a message each time when entering a parallel-mode function. */
#define _GLIBCXX_VERBOSE_LEVEL 0
/** @def _GLIBCXX_CALL
* @brief Macro to produce log message when entering a function.
* @param n Input size.
* @see _GLIBCXX_VERBOSE_LEVEL */
#if (_GLIBCXX_VERBOSE_LEVEL == 0)
#define _GLIBCXX_CALL(n)
#endif
#if (_GLIBCXX_VERBOSE_LEVEL == 1)
#define _GLIBCXX_CALL(n) printf(" %s:\niam = %d, n = %ld, num_threads = %d\n", __PRETTY_FUNCTION__, omp_get_thread_num(), (n), get_max_threads());
#endif
/** @brief Use floating-point scaling instead of modulo for mapping
* random numbers to a range. This can be faster on certain CPUs. */
#define _GLIBCXX_SCALE_DOWN_FPU 0
/** @brief Switch on many _GLIBCXX_PARALLEL_ASSERTions in parallel code.
* Should be switched on only locally. */
#define _GLIBCXX_ASSERTIONS 0
/** @brief Switch on many _GLIBCXX_PARALLEL_ASSERTions in parallel code.
* Consider the size of the L1 cache for __gnu_parallel::parallel_random_shuffle(). */
#define _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_L1 0
/** @brief Switch on many _GLIBCXX_PARALLEL_ASSERTions in parallel code.
* Consider the size of the TLB for __gnu_parallel::parallel_random_shuffle(). */
#define _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_TLB 0
/** @brief First copy the data, sort it locally, and merge it back
* (0); or copy it back after everyting is done (1).
*
* Recommendation: 0 */
#define _GLIBCXX_MULTIWAY_MERGESORT_COPY_LAST 0

View File

@ -0,0 +1,68 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/equally_split.h
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_EQUALLY_SPLIT_H
#define _GLIBCXX_PARALLEL_EQUALLY_SPLIT_H 1
namespace __gnu_parallel
{
/** @brief Function to split a sequence into parts of almost equal size.
*
* The resulting sequence s of length p+1 contains the splitting
* positions when splitting the range [0,n) into parts of almost
* equal size (plus minus 1). The first entry is 0, the last one
* n. There may result empty parts.
* @param n Number of elements
* @param p Number of parts
* @param s Splitters
* @returns End of splitter sequence, i. e. @c s+p+1 */
template<typename _DifferenceTp, typename OutputIterator>
OutputIterator
equally_split(_DifferenceTp n, thread_index_t p, OutputIterator s)
{
typedef _DifferenceTp difference_type;
difference_type chunk_length = n / p, split = n % p, start = 0;
for (int i = 0; i < p; i++)
{
*s++ = start;
start += (difference_type(i) < split) ? (chunk_length + 1) : chunk_length;
}
*s++ = n;
return s;
}
}
#endif

View File

@ -0,0 +1,170 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/features.h
* @brief Defines on whether to include algorithm variants.
*
* Less variants reduce executable size and compile time.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_FEATURES_H
#define _GLIBCXX_PARALLEL_FEATURES_H 1
#ifndef _GLIBCXX_MERGESORT
/** @def _GLIBCXX_MERGESORT
* @brief Include parallel multi-way mergesort.
* @see __gnu_parallel::Settings::sort_algorithm */
#define _GLIBCXX_MERGESORT 1
#endif
#ifndef _GLIBCXX_QUICKSORT
/** @def _GLIBCXX_QUICKSORT
* @brief Include parallel unbalanced quicksort.
* @see __gnu_parallel::Settings::sort_algorithm */
#define _GLIBCXX_QUICKSORT 1
#endif
#ifndef _GLIBCXX_BAL_QUICKSORT
/** @def _GLIBCXX_BAL_QUICKSORT
* @brief Include parallel dynamically load-balanced quicksort.
* @see __gnu_parallel::Settings::sort_algorithm */
#define _GLIBCXX_BAL_QUICKSORT 1
#endif
#ifndef _GLIBCXX_LOSER_TREE
/** @def _GLIBCXX_LOSER_TREE
* @brief Include guarded (sequences may run empty) loser tree,
* moving objects.
* @see __gnu_parallel::Settings multiway_merge_algorithm */
#define _GLIBCXX_LOSER_TREE 1
#endif
#ifndef _GLIBCXX_LOSER_TREE_EXPLICIT
/** @def _GLIBCXX_LOSER_TREE_EXPLICIT
* @brief Include standard loser tree, storing two flags for infimum
* and supremum.
* @see __gnu_parallel::Settings multiway_merge_algorithm */
#define _GLIBCXX_LOSER_TREE_EXPLICIT 0
#endif
#ifndef _GLIBCXX_LOSER_TREE_REFERENCE
/** @def _GLIBCXX_LOSER_TREE_REFERENCE
* @brief Include some loser tree variant.
* @see __gnu_parallel::Settings multiway_merge_algorithm */
#define _GLIBCXX_LOSER_TREE_REFERENCE 0
#endif
#ifndef _GLIBCXX_LOSER_TREE_POINTER
/** @def _GLIBCXX_LOSER_TREE_POINTER
* @brief Include some loser tree variant.
* @see __gnu_parallel::Settings multiway_merge_algorithm */
#define _GLIBCXX_LOSER_TREE_POINTER 0
#endif
#ifndef _GLIBCXX_LOSER_TREE_UNGUARDED
/** @def _GLIBCXX_LOSER_TREE_UNGUARDED
* @brief Include unguarded (sequences must not run empty) loser
* tree, moving objects.
* @see __gnu_parallel::Settings multiway_merge_algorithm */
#define _GLIBCXX_LOSER_TREE_UNGUARDED 1
#endif
#ifndef _GLIBCXX_LOSER_TREE_POINTER_UNGUARDED
/** @def _GLIBCXX_LOSER_TREE_POINTER_UNGUARDED
* @brief Include some loser tree variant.
* @see __gnu_parallel::Settings multiway_merge_algorithm */
#define _GLIBCXX_LOSER_TREE_POINTER_UNGUARDED 0
#endif
#ifndef _GLIBCXX_LOSER_TREE_COMBINED
/** @def _GLIBCXX_LOSER_TREE_COMBINED
* @brief Include some loser tree variant.
* @see __gnu_parallel::Settings multiway_merge_algorithm */
#define _GLIBCXX_LOSER_TREE_COMBINED 0
#endif
#ifndef _GLIBCXX_LOSER_TREE_SENTINEL
/** @def _GLIBCXX_LOSER_TREE_SENTINEL
* @brief Include some loser tree variant.
* @see __gnu_parallel::Settings multiway_merge_algorithm */
#define _GLIBCXX_LOSER_TREE_SENTINEL 0
#endif
#ifndef _GLIBCXX_FIND_GROWING_BLOCKS
/** @brief Include the growing blocks variant for std::find.
* @see __gnu_parallel::Settings::find_distribution */
#define _GLIBCXX_FIND_GROWING_BLOCKS 1
#endif
#ifndef _GLIBCXX_FIND_CONSTANT_SIZE_BLOCKS
/** @brief Include the equal-sized blocks variant for std::find.
* @see __gnu_parallel::Settings::find_distribution */
#define _GLIBCXX_FIND_CONSTANT_SIZE_BLOCKS 1
#endif
#ifndef _GLIBCXX_FIND_EQUAL_SPLIT
/** @def _GLIBCXX_FIND_EQUAL_SPLIT
* @brief Include the equal splitting variant for std::find.
* @see __gnu_parallel::Settings::find_distribution */
#define _GLIBCXX_FIND_EQUAL_SPLIT 1
#endif
#ifndef _GLIBCXX_TREE_INITIAL_SPLITTING
/** @def _GLIBCXX_TREE_INITIAL_SPLITTING
* @brief Include the initial splitting variant for
* _Rb_tree::insert_unique(InputIterator beg, InputIterator end).
* @see __gnu_parallel::_Rb_tree */
#define _GLIBCXX_TREE_INITIAL_SPLITTING 1
#endif
#ifndef _GLIBCXX_TREE_DYNAMIC_BALANCING
/** @def _GLIBCXX_TREE_DYNAMIC_BALANCING
* @brief Include the dynamic balancing variant for
* _Rb_tree::insert_unique(InputIterator beg, InputIterator end).
* @see __gnu_parallel::_Rb_tree */
#define _GLIBCXX_TREE_DYNAMIC_BALANCING 1
#endif
#ifndef _GLIBCXX_TREE_FULL_COPY
/** @def _GLIBCXX_TREE_FULL_COPY
* @brief In order to sort the input sequence of
* _Rb_tree::insert_unique(InputIterator beg, InputIterator end) a
* full copy of the input elements is done.
* @see __gnu_parallel::_Rb_tree */
#define _GLIBCXX_TREE_FULL_COPY 1
#endif
#endif

View File

@ -0,0 +1,340 @@
/// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/find.h
* @brief Parallel implementation base for std::find(), std::equal()
* and related functions.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze and Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_FIND_H
#define _GLIBCXX_PARALLEL_FIND_H 1
#include <bits/stl_algobase.h>
#include <parallel/features.h>
#include <parallel/parallel.h>
#include <parallel/compatibility.h>
#include <parallel/equally_split.h>
namespace __gnu_parallel
{
/**
* @brief Parallel std::find, switch for different algorithms.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence. Must have same
* length as first sequence.
* @param pred Find predicate.
* @param selector Functionality (e. g. std::find_if (), std::equal(),...)
* @return Place of finding in both sequences.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred, typename Selector>
std::pair<RandomAccessIterator1, RandomAccessIterator2>
find_template(RandomAccessIterator1 begin1, RandomAccessIterator1 end1,
RandomAccessIterator2 begin2, Pred pred, Selector selector)
{
switch (Settings::find_distribution)
{
case Settings::GROWING_BLOCKS:
return find_template(begin1, end1, begin2, pred, selector, growing_blocks_tag());
case Settings::CONSTANT_SIZE_BLOCKS:
return find_template(begin1, end1, begin2, pred, selector, constant_size_blocks_tag());
case Settings::EQUAL_SPLIT:
return find_template(begin1, end1, begin2, pred, selector, equal_split_tag());
default:
_GLIBCXX_PARALLEL_ASSERT(false);
return std::make_pair(begin1, begin2);
}
}
#if _GLIBCXX_FIND_EQUAL_SPLIT
/**
* @brief Parallel std::find, equal splitting variant.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence. Second sequence
* must have same length as first sequence.
* @param pred Find predicate.
* @param selector Functionality (e. g. std::find_if (), std::equal(),...)
* @return Place of finding in both sequences.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred, typename Selector>
std::pair<RandomAccessIterator1, RandomAccessIterator2>
find_template(RandomAccessIterator1 begin1, RandomAccessIterator1 end1, RandomAccessIterator2 begin2, Pred pred, Selector selector, equal_split_tag)
{
_GLIBCXX_CALL(end1 - begin1)
typedef std::iterator_traits<RandomAccessIterator1> traits_type;
typedef typename traits_type::difference_type difference_type;
typedef typename traits_type::value_type value_type;
difference_type length = end1 - begin1;
difference_type result = length;
const thread_index_t num_threads = get_max_threads();
// XXX VLA error.
difference_type borders[num_threads + 1];
equally_split(length, num_threads, borders);
#pragma omp parallel shared(result) num_threads(num_threads)
{
int iam = omp_get_thread_num();
difference_type pos = borders[iam], limit = borders[iam + 1];
RandomAccessIterator1 i1 = begin1 + pos;
RandomAccessIterator2 i2 = begin2 + pos;
for (; pos < limit; pos++)
{
#pragma omp flush(result)
// Result has been set to something lower.
if (result < pos)
break;
if (selector(i1, i2, pred))
{
#pragma omp critical (result)
if (result > pos)
result = pos;
break;
}
i1++;
i2++;
}
}
return std::pair<RandomAccessIterator1, RandomAccessIterator2>(begin1 + result, begin2 + result);
}
#endif
#if _GLIBCXX_FIND_GROWING_BLOCKS
/**
* @brief Parallel std::find, growing block size variant.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence. Second sequence
* must have same length as first sequence.
* @param pred Find predicate.
* @param selector Functionality (e. g. std::find_if (), std::equal(),...)
* @return Place of finding in both sequences.
* @see __gnu_parallel::Settings::find_sequential_search_size
* @see __gnu_parallel::Settings::find_initial_block_size
* @see __gnu_parallel::Settings::find_maximum_block_size
* @see __gnu_parallel::Settings::find_increasing_factor
*
* There are two main differences between the growing blocks and
* the constant-size blocks variants.
* 1. For GB, the block size grows; for CSB, the block size is fixed.
* 2. For GB, the blocks are allocated dynamically;
* for CSB, the blocks are allocated in a predetermined manner,
* namely spacial round-robin.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred, typename Selector>
std::pair<RandomAccessIterator1, RandomAccessIterator2>
find_template(RandomAccessIterator1 begin1, RandomAccessIterator1 end1,
RandomAccessIterator2 begin2, Pred pred, Selector selector,
growing_blocks_tag)
{
_GLIBCXX_CALL(end1 - begin1)
typedef std::iterator_traits<RandomAccessIterator1> traits_type;
typedef typename traits_type::difference_type difference_type;
typedef typename traits_type::value_type value_type;
difference_type length = end1 - begin1;
difference_type sequential_search_size = std::min<difference_type>(length, Settings::find_sequential_search_size);
// Try it sequentially first.
std::pair<RandomAccessIterator1, RandomAccessIterator2> find_seq_result =
selector.sequential_algorithm(begin1, begin1 + sequential_search_size, begin2, pred);
if (find_seq_result.first != (begin1 + sequential_search_size))
return find_seq_result;
// Index of beginning of next free block (after sequential find).
difference_type next_block_pos = sequential_search_size;
difference_type result = length;
const thread_index_t num_threads = get_max_threads();
#pragma omp parallel shared(result) num_threads(num_threads)
{
// Not within first k elements -> start parallel.
thread_index_t iam = omp_get_thread_num();
difference_type block_size = Settings::find_initial_block_size;
difference_type start = fetch_and_add<difference_type>(&next_block_pos, block_size);
// Get new block, update pointer to next block.
difference_type stop = std::min<difference_type>(length, start + block_size);
std::pair<RandomAccessIterator1, RandomAccessIterator2> local_result;
while (start < length)
{
#pragma omp flush(result)
// Get new value of result.
if (result < start)
{
// No chance to find first element.
break;
}
local_result = selector.sequential_algorithm(begin1 + start, begin1 + stop, begin2 + start, pred);
if (local_result.first != (begin1 + stop))
{
#pragma omp critical(result)
if ((local_result.first - begin1) < result)
{
result = local_result.first - begin1;
// Result cannot be in future blocks, stop algorithm.
fetch_and_add<difference_type>(&next_block_pos, length);
}
}
block_size = std::min<difference_type>(block_size * Settings::find_increasing_factor, Settings::find_maximum_block_size);
// Get new block, update pointer to next block.
start = fetch_and_add<difference_type>(&next_block_pos, block_size);
stop = (length < (start + block_size)) ? length : (start + block_size);
}
}
// Return iterator on found element.
return std::pair<RandomAccessIterator1, RandomAccessIterator2>(begin1 + result, begin2 + result);
}
#endif
#if _GLIBCXX_FIND_CONSTANT_SIZE_BLOCKS
/**
* @brief Parallel std::find, constant block size variant.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence. Second sequence
* must have same length as first sequence.
* @param pred Find predicate.
* @param selector Functionality (e. g. std::find_if (), std::equal(),...)
* @return Place of finding in both sequences.
* @see __gnu_parallel::Settings::find_sequential_search_size
* @see __gnu_parallel::Settings::find_block_size
* There are two main differences between the growing blocks and the
* constant-size blocks variants.
* 1. For GB, the block size grows; for CSB, the block size is fixed.
* 2. For GB, the blocks are allocated dynamically; for CSB, the
* blocks are allocated in a predetermined manner, namely spacial
* round-robin.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred, typename Selector>
std::pair<RandomAccessIterator1, RandomAccessIterator2>
find_template(RandomAccessIterator1 begin1, RandomAccessIterator1 end1,
RandomAccessIterator2 begin2, Pred pred, Selector selector,
constant_size_blocks_tag)
{
_GLIBCXX_CALL(end1 - begin1)
typedef std::iterator_traits<RandomAccessIterator1> traits_type;
typedef typename traits_type::difference_type difference_type;
typedef typename traits_type::value_type value_type;
difference_type length = end1 - begin1;
difference_type sequential_search_size = std::min<difference_type>(length, Settings::find_sequential_search_size);
// Try it sequentially first.
std::pair<RandomAccessIterator1, RandomAccessIterator2> find_seq_result =
selector.sequential_algorithm(begin1, begin1 + sequential_search_size, begin2, pred);
if (find_seq_result.first != (begin1 + sequential_search_size))
return find_seq_result;
difference_type result = length;
const thread_index_t num_threads = get_max_threads();
// Not within first sequential_search_size elements -> start parallel.
#pragma omp parallel shared(result) num_threads(num_threads)
{
thread_index_t iam = omp_get_thread_num();
difference_type block_size = Settings::find_initial_block_size;
difference_type start, stop;
// First element of thread's current iteration.
difference_type iteration_start = sequential_search_size;
// Where to work (initialization).
start = iteration_start + iam * block_size;
stop = std::min<difference_type>(length, start + block_size);
std::pair<RandomAccessIterator1, RandomAccessIterator2> local_result;
while (start < length)
{
// Get new value of result.
#pragma omp flush(result)
// No chance to find first element.
if (result < start)
break;
local_result = selector.sequential_algorithm(begin1 + start, begin1 + stop, begin2 + start, pred);
if (local_result.first != (begin1 + stop))
{
#pragma omp critical(result)
if ((local_result.first - begin1) < result)
result = local_result.first - begin1;
// Will not find better value in its interval.
break;
}
iteration_start += num_threads * block_size;
// Where to work.
start = iteration_start + iam * block_size;
stop = std::min<difference_type>(length, start + block_size);
}
}
// Return iterator on found element.
return std::pair<RandomAccessIterator1, RandomAccessIterator2>(begin1 + result, begin2 + result);
}
#endif
} // end namespace
#endif

View File

@ -0,0 +1,184 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/find_selectors.h
* @brief Function objects representing different tasks to be plugged
* into the parallel find algorithm.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze.
#ifndef _GLIBCXX_PARALLEL_FIND_FUNCTIONS_H
#define _GLIBCXX_PARALLEL_FIND_FUNCTIONS_H 1
#include <parallel/tags.h>
#include <parallel/basic_iterator.h>
#include <bits/stl_pair.h>
namespace __gnu_parallel
{
/** @brief Base class of all __gnu_parallel::find_template selectors. */
struct generic_find_selector
{ };
/**
* @brief Test predicate on a single element, used for std::find()
* and std::find_if ().
*/
struct find_if_selector : public generic_find_selector
{
/** @brief Test on one position.
* @param i1 Iterator on first sequence.
* @param i2 Iterator on second sequence (unused).
* @param pred Find predicate.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred>
inline bool
operator()(RandomAccessIterator1 i1, RandomAccessIterator2 i2, Pred pred)
{ return pred(*i1); }
/** @brief Corresponding sequential algorithm on a sequence.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence.
* @param pred Find predicate.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred>
inline std::pair<RandomAccessIterator1, RandomAccessIterator2>
sequential_algorithm(RandomAccessIterator1 begin1, RandomAccessIterator1 end1, RandomAccessIterator2 begin2, Pred pred)
{
return std::make_pair(find_if(begin1, end1, pred, sequential_tag()), begin2);
}
};
/** @brief Test predicate on two adjacent elements. */
struct adjacent_find_selector : public generic_find_selector
{
/** @brief Test on one position.
* @param i1 Iterator on first sequence.
* @param i2 Iterator on second sequence (unused).
* @param pred Find predicate.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred>
inline bool
operator()(RandomAccessIterator1 i1, RandomAccessIterator2 i2, Pred pred)
{
// Passed end iterator is one short.
return pred(*i1, *(i1 + 1));
}
/** @brief Corresponding sequential algorithm on a sequence.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence.
* @param pred Find predicate.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred>
inline std::pair<RandomAccessIterator1, RandomAccessIterator2>
sequential_algorithm(RandomAccessIterator1 begin1, RandomAccessIterator1 end1, RandomAccessIterator2 begin2, Pred pred)
{
// Passed end iterator is one short.
RandomAccessIterator1 spot = adjacent_find(begin1, end1 + 1, pred, sequential_tag());
if (spot == (end1 + 1))
spot = end1;
return std::make_pair(spot, begin2);
}
};
/** @brief Test inverted predicate on a single element. */
struct mismatch_selector : public generic_find_selector
{
/**
* @brief Test on one position.
* @param i1 Iterator on first sequence.
* @param i2 Iterator on second sequence (unused).
* @param pred Find predicate.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred>
inline bool
operator()(RandomAccessIterator1 i1, RandomAccessIterator2 i2, Pred pred)
{ return !pred(*i1, *i2); }
/**
* @brief Corresponding sequential algorithm on a sequence.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence.
* @param pred Find predicate.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred>
inline std::pair<RandomAccessIterator1, RandomAccessIterator2>
sequential_algorithm(RandomAccessIterator1 begin1, RandomAccessIterator1 end1, RandomAccessIterator2 begin2, Pred pred)
{
return mismatch(begin1, end1, begin2, pred, sequential_tag());
}
};
/** @brief Test predicate on several elements. */
template<typename ForwardIterator>
struct find_first_of_selector : public generic_find_selector
{
ForwardIterator begin;
ForwardIterator end;
explicit find_first_of_selector(ForwardIterator begin, ForwardIterator end)
: begin(begin), end(end) { }
/** @brief Test on one position.
* @param i1 Iterator on first sequence.
* @param i2 Iterator on second sequence (unused).
* @param pred Find predicate. */
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred>
inline bool
operator()(RandomAccessIterator1 i1, RandomAccessIterator2 i2, Pred pred)
{
for (ForwardIterator pos_in_candidates = begin; pos_in_candidates != end; pos_in_candidates++)
if (pred(*i1, *pos_in_candidates))
return true;
return false;
}
/** @brief Corresponding sequential algorithm on a sequence.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence.
* @param pred Find predicate. */
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename Pred>
inline std::pair<RandomAccessIterator1, RandomAccessIterator2>
sequential_algorithm(RandomAccessIterator1 begin1, RandomAccessIterator1 end1, RandomAccessIterator2 begin2, Pred pred)
{
return std::make_pair(find_first_of(begin1, end1, begin, end, pred, sequential_tag()), begin2);
}
};
}
#endif

View File

@ -0,0 +1,83 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/for_each.h
* @brief Main interface for embarassingly parallel functions.
*
* The explicit implementation are in other header files, like
* workstealing.h, par_loop.h, omp_loop.h, and omp_loop_static.h.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze.
#ifndef _GLIBCXX_PARALLEL_FOR_EACH_H
#define _GLIBCXX_PARALLEL_FOR_EACH_H 1
#include <parallel/settings.h>
#include <parallel/par_loop.h>
#include <parallel/omp_loop.h>
#include <parallel/workstealing.h>
namespace __gnu_parallel
{
/** @brief Chose the desired algorithm by evaluating @c parallelism_tag.
* @param begin Begin iterator of input sequence.
* @param end End iterator of input sequence.
* @param user_op A user-specified functor (comparator, predicate,
* associative operator,...)
* @param functionality functor to "process" an element with
* user_op (depends on desired functionality, e. g. accumulate,
* for_each,...
* @param reduction Reduction functor.
* @param reduction_start Initial value for reduction.
* @param output Output iterator.
* @param bound Maximum number of elements processed.
* @param parallelism_tag Parallelization method */
template<typename InputIterator, typename UserOp, typename Functionality, typename Red, typename Result>
UserOp
for_each_template_random_access(InputIterator begin, InputIterator end,
UserOp user_op, Functionality& functionality,
Red reduction, Result reduction_start,
Result& output,
typename std::iterator_traits<InputIterator>::difference_type bound, parallelism parallelism_tag)
{
if (parallelism_tag == parallel_unbalanced)
return for_each_template_random_access_ed(begin, end, user_op, functionality, reduction, reduction_start, output, bound);
else if (parallelism_tag == parallel_omp_loop)
return for_each_template_random_access_omp_loop(begin, end, user_op, functionality, reduction, reduction_start, output, bound);
else if (parallelism_tag == parallel_omp_loop_static)
return for_each_template_random_access_omp_loop(begin, end, user_op, functionality, reduction, reduction_start, output, bound);
else //e. g. parallel_balanced
return for_each_template_random_access_workstealing(begin, end, user_op, functionality, reduction, reduction_start, output, bound);
}
}
#endif

View File

@ -0,0 +1,343 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/for_each_selectors.h
* @brief Functors representing different tasks to be plugged into the
* generic parallelization methods for embarrassingly parallel functions.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze.
#ifndef _GLIBCXX_PARALLEL_FOR_EACH_SELECTORS_H
#define _GLIBCXX_PARALLEL_FOR_EACH_SELECTORS_H 1
#include <parallel/basic_iterator.h>
namespace __gnu_parallel
{
/** @brief Generic selector for embarrassingly parallel functions. */
template<typename It>
struct generic_for_each_selector
{
/** @brief Iterator on last element processed; needed for some
* algorithms (e. g. std::transform()).
*/
It finish_iterator;
};
/** @brief std::for_each() selector. */
template<typename It>
struct for_each_selector : public generic_for_each_selector<It>
{
/** @brief Functor execution.
* @param o Operator.
* @param i Iterator referencing object. */
template<typename Op>
inline bool operator()(Op& o, It i)
{
o(*i);
return true;
}
};
/** @brief std::generate() selector. */
template<typename It>
struct generate_selector : public generic_for_each_selector<It>
{
/** @brief Functor execution.
* @param o Operator.
* @param i Iterator referencing object. */
template<typename Op>
inline bool operator()(Op& o, It i)
{
*i = o();
return true;
}
};
/** @brief std::fill() selector. */
template<typename It>
struct fill_selector : public generic_for_each_selector<It>
{
/** @brief Functor execution.
* @param v Current value.
* @param i Iterator referencing object. */
template<typename Val>
inline bool operator()(Val& v, It i)
{
*i = v;
return true;
}
};
/** @brief std::transform() selector, one input sequence variant. */
template<typename It>
struct transform1_selector : public generic_for_each_selector<It>
{
/** @brief Functor execution.
* @param o Operator.
* @param i Iterator referencing object. */
template<typename Op>
inline bool operator()(Op& o, It i)
{
*i.second = o(*i.first);
return true;
}
};
/** @brief std::transform() selector, two input sequences variant. */
template<typename It>
struct transform2_selector : public generic_for_each_selector<It>
{
/** @brief Functor execution.
* @param o Operator.
* @param i Iterator referencing object. */
template<typename Op>
inline bool operator()(Op& o, It i)
{
*i.third = o(*i.first, *i.second);
return true;
}
};
/** @brief std::replace() selector. */
template<typename It, typename T>
struct replace_selector : public generic_for_each_selector<It>
{
/** @brief Value to replace with. */
const T& new_val;
/** @brief Constructor
* @param new_val Value to replace with. */
explicit replace_selector(const T &new_val) : new_val(new_val) {}
/** @brief Functor execution.
* @param v Current value.
* @param i Iterator referencing object. */
inline bool operator()(T& v, It i)
{
if (*i == v)
*i = new_val;
return true;
}
};
/** @brief std::replace() selector. */
template<typename It, typename Op, typename T>
struct replace_if_selector : public generic_for_each_selector<It>
{
/** @brief Value to replace with. */
const T& new_val;
/** @brief Constructor.
* @param new_val Value to replace with. */
explicit replace_if_selector(const T &new_val) : new_val(new_val) { }
/** @brief Functor execution.
* @param o Operator.
* @param i Iterator referencing object. */
inline bool operator()(Op& o, It i)
{
if (o(*i))
*i = new_val;
return true;
}
};
/** @brief std::count() selector. */
template<typename It, typename Diff>
struct count_selector : public generic_for_each_selector<It>
{
/** @brief Functor execution.
* @param v Current value.
* @param i Iterator referencing object.
* @return 1 if count, 0 if does not count. */
template<typename Val>
inline Diff operator()(Val& v, It i)
{ return (v == *i) ? 1 : 0; }
};
/** @brief std::count_if () selector. */
template<typename It, typename Diff>
struct count_if_selector : public generic_for_each_selector<It>
{
/** @brief Functor execution.
* @param o Operator.
* @param i Iterator referencing object.
* @return 1 if count, 0 if does not count. */
template<typename Op>
inline Diff operator()(Op& o, It i)
{ return (o(*i)) ? 1 : 0; }
};
/** @brief std::accumulate() selector. */
template<typename It>
struct accumulate_selector : public generic_for_each_selector<It>
{
/** @brief Functor execution.
* @param o Operator (unused).
* @param i Iterator referencing object.
* @return The current value. */
template<typename Op>
inline typename std::iterator_traits<It>::value_type operator()(Op o, It i)
{ return *i; }
};
/** @brief std::inner_product() selector. */
template<typename It, typename It2, typename T>
struct inner_product_selector : public generic_for_each_selector<It>
{
/** @brief Begin iterator of first sequence. */
It begin1_iterator;
/** @brief Begin iterator of second sequence. */
It2 begin2_iterator;
/** @brief Constructor.
* @param b1 Begin iterator of first sequence.
* @param b2 Begin iterator of second sequence. */
explicit inner_product_selector(It b1, It2 b2) : begin1_iterator(b1), begin2_iterator(b2) { }
/** @brief Functor execution.
* @param mult Multiplication functor.
* @param current Iterator referencing object.
* @return Inner product elemental result. */
template<typename Op>
inline T operator()(Op mult, It current)
{
typename std::iterator_traits<It>::difference_type position = current - begin1_iterator;
return mult(*current, *(begin2_iterator + position));
}
};
/** @brief Selector that just returns the passed iterator. */
template<typename It>
struct identity_selector : public generic_for_each_selector<It>
{
/** @brief Functor execution.
* @param o Operator (unused).
* @param i Iterator referencing object.
* @return Passed iterator. */
template<typename Op>
inline It operator()(Op o, It i)
{ return i; }
};
/** @brief Selector that returns the difference between two adjacent
* elements.
*/
template<typename It>
struct adjacent_difference_selector : public generic_for_each_selector<It>
{
template<typename Op>
inline bool operator()(Op& o, It i)
{
typename It::first_type go_back_one = i.first;
--go_back_one;
*i.second = o(*i.first, *go_back_one);
return true;
}
};
// XXX move into type_traits?
/** @brief Functor doing nothing
*
* For some reduction tasks (this is not a function object, but is
* passed as selector dummy parameter.
*/
struct nothing
{
/** @brief Functor execution.
* @param i Iterator referencing object. */
template<typename It>
inline void operator()(It i)
{ }
};
/** @brief Reduction function doing nothing. */
struct dummy_reduct
{
inline bool operator()(bool /*x*/, bool /*y*/) const
{ return true; }
};
/** @brief Reduction for finding the maximum element, using a comparator. */
template<typename Comp, typename It>
struct min_element_reduct
{
Comp& comp;
explicit min_element_reduct(Comp &c) : comp(c)
{ }
inline It operator()(It x, It y)
{
if (comp(*x, *y))
return x;
else
return y;
}
};
/** @brief Reduction for finding the maximum element, using a comparator. */
template<typename Comp, typename It>
struct max_element_reduct
{
Comp& comp;
explicit max_element_reduct(Comp& c) : comp(c)
{ }
inline It operator()(It x, It y)
{
if (comp(*x, *y))
return y;
else
return x;
}
};
/** @brief General reduction, using a binary operator. */
template<typename BinOp>
struct accumulate_binop_reduct
{
BinOp& binop;
explicit accumulate_binop_reduct(BinOp& b) : binop(b) {}
template<typename T>
inline T operator()(T x, T y) { return binop(x, y); }
};
}
#endif

View File

@ -0,0 +1,203 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/iterator.h
* @brief Helper iterator classes for the std::transform() functions.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_ITERATOR_H
#define _GLIBCXX_PARALLEL_ITERATOR_H 1
#include <parallel/basic_iterator.h>
#include <bits/stl_pair.h>
namespace __gnu_parallel
{
/** @brief A pair of iterators. The usual iterator operations are
* applied to both child iterators.
*/
template<typename Iterator1, typename Iterator2, typename IteratorCategory>
class iterator_pair : public std::pair<Iterator1, Iterator2>
{
private:
typedef iterator_pair<Iterator1, Iterator2, IteratorCategory> type;
typedef std::pair<Iterator1, Iterator2> base_type;
public:
typedef IteratorCategory iterator_category;
typedef void value_type;
typedef std::iterator_traits<Iterator1> traits_type;
typedef typename traits_type::difference_type difference_type;
typedef type* pointer;
typedef type& reference;
iterator_pair() { }
iterator_pair(const Iterator1& first, const Iterator2& second)
: base_type(first, second) { }
// Pre-increment operator.
type&
operator++()
{
++base_type::first;
++base_type::second;
return *this;
}
// Post-increment operator.
const type
operator++(int)
{ return type(base_type::first++, base_type::second++); }
// Pre-decrement operator.
type&
operator--()
{
--base_type::first;
--base_type::second;
return *this;
}
// Post-decrement operator.
const type
operator--(int)
{ return type(base_type::first--, base_type::second--); }
// Type conversion.
operator Iterator2() const
{ return base_type::second; }
type&
operator=(const type& other)
{
base_type::first = other.first;
base_type::second = other.second;
return *this;
}
type
operator+(difference_type delta) const
{ return type(base_type::first + delta, base_type::second + delta); }
difference_type
operator-(const type& other) const
{ return base_type::first - other.first; }
};
/** @brief A triple of iterators. The usual iterator operations are
applied to all three child iterators.
*/
template<typename Iterator1, typename Iterator2, typename Iterator3, typename IteratorCategory>
class iterator_triple
{
private:
typedef iterator_triple<Iterator1, Iterator2, Iterator3, IteratorCategory> type;
public:
typedef IteratorCategory iterator_category;
typedef void value_type;
typedef typename Iterator1::difference_type difference_type;
typedef type* pointer;
typedef type& reference;
Iterator1 first;
Iterator2 second;
Iterator3 third;
iterator_triple() { }
iterator_triple(const Iterator1& _first, const Iterator2& _second,
const Iterator3& _third)
{
first = _first;
second = _second;
third = _third;
}
// Pre-increment operator.
type&
operator++()
{
++first;
++second;
++third;
return *this;
}
// Post-increment operator.
const type
operator++(int)
{ return type(first++, second++, third++); }
// Pre-decrement operator.
type&
operator--()
{
--first;
--second;
--third;
return *this;
}
// Post-decrement operator.
const type
operator--(int)
{ return type(first--, second--, third--); }
// Type conversion.
operator Iterator3() const
{ return third; }
type&
operator=(const type& other)
{
first = other.first;
second = other.second;
third = other.third;
return *this;
}
type
operator+(difference_type delta) const
{ return type(first + delta, second + delta, third + delta); }
difference_type
operator-(const type& other) const
{ return first - other.first; }
};
}
#endif

View File

@ -0,0 +1,181 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/list_partition.h
* @brief Functionality to split sequence referenced by only input
* iterators.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Leonor Frias Moya and Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_LIST_PARTITION_H
#define _GLIBCXX_PARALLEL_LIST_PARTITION_H 1
#include <parallel/parallel.h>
#include <vector>
namespace __gnu_parallel
{
/** @brief Shrinks and doubles the ranges.
* @param os_starts Start positions worked on (oversampled).
* @param count_to_two Counts up to 2.
* @param range_length Current length of a chunk.
* @param make_twice Whether the @c os_starts is allowed to be
* grown or not
*/
template<typename InputIterator>
void
shrink_and_double(std::vector<InputIterator>& os_starts, size_t& count_to_two, size_t& range_length, const bool make_twice)
{
++count_to_two;
if (not make_twice or count_to_two < 2)
{
shrink(os_starts, count_to_two, range_length);
}
else
{
os_starts.resize((os_starts.size() - 1) * 2 + 1);
count_to_two = 0;
}
}
/** @brief Combines two ranges into one and thus halves the number of ranges.
* @param os_starts Start positions worked on (oversampled).
* @param count_to_two Counts up to 2.
* @param range_length Current length of a chunk. */
template<typename InputIterator>
void
shrink(std::vector<InputIterator>& os_starts, size_t& count_to_two,
size_t& range_length)
{
for (typename std::vector<InputIterator>::size_type i = 0; i <= (os_starts.size() / 2); ++i)
{
os_starts[i] = os_starts[i * 2];
}
range_length *= 2;
}
/** @brief Splits a sequence given by input iterators into parts of
* almost equal size
*
* The function needs only one pass over the sequence.
* @param begin Begin iterator of input sequence.
* @param end End iterator of input sequence.
* @param starts Start iterators for the resulting parts, dimension
* @c num_parts+1. For convenience, @c starts @c [num_parts]
* contains the end iterator of the sequence.
* @param lengths Length of the resulting parts.
* @param num_parts Number of parts to split the sequence into.
* @param f Functor to be applied to each element by traversing it
* @param oversampling Oversampling factor. If 0, then the
* partitions will differ in at most @f$ \sqrt{\mathrm{end} -
* \mathrm{begin}} @f$ elements. Otherwise, the ratio between the
* longest and the shortest part is bounded by @f$
* 1/(\mathrm{oversampling} \cdot \mathrm{num\_parts}) @f$.
* @return Length of the whole sequence.
*/
template<typename InputIterator, typename FunctorType>
size_t
list_partition(const InputIterator begin, const InputIterator end,
InputIterator* starts, size_t* lengths, const int num_parts,
FunctorType& f, int oversampling = 0)
{
bool make_twice = false;
// According to the oversampling factor, the resizing algorithm is chosen.
if (oversampling == 0)
{
make_twice = true;
oversampling = 1;
}
std::vector<InputIterator> os_starts(2 * oversampling * num_parts + 1);
os_starts[0]= begin;
InputIterator prev = begin, it = begin;
size_t dist_limit = 0, dist = 0;
size_t cur = 1, next = 1;
size_t range_length = 1;
size_t count_to_two = 0;
while (it != end){
cur = next;
for (; cur < os_starts.size() and it != end; ++cur)
{
for (dist_limit += range_length; dist < dist_limit and it != end; ++dist)
{
f(it);
++it;
}
os_starts[cur] = it;
}
// Must compare for end and not cur < os_starts.size() , because
// cur could be == os_starts.size() as well
if (it == end)
break;
shrink_and_double(os_starts, count_to_two, range_length, make_twice);
next = os_starts.size()/2 + 1;
}
// Calculation of the parts (one must be extracted from current
// because the partition beginning at end, consists only of
// itself).
size_t size_part = (cur - 1) / num_parts;
int size_greater = static_cast<int>((cur - 1) % num_parts);
starts[0] = os_starts[0];
size_t index = 0;
// Smallest partitions.
for (int i = 1; i < (num_parts + 1 - size_greater); ++i)
{
lengths[i-1] = size_part * range_length;
index += size_part;
starts[i] = os_starts[index];
}
// Biggest partitions.
for (int i = num_parts + 1 - size_greater; i <= num_parts; ++i)
{
lengths[i-1] = (size_part+1) * range_length;
index += (size_part+1);
starts[i] = os_starts[index];
}
// Correction of the end size (the end iteration has not finished).
lengths[num_parts - 1] -= (dist_limit - dist);
return dist;
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,230 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/merge.h
* @brief Parallel implementation of std::merge().
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_MERGE_H
#define _GLIBCXX_PARALLEL_MERGE_H 1
#include <parallel/basic_iterator.h>
#include <bits/stl_algo.h>
namespace __gnu_parallel
{
/** @brief Merge routine being able to merge only the @c max_length
* smallest elements.
*
* The @c begin iterators are advanced accordingly, they might not
* reach @c end, in contrast to the usual variant.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence.
* @param end2 End iterator of second sequence.
* @param target Target begin iterator.
* @param max_length Maximum number of elements to merge.
* @param comp Comparator.
* @return Output end iterator. */
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename OutputIterator, typename _DifferenceTp, typename Comparator>
OutputIterator
merge_advance_usual(RandomAccessIterator1& begin1, RandomAccessIterator1 end1, RandomAccessIterator2& begin2, RandomAccessIterator2 end2, OutputIterator target, _DifferenceTp max_length, Comparator comp)
{
typedef _DifferenceTp difference_type;
while (begin1 != end1 && begin2 != end2 && max_length > 0)
{
// array1[i1] < array0[i0]
if (comp(*begin2, *begin1))
*target++ = *begin2++;
else
*target++ = *begin1++;
max_length--;
}
if (begin1 != end1)
{
target = std::copy(begin1, begin1 + max_length, target);
begin1 += max_length;
}
else
{
target = std::copy(begin2, begin2 + max_length, target);
begin2 += max_length;
}
return target;
}
/** @brief Merge routine being able to merge only the @c max_length
* smallest elements.
*
* The @c begin iterators are advanced accordingly, they might not
* reach @c end, in contrast to the usual variant.
* Specially designed code should allow the compiler to generate
* conditional moves instead of branches.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence.
* @param end2 End iterator of second sequence.
* @param target Target begin iterator.
* @param max_length Maximum number of elements to merge.
* @param comp Comparator.
* @return Output end iterator. */
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename OutputIterator, typename _DifferenceTp, typename Comparator>
OutputIterator
merge_advance_movc(RandomAccessIterator1& begin1, RandomAccessIterator1 end1, RandomAccessIterator2& begin2, RandomAccessIterator2 end2, OutputIterator target, _DifferenceTp max_length, Comparator comp)
{
typedef _DifferenceTp difference_type;
typedef typename std::iterator_traits<RandomAccessIterator1>::value_type value_type1;
typedef typename std::iterator_traits<RandomAccessIterator2>::value_type value_type2;
#if _GLIBCXX_ASSERTIONS
_GLIBCXX_PARALLEL_ASSERT(max_length >= 0);
#endif
while (begin1 != end1 && begin2 != end2 && max_length > 0)
{
value_type1 element1;
value_type2 element2;
RandomAccessIterator1 next1;
RandomAccessIterator2 next2;
next1 = begin1 + 1;
next2 = begin2 + 1;
element1 = *begin1;
element2 = *begin2;
if (comp(element2, element1))
{
element1 = element2;
begin2 = next2;
}
else
{
begin1 = next1;
}
*target = element1;
target++;
max_length--;
}
if (begin1 != end1)
{
target = std::copy(begin1, begin1 + max_length, target);
begin1 += max_length;
}
else
{
target = std::copy(begin2, begin2 + max_length, target);
begin2 += max_length;
}
return target;
}
/** @brief Merge routine being able to merge only the @c max_length
* smallest elements.
*
* The @c begin iterators are advanced accordingly, they might not
* reach @c end, in contrast to the usual variant.
* Static switch on whether to use the conditional-move variant.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence.
* @param end2 End iterator of second sequence.
* @param target Target begin iterator.
* @param max_length Maximum number of elements to merge.
* @param comp Comparator.
* @return Output end iterator. */
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename OutputIterator, typename _DifferenceTp, typename Comparator>
inline OutputIterator
merge_advance(RandomAccessIterator1& begin1, RandomAccessIterator1 end1, RandomAccessIterator2& begin2, RandomAccessIterator2 end2, OutputIterator target, _DifferenceTp max_length, Comparator comp)
{
_GLIBCXX_CALL(max_length)
return merge_advance_movc(begin1, end1, begin2, end2, target, max_length, comp);
}
/** @brief Merge routine fallback to sequential in case the
iterators of the two input sequences are of different type.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence.
* @param end2 End iterator of second sequence.
* @param target Target begin iterator.
* @param max_length Maximum number of elements to merge.
* @param comp Comparator.
* @return Output end iterator. */
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename RandomAccessIterator3, typename Comparator>
inline RandomAccessIterator3
parallel_merge_advance(RandomAccessIterator1& begin1, RandomAccessIterator1 end1,
RandomAccessIterator2& begin2, RandomAccessIterator2 end2, //different iterators, parallel implementation not available
RandomAccessIterator3 target,
typename std::iterator_traits<RandomAccessIterator1>::difference_type max_length, Comparator comp)
{
return merge_advance(begin1, end1, begin2, end2, target, max_length, comp);
}
/** @brief Parallel merge routine being able to merge only the @c
* max_length smallest elements.
*
* The @c begin iterators are advanced accordingly, they might not
* reach @c end, in contrast to the usual variant.
* The functionality is projected onto parallel_multiway_merge.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence.
* @param end2 End iterator of second sequence.
* @param target Target begin iterator.
* @param max_length Maximum number of elements to merge.
* @param comp Comparator.
* @return Output end iterator.
*/
template<typename RandomAccessIterator1, typename RandomAccessIterator3, typename Comparator>
inline RandomAccessIterator3
parallel_merge_advance(RandomAccessIterator1& begin1, RandomAccessIterator1 end1, RandomAccessIterator1& begin2, RandomAccessIterator1 end2, RandomAccessIterator3 target, typename std::iterator_traits<RandomAccessIterator1>::difference_type max_length, Comparator comp)
{
typedef typename std::iterator_traits<RandomAccessIterator1>::value_type
value_type;
typedef typename std::iterator_traits<RandomAccessIterator1>::difference_type
difference_type1 /* == difference_type2 */;
typedef typename std::iterator_traits<RandomAccessIterator3>::difference_type
difference_type3;
std::pair<RandomAccessIterator1, RandomAccessIterator1> seqs[2] = { std::make_pair(begin1, end1), std::make_pair(begin2, end2) };
RandomAccessIterator3 target_end = parallel_multiway_merge(seqs, seqs + 2, target, comp, max_length, true, false);
return target_end;
}
} //namespace __gnu_parallel
#endif

View File

@ -0,0 +1,608 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/multiseq_selection.h
* @brief Functions to find elements of a certain global rank in
* multiple sorted sequences. Also serves for splitting such
* sequence sets.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H
#define _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H 1
#include <vector>
#include <queue>
#include <bits/stl_algo.h>
#include <parallel/sort.h>
namespace __gnu_parallel
{
/** @brief Compare a pair of types lexicographically, ascending. */
template<typename T1, typename T2, typename Comparator>
class lexicographic : public std::binary_function<std::pair<T1, T2>, std::pair<T1, T2>, bool>
{
private:
Comparator& comp;
public:
lexicographic(Comparator& _comp) : comp(_comp) { }
// XXX const
inline bool
operator()(const std::pair<T1, T2>& p1, const std::pair<T1, T2>& p2) const
{
if (comp(p1.first, p2.first))
return true;
if (comp(p2.first, p1.first))
return false;
// Firsts are equal.
return p1.second < p2.second;
}
};
/** @brief Compare a pair of types lexicographically, descending. */
template<typename T1, typename T2, typename Comparator>
class lexicographic_reverse : public std::binary_function<T1, T2, bool>
{
private:
Comparator& comp;
public:
lexicographic_reverse(Comparator& _comp) : comp(_comp) { }
inline bool
operator()(const std::pair<T1, T2>& p1, const std::pair<T1, T2>& p2) const
{
if (comp(p2.first, p1.first))
return true;
if (comp(p1.first, p2.first))
return false;
// Firsts are equal.
return p2.second < p1.second;
}
};
/**
* @brief Splits several sorted sequences at a certain global rank,
* resulting in a splitting point for each sequence.
* The sequences are passed via a sequence of random-access
* iterator pairs, none of the sequences may be empty. If there
* are several equal elements across the split, the ones on the
* left side will be chosen from sequences with smaller number.
* @param begin_seqs Begin of the sequence of iterator pairs.
* @param end_seqs End of the sequence of iterator pairs.
* @param rank The global rank to partition at.
* @param begin_offsets A random-access sequence begin where the
* result will be stored in. Each element of the sequence is an
* iterator that points to the first element on the greater part of
* the respective sequence.
* @param comp The ordering functor, defaults to std::less<T>.
*/
template<typename RanSeqs, typename RankType, typename RankIterator, typename Comparator>
void
multiseq_partition(RanSeqs begin_seqs, RanSeqs end_seqs, RankType rank,
RankIterator begin_offsets,
Comparator comp = std::less<
typename std::iterator_traits<typename std::iterator_traits<RanSeqs>::value_type::first_type>::value_type>()) // std::less<T>
{
_GLIBCXX_CALL(end_seqs - begin_seqs)
typedef typename std::iterator_traits<RanSeqs>::value_type::first_type It;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef typename std::iterator_traits<It>::value_type T;
lexicographic<T, int, Comparator> lcomp(comp);
lexicographic_reverse<T, int, Comparator> lrcomp(comp);
// Number of sequences, number of elements in total (possibly
// including padding).
difference_type m = std::distance(begin_seqs, end_seqs), N = 0, nmax, n, r;
for (int i = 0; i < m; i++)
N += std::distance(begin_seqs[i].first, begin_seqs[i].second);
if (rank == N)
{
for (int i = 0; i < m; i++)
begin_offsets[i] = begin_seqs[i].second; // Very end.
// Return m - 1;
}
_GLIBCXX_PARALLEL_ASSERT(m != 0 && N != 0 && rank >= 0 && rank < N);
difference_type* ns = new difference_type[m];
difference_type* a = new difference_type[m];
difference_type* b = new difference_type[m];
difference_type l;
ns[0] = std::distance(begin_seqs[0].first, begin_seqs[0].second);
nmax = ns[0];
for (int i = 0; i < m; i++)
{
ns[i] = std::distance(begin_seqs[i].first, begin_seqs[i].second);
nmax = std::max(nmax, ns[i]);
}
r = log2(nmax) + 1;
// Pad all lists to this length, at least as long as any ns[i],
// equality iff nmax = 2^k - 1.
l = (1ULL << r) - 1;
// From now on, including padding.
N = l * m;
for (int i = 0; i < m; i++)
{
a[i] = 0;
b[i] = l;
}
n = l / 2;
// Invariants:
// 0 <= a[i] <= ns[i], 0 <= b[i] <= l
#define S(i) (begin_seqs[i].first)
// Initial partition.
std::vector<std::pair<T, int> > sample;
for (int i = 0; i < m; i++)
if (n < ns[i]) //sequence long enough
sample.push_back(std::make_pair(S(i)[n], i));
__gnu_sequential::sort(sample.begin(), sample.end(), lcomp);
for (int i = 0; i < m; i++) //conceptual infinity
if (n >= ns[i]) //sequence too short, conceptual infinity
sample.push_back(std::make_pair(S(i)[0] /*dummy element*/, i));
difference_type localrank = rank * m / N ;
int j;
for (j = 0; j < localrank && ((n + 1) <= ns[sample[j].second]); j++)
a[sample[j].second] += n + 1;
for (; j < m; j++)
b[sample[j].second] -= n + 1;
// Further refinement.
while (n > 0)
{
n /= 2;
int lmax_seq = -1; // to avoid warning
const T* lmax = NULL; // impossible to avoid the warning?
for (int i = 0; i < m; i++)
{
if (a[i] > 0)
{
if (!lmax)
{
lmax = &(S(i)[a[i] - 1]);
lmax_seq = i;
}
else
{
// Max, favor rear sequences.
if (!comp(S(i)[a[i] - 1], *lmax))
{
lmax = &(S(i)[a[i] - 1]);
lmax_seq = i;
}
}
}
}
int i;
for (i = 0; i < m; i++)
{
difference_type middle = (b[i] + a[i]) / 2;
if (lmax && middle < ns[i] &&
lcomp(std::make_pair(S(i)[middle], i), std::make_pair(*lmax, lmax_seq)))
a[i] = std::min(a[i] + n + 1, ns[i]);
else
b[i] -= n + 1;
}
difference_type leftsize = 0, total = 0;
for (int i = 0; i < m; i++)
{
leftsize += a[i] / (n + 1);
total += l / (n + 1);
}
difference_type skew = static_cast<difference_type>(static_cast<uint64>(total) * rank / N - leftsize);
if (skew > 0)
{
// Move to the left, find smallest.
std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int> >, lexicographic_reverse<T, int, Comparator> > pq(lrcomp);
for (int i = 0; i < m; i++)
if (b[i] < ns[i])
pq.push(std::make_pair(S(i)[b[i]], i));
for (; skew != 0 && !pq.empty(); skew--)
{
int source = pq.top().second;
pq.pop();
a[source] = std::min(a[source] + n + 1, ns[source]);
b[source] += n + 1;
if (b[source] < ns[source])
pq.push(std::make_pair(S(source)[b[source]], source));
}
}
else if (skew < 0)
{
// Move to the right, find greatest.
std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int> >, lexicographic<T, int, Comparator> > pq(lcomp);
for (int i = 0; i < m; i++)
if (a[i] > 0)
pq.push(std::make_pair(S(i)[a[i] - 1], i));
for (; skew != 0; skew++)
{
int source = pq.top().second;
pq.pop();
a[source] -= n + 1;
b[source] -= n + 1;
if (a[source] > 0)
pq.push(std::make_pair(S(source)[a[source] - 1], source));
}
}
}
// Postconditions:
// a[i] == b[i] in most cases, except when a[i] has been clamped
// because of having reached the boundary
// Now return the result, calculate the offset.
// Compare the keys on both edges of the border.
// Maximum of left edge, minimum of right edge.
bool maxleftset = false, minrightset = false;
T maxleft, minright; // Impossible to avoid the warning?
for (int i = 0; i < m; i++)
{
if (a[i] > 0)
{
if (!maxleftset)
{
maxleft = S(i)[a[i] - 1];
maxleftset = true;
}
else
{
// Max, favor rear sequences.
if (!comp(S(i)[a[i] - 1], maxleft))
maxleft = S(i)[a[i] - 1];
}
}
if (b[i] < ns[i])
{
if (!minrightset)
{
minright = S(i)[b[i]];
minrightset = true;
}
else
{
// Min, favor fore sequences.
if (comp(S(i)[b[i]], minright))
minright = S(i)[b[i]];
}
}
}
int seq = 0;
for (int i = 0; i < m; i++)
begin_offsets[i] = S(i) + a[i];
delete[] ns;
delete[] a;
delete[] b;
}
/**
* @brief Selects the element at a certain global rank from several
* sorted sequences.
*
* The sequences are passed via a sequence of random-access
* iterator pairs, none of the sequences may be empty.
* @param begin_seqs Begin of the sequence of iterator pairs.
* @param end_seqs End of the sequence of iterator pairs.
* @param rank The global rank to partition at.
* @param offset The rank of the selected element in the global
* subsequence of elements equal to the selected element. If the
* selected element is unique, this number is 0.
* @param comp The ordering functor, defaults to std::less.
*/
template<typename T, typename RanSeqs, typename RankType, typename Comparator>
T
multiseq_selection(RanSeqs begin_seqs, RanSeqs end_seqs, RankType rank,
RankType& offset, Comparator comp = std::less<T>())
{
_GLIBCXX_CALL(end_seqs - begin_seqs)
typedef typename std::iterator_traits<RanSeqs>::value_type::first_type It;
typedef typename std::iterator_traits<It>::difference_type difference_type;
lexicographic<T, int, Comparator> lcomp(comp);
lexicographic_reverse<T, int, Comparator> lrcomp(comp);
// Number of sequences, number of elements in total (possibly
// including padding).
difference_type m = std::distance(begin_seqs, end_seqs);
difference_type N = 0;
difference_type nmax, n, r;
for (int i = 0; i < m; i++)
N += std::distance(begin_seqs[i].first, begin_seqs[i].second);
if (m == 0 || N == 0 || rank < 0 || rank >= N)
{
// Result undefined when there is no data or rank is outside bounds.
throw std::exception();
}
difference_type* ns = new difference_type[m];
difference_type* a = new difference_type[m];
difference_type* b = new difference_type[m];
difference_type l;
ns[0] = std::distance(begin_seqs[0].first, begin_seqs[0].second);
nmax = ns[0];
for (int i = 0; i < m; i++)
{
ns[i] = std::distance(begin_seqs[i].first, begin_seqs[i].second);
nmax = std::max(nmax, ns[i]);
}
r = log2(nmax) + 1;
// Pad all lists to this length, at least as long as any ns[i],
// equality iff nmax = 2^k - 1
l = pow2(r) - 1;
// From now on, including padding.
N = l * m;
for (int i = 0; i < m; i++)
{
a[i] = 0;
b[i] = l;
}
n = l / 2;
// Invariants:
// 0 <= a[i] <= ns[i], 0 <= b[i] <= l
#define S(i) (begin_seqs[i].first)
// Initial partition.
std::vector<std::pair<T, int> > sample;
for (int i = 0; i < m; i++)
if (n < ns[i])
sample.push_back(std::make_pair(S(i)[n], i));
__gnu_sequential::sort(sample.begin(), sample.end(), lcomp, sequential_tag());
// Conceptual infinity.
for (int i = 0; i < m; i++)
if (n >= ns[i])
sample.push_back(std::make_pair(S(i)[0] /*dummy element*/, i));
difference_type localrank = rank * m / N ;
int j;
for (j = 0; j < localrank && ((n + 1) <= ns[sample[j].second]); j++)
a[sample[j].second] += n + 1;
for (; j < m; j++)
b[sample[j].second] -= n + 1;
// Further refinement.
while (n > 0)
{
n /= 2;
const T* lmax = NULL;
for (int i = 0; i < m; i++)
{
if (a[i] > 0)
{
if (!lmax)
{
lmax = &(S(i)[a[i] - 1]);
}
else
{
if (comp(*lmax, S(i)[a[i] - 1])) //max
lmax = &(S(i)[a[i] - 1]);
}
}
}
int i;
for (i = 0; i < m; i++)
{
difference_type middle = (b[i] + a[i]) / 2;
if (lmax && middle < ns[i] && comp(S(i)[middle], *lmax))
a[i] = std::min(a[i] + n + 1, ns[i]);
else
b[i] -= n + 1;
}
difference_type leftsize = 0, total = 0;
for (int i = 0; i < m; i++)
{
leftsize += a[i] / (n + 1);
total += l / (n + 1);
}
difference_type skew = (unsigned long long)total * rank / N - leftsize;
if (skew > 0)
{
// Move to the left, find smallest.
std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int> >, lexicographic_reverse<T, int, Comparator> > pq(lrcomp);
for (int i = 0; i < m; i++)
if (b[i] < ns[i])
pq.push(std::make_pair(S(i)[b[i]], i));
for (; skew != 0 && !pq.empty(); skew--)
{
int source = pq.top().second;
pq.pop();
a[source] = std::min(a[source] + n + 1, ns[source]);
b[source] += n + 1;
if (b[source] < ns[source])
pq.push(std::make_pair(S(source)[b[source]], source));
}
}
else if (skew < 0)
{
// Move to the right, find greatest.
std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int> >, lexicographic<T, int, Comparator> > pq(lcomp);
for (int i = 0; i < m; i++)
if (a[i] > 0)
pq.push(std::make_pair(S(i)[a[i] - 1], i));
for (; skew != 0; skew++)
{
int source = pq.top().second;
pq.pop();
a[source] -= n + 1;
b[source] -= n + 1;
if (a[source] > 0)
pq.push(std::make_pair(S(source)[a[source] - 1], source));
}
}
}
// Postconditions:
// a[i] == b[i] in most cases, except when a[i] has been clamped
// because of having reached the boundary
// Now return the result, calculate the offset.
// Compare the keys on both edges of the border.
// Maximum of left edge, minimum of right edge.
bool maxleftset = false, minrightset = false;
// Impossible to avoid the warning?
T maxleft, minright;
for (int i = 0; i < m; i++)
{
if (a[i] > 0)
{
if (!maxleftset)
{
maxleft = S(i)[a[i] - 1];
maxleftset = true;
}
else
{
// Max.
if (comp(maxleft, S(i)[a[i] - 1]))
maxleft = S(i)[a[i] - 1];
}
}
if (b[i] < ns[i])
{
if (!minrightset)
{
minright = S(i)[b[i]];
minrightset = true;
}
else
{
// Min.
if (comp(S(i)[b[i]], minright))
minright = S(i)[b[i]];
}
}
}
// Minright is the splitter, in any case.
if (!maxleftset || comp(minright, maxleft))
{
// Good luck, everything is split unambigiously.
offset = 0;
}
else
{
// We have to calculate an offset.
offset = 0;
for (int i = 0; i < m; i++)
{
difference_type lb = std::lower_bound(S(i), S(i) + ns[i], minright,
comp) - S(i);
offset += a[i] - lb;
}
}
delete[] ns;
delete[] a;
delete[] b;
return minright;
}
}
#undef S
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,413 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/multiway_mergesort.h
* @brief Parallel multiway merge sort.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_MERGESORT_H
#define _GLIBCXX_PARALLEL_MERGESORT_H 1
#include <vector>
#include <parallel/basic_iterator.h>
#include <bits/stl_algo.h>
#include <parallel/parallel.h>
#include <parallel/multiway_merge.h>
#include <parallel/timing.h>
namespace __gnu_parallel
{
/** @brief Subsequence description. */
template<typename _DifferenceTp>
struct Piece
{
typedef _DifferenceTp difference_type;
/** @brief Begin of subsequence. */
difference_type begin;
/** @brief End of subsequence. */
difference_type end;
};
/** @brief Data accessed by all threads.
*
* PMWMS = parallel multiway mergesort */
template<typename RandomAccessIterator>
struct PMWMSSortingData
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
/** @brief Input begin. */
RandomAccessIterator source;
/** @brief Start indices, per thread. */
difference_type* starts;
/** @brief Temporary arrays for each thread.
*
* Indirection Allows using the temporary storage in different
* ways, without code duplication.
* @see _GLIBCXX_MULTIWAY_MERGESORT_COPY_LAST */
value_type** temporaries;
#if _GLIBCXX_MULTIWAY_MERGESORT_COPY_LAST
/** @brief Storage in which to sort. */
RandomAccessIterator* sorting_places;
/** @brief Storage into which to merge. */
value_type** merging_places;
#else
/** @brief Storage in which to sort. */
value_type** sorting_places;
/** @brief Storage into which to merge. */
RandomAccessIterator* merging_places;
#endif
/** @brief Samples. */
value_type* samples;
/** @brief Offsets to add to the found positions. */
difference_type* offsets;
/** @brief Pieces of data to merge @c [thread][sequence] */
std::vector<Piece<difference_type> >* pieces;
};
/** @brief Thread local data for PMWMS. */
template<typename RandomAccessIterator>
struct PMWMSSorterPU
{
/** @brief Total number of thread involved. */
thread_index_t num_threads;
/** @brief Number of owning thread. */
thread_index_t iam;
/** @brief Stable sorting desired. */
bool stable;
/** @brief Pointer to global data. */
PMWMSSortingData<RandomAccessIterator>* sd;
};
/**
* @brief Select samples from a sequence.
* @param d Pointer to thread-local data. Result will be placed in
* @c d->ds->samples.
* @param num_samples Number of samples to select.
*/
template<typename RandomAccessIterator, typename _DifferenceTp>
inline void
determine_samples(PMWMSSorterPU<RandomAccessIterator>* d,
_DifferenceTp& num_samples)
{
typedef _DifferenceTp difference_type;
PMWMSSortingData<RandomAccessIterator>* sd = d->sd;
num_samples = Settings::sort_mwms_oversampling * d->num_threads - 1;
difference_type es[num_samples + 2];
equally_split(sd->starts[d->iam + 1] - sd->starts[d->iam], num_samples + 1, es);
for (difference_type i = 0; i < num_samples; i++)
sd->samples[d->iam * num_samples + i] = sd->source[sd->starts[d->iam] + es[i + 1]];
}
/** @brief PMWMS code executed by each thread.
* @param d Pointer to thread-local data.
* @param comp Comparator.
*/
template<typename RandomAccessIterator, typename Comparator>
inline void
parallel_sort_mwms_pu(PMWMSSorterPU<RandomAccessIterator>* d,
Comparator& comp)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
Timing<sequential_tag> t;
t.tic();
PMWMSSortingData<RandomAccessIterator>* sd = d->sd;
thread_index_t iam = d->iam;
// Length of this thread's chunk, before merging.
difference_type length_local = sd->starts[iam + 1] - sd->starts[iam];
#if _GLIBCXX_MULTIWAY_MERGESORT_COPY_LAST
typedef RandomAccessIterator SortingPlacesIterator;
// Sort in input storage.
sd->sorting_places[iam] = sd->source + sd->starts[iam];
#else
typedef value_type* SortingPlacesIterator;
// Sort in temporary storage, leave space for sentinel.
sd->sorting_places[iam] = sd->temporaries[iam] = static_cast<value_type*>(::operator new(sizeof(value_type) *(length_local + 1)));
// Copy there.
std::uninitialized_copy(sd->source + sd->starts[iam], sd->source + sd->starts[iam] + length_local, sd->sorting_places[iam]);
#endif
// Sort locally.
if (d->stable)
__gnu_sequential::stable_sort(sd->sorting_places[iam], sd->sorting_places[iam] + length_local, comp);
else
__gnu_sequential::sort(sd->sorting_places[iam], sd->sorting_places[iam] + length_local, comp);
#if _GLIBCXX_ASSERTIONS
_GLIBCXX_PARALLEL_ASSERT(is_sorted(sd->sorting_places[iam], sd->sorting_places[iam] + length_local, comp));
#endif
// Invariant: locally sorted subsequence in sd->sorting_places[iam],
// sd->sorting_places[iam] + length_local.
t.tic("local sort");
if (Settings::sort_splitting == Settings::SAMPLING)
{
difference_type num_samples;
determine_samples(d, num_samples);
#pragma omp barrier
t.tic("sample/wait");
#pragma omp single
__gnu_sequential::sort(sd->samples, sd->samples + (num_samples * d->num_threads), comp);
#pragma omp barrier
for (int s = 0; s < d->num_threads; s++)
{
// For each sequence.
if (num_samples * iam > 0)
sd->pieces[iam][s].begin = std::lower_bound(sd->sorting_places[s],
sd->sorting_places[s] + sd->starts[s + 1] - sd->starts[s],
sd->samples[num_samples * iam],
comp)
- sd->sorting_places[s];
else
// Absolute beginning.
sd->pieces[iam][s].begin = 0;
if ((num_samples * (iam + 1)) < (num_samples * d->num_threads))
sd->pieces[iam][s].end = std::lower_bound(sd->sorting_places[s],
sd->sorting_places[s] + sd->starts[s + 1] - sd->starts[s], sd->samples[num_samples * (iam + 1)], comp)
- sd->sorting_places[s];
else
// Absolute end.
sd->pieces[iam][s].end = sd->starts[s + 1] - sd->starts[s];
}
}
else if (Settings::sort_splitting == Settings::EXACT)
{
#pragma omp barrier
t.tic("wait");
std::vector<std::pair<SortingPlacesIterator, SortingPlacesIterator> > seqs(d->num_threads);
for (int s = 0; s < d->num_threads; s++)
seqs[s] = std::make_pair(sd->sorting_places[s], sd->sorting_places[s] + sd->starts[s + 1] - sd->starts[s]);
std::vector<SortingPlacesIterator> offsets(d->num_threads);
// If not last thread.
if (iam < d->num_threads - 1)
multiseq_partition(seqs.begin(), seqs.end(), sd->starts[iam + 1], offsets.begin(), comp);
for (int seq = 0; seq < d->num_threads; seq++)
{
// For each sequence.
if (iam < (d->num_threads - 1))
sd->pieces[iam][seq].end = offsets[seq] - seqs[seq].first;
else
// Absolute end of this sequence.
sd->pieces[iam][seq].end = sd->starts[seq + 1] - sd->starts[seq];
}
#pragma omp barrier
for (int seq = 0; seq < d->num_threads; seq++)
{
// For each sequence.
if (iam > 0)
sd->pieces[iam][seq].begin = sd->pieces[iam - 1][seq].end;
else
// Absolute beginning.
sd->pieces[iam][seq].begin = 0;
}
}
t.tic("split");
// Offset from target begin, length after merging.
difference_type offset = 0, length_am = 0;
for (int s = 0; s < d->num_threads; s++)
{
length_am += sd->pieces[iam][s].end - sd->pieces[iam][s].begin;
offset += sd->pieces[iam][s].begin;
}
#if _GLIBCXX_MULTIWAY_MERGESORT_COPY_LAST
// Merge to temporary storage, uninitialized creation not possible
// since there is no multiway_merge calling the placement new
// instead of the assignment operator.
sd->merging_places[iam] = sd->temporaries[iam] = new value_type[length_am];
#else
// Merge directly to target.
sd->merging_places[iam] = sd->source + offset;
#endif
std::vector<std::pair<SortingPlacesIterator, SortingPlacesIterator> > seqs(d->num_threads);
for (int s = 0; s < d->num_threads; s++)
{
seqs[s] = std::make_pair(sd->sorting_places[s] + sd->pieces[iam][s].begin, sd->sorting_places[s] + sd->pieces[iam][s].end);
#if _GLIBCXX_ASSERTIONS
_GLIBCXX_PARALLEL_ASSERT(is_sorted(seqs[s].first, seqs[s].second, comp));
#endif
}
multiway_merge(seqs.begin(), seqs.end(), sd->merging_places[iam], comp, length_am, d->stable, false, sequential_tag());
t.tic("merge");
#if _GLIBCXX_ASSERTIONS
_GLIBCXX_PARALLEL_ASSERT(is_sorted(sd->merging_places[iam], sd->merging_places[iam] + length_am, comp));
#endif
# pragma omp barrier
#if _GLIBCXX_MULTIWAY_MERGESORT_COPY_LAST
// Write back.
std::copy(sd->merging_places[iam], sd->merging_places[iam] + length_am,
sd->source + offset);
#endif
delete[] sd->temporaries[iam];
t.tic("copy back");
t.print();
}
/** @brief PMWMS main call.
* @param begin Begin iterator of sequence.
* @param end End iterator of sequence.
* @param comp Comparator.
* @param n Length of sequence.
* @param num_threads Number of threads to use.
* @param stable Stable sorting.
*/
template<typename RandomAccessIterator, typename Comparator>
inline void
parallel_sort_mwms(RandomAccessIterator begin, RandomAccessIterator end, Comparator comp, typename std::iterator_traits<RandomAccessIterator>::difference_type n, int num_threads, bool stable)
{
_GLIBCXX_CALL(n)
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
if (n <= 1)
return;
// At least one element per thread.
if (num_threads > n)
num_threads = static_cast<thread_index_t>(n);
PMWMSSortingData<RandomAccessIterator> sd;
sd.source = begin;
sd.temporaries = new value_type*[num_threads];
#if _GLIBCXX_MULTIWAY_MERGESORT_COPY_LAST
sd.sorting_places = new RandomAccessIterator[num_threads];
sd.merging_places = new value_type*[num_threads];
#else
sd.sorting_places = new value_type*[num_threads];
sd.merging_places = new RandomAccessIterator[num_threads];
#endif
if (Settings::sort_splitting == Settings::SAMPLING)
sd.samples = new value_type[num_threads * (Settings::sort_mwms_oversampling * num_threads - 1)];
else
sd.samples = NULL;
sd.offsets = new difference_type[num_threads - 1];
sd.pieces = new std::vector<Piece<difference_type> >[num_threads];
for (int s = 0; s < num_threads; s++)
sd.pieces[s].resize(num_threads);
PMWMSSorterPU<RandomAccessIterator>* pus = new PMWMSSorterPU<RandomAccessIterator>[num_threads];
difference_type* starts = sd.starts = new difference_type[num_threads + 1];
difference_type chunk_length = n / num_threads, split = n % num_threads, start = 0;
for (int i = 0; i < num_threads; i++)
{
starts[i] = start;
start += (i < split) ? (chunk_length + 1) : chunk_length;
pus[i].num_threads = num_threads;
pus[i].iam = i;
pus[i].sd = &sd;
pus[i].stable = stable;
}
starts[num_threads] = start;
// Now sort in parallel.
#pragma omp parallel num_threads(num_threads)
parallel_sort_mwms_pu(&(pus[omp_get_thread_num()]), comp);
// XXX sd as RAII
delete[] starts;
delete[] sd.temporaries;
delete[] sd.sorting_places;
delete[] sd.merging_places;
if (Settings::sort_splitting == Settings::SAMPLING)
delete[] sd.samples;
delete[] sd.offsets;
delete[] sd.pieces;
delete[] pus;
}
}
#endif

View File

@ -0,0 +1,322 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/**
* @file parallel/numeric
*
* @brief Parallel STL fucntion calls corresponding to stl_numeric.h.
* The functions defined here mainly do case switches and
* call the actual parallelized versions in other files.
* Inlining policy: Functions that basically only contain one function call,
* are declared inline.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler and Felix Putze.
#ifndef _GLIBCXX_PARALLEL_NUMERIC_H
#define _GLIBCXX_PARALLEL_NUMERIC_H 1
#include <numeric>
#include <functional>
#include <parallel/numericfwd.h>
#include <parallel/iterator.h>
#include <parallel/for_each.h>
#include <parallel/for_each_selectors.h>
#include <parallel/partial_sum.h>
namespace std
{
namespace __parallel
{
// Sequential fallback.
template<typename InputIterator, typename T>
inline T
accumulate(InputIterator begin, InputIterator end, T init, __gnu_parallel::sequential_tag)
{ return _GLIBCXX_STD_P::accumulate(begin, end, init); }
// Sequential fallback.
template<typename InputIterator, typename T, typename BinaryOperation>
inline T
accumulate(InputIterator begin, InputIterator end, T init,
BinaryOperation binary_op, __gnu_parallel::sequential_tag)
{ return _GLIBCXX_STD_P::accumulate(begin, end, init, binary_op); }
// Sequential fallback for input iterator case.
template<typename InputIterator, typename T, typename IteratorTag>
inline T
accumulate_switch(InputIterator begin, InputIterator end, T init, IteratorTag, __gnu_parallel::parallelism parallelism_tag)
{ return accumulate(begin, end, init, __gnu_parallel::sequential_tag()); }
// Public interface.
template<typename InputIterator, typename T>
inline T
accumulate(InputIterator begin, InputIterator end, T init, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_unbalanced)
{
return accumulate_switch(begin, end, init, std::plus<typename std::iterator_traits<InputIterator>::value_type>(), typename std::iterator_traits<InputIterator>::iterator_category(), parallelism_tag);
}
// Sequential fallback for input iterator case.
template<typename InputIterator, typename T, typename BinaryOperation, typename IteratorTag>
T
accumulate_switch(InputIterator begin, InputIterator end, T init, BinaryOperation binary_op, IteratorTag, __gnu_parallel::parallelism parallelism_tag)
{
return accumulate(begin, end, init, binary_op, __gnu_parallel::sequential_tag());
}
// Parallel algorithm for random access iterators.
template<typename _RandomAccessIterator, typename T, typename BinaryOperation>
T
accumulate_switch(_RandomAccessIterator begin, _RandomAccessIterator end, T init, BinaryOperation binary_op, random_access_iterator_tag, __gnu_parallel::parallelism parallelism_tag)
{
if (_GLIBCXX_PARALLEL_CONDITION(static_cast<__gnu_parallel::sequence_index_t>(end - begin) >= __gnu_parallel::Settings::accumulate_minimal_n && __gnu_parallel::is_parallel(parallelism_tag)))
{
T res = init;
__gnu_parallel::accumulate_selector<_RandomAccessIterator> my_selector;
__gnu_parallel::for_each_template_random_access(begin, end, __gnu_parallel::nothing(), my_selector, __gnu_parallel::accumulate_binop_reduct<BinaryOperation>(binary_op), res, res, -1, parallelism_tag);
return res;
}
else
return accumulate(begin, end, init, binary_op, __gnu_parallel::sequential_tag());
}
// Public interface.
template<typename InputIterator, typename T, typename BinaryOperation>
inline T
accumulate(InputIterator begin, InputIterator end, T init, BinaryOperation binary_op, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_unbalanced)
{
return accumulate_switch(begin, end, init, binary_op, typename std::iterator_traits<InputIterator>::iterator_category(), parallelism_tag);
}
// Sequential fallback.
template<typename InputIterator1, typename InputIterator2, typename T, typename BinaryFunction1, typename BinaryFunction2>
inline T
inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, BinaryFunction1 binary_op1, BinaryFunction2 binary_op2, __gnu_parallel::sequential_tag)
{
return _GLIBCXX_STD_P::inner_product(first1, last1, first2, init, binary_op1, binary_op2);
}
// Sequential fallback.
template<typename InputIterator1, typename InputIterator2, typename T>
inline T
inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, __gnu_parallel::sequential_tag)
{
return _GLIBCXX_STD_P::inner_product(first1, last1, first2, init);
}
// Parallel algorithm for random access iterators.
template<typename RandomAccessIterator1, typename RandomAccessIterator2, typename T, typename BinaryFunction1, typename BinaryFunction2>
T
inner_product_switch(RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, T init, BinaryFunction1 binary_op1, BinaryFunction2 binary_op2, random_access_iterator_tag, random_access_iterator_tag, __gnu_parallel::parallelism parallelism_tag)
{
if (_GLIBCXX_PARALLEL_CONDITION((last1 - first1) >= __gnu_parallel::Settings::accumulate_minimal_n && __gnu_parallel::is_parallel(parallelism_tag)))
{
T res = init;
__gnu_parallel::inner_product_selector<RandomAccessIterator1, RandomAccessIterator2, T> my_selector(first1, first2);
__gnu_parallel::for_each_template_random_access(first1, last1, binary_op2, my_selector, binary_op1, res, res, -1, parallelism_tag);
return res;
}
else
return inner_product(first1, last1, first2, init, __gnu_parallel::sequential_tag());
}
// No parallelism for input iterators.
template<typename InputIterator1, typename InputIterator2, typename T, typename BinaryFunction1, typename BinaryFunction2, typename IteratorTag1, typename IteratorTag2>
inline T
inner_product_switch(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, BinaryFunction1 binary_op1, BinaryFunction2 binary_op2, IteratorTag1, IteratorTag2, __gnu_parallel::parallelism parallelism_tag)
{
return _GLIBCXX_STD_P::inner_product(first1, last1, first2, init, binary_op1, binary_op2);
}
template<typename InputIterator1, typename InputIterator2, typename T, typename BinaryFunction1, typename BinaryFunction2>
inline T
inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, BinaryFunction1 binary_op1, BinaryFunction2 binary_op2, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_unbalanced)
{
typedef iterator_traits<InputIterator1> traits1_type;
typedef typename traits1_type::iterator_category iterator1_category;
typedef iterator_traits<InputIterator2> traits2_type;
typedef typename traits2_type::iterator_category iterator2_category;
return inner_product_switch(first1, last1, first2, init, binary_op1, binary_op2, iterator1_category(), iterator2_category(), parallelism_tag);
}
template<typename InputIterator1, typename InputIterator2, typename T>
inline T
inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_unbalanced)
{
typedef iterator_traits<InputIterator1> traits_type;
typedef typename traits_type::value_type value_type;
return inner_product(first1, last1, first2, init, std::plus<value_type>(),
std::multiplies<value_type>(), parallelism_tag);
}
// Sequential fallback.
template<typename InputIterator, typename OutputIterator>
inline OutputIterator
partial_sum(InputIterator begin, InputIterator end, OutputIterator result,
__gnu_parallel::sequential_tag)
{ return _GLIBCXX_STD_P::partial_sum(begin, end, result); }
// Sequential fallback.
template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
inline OutputIterator
partial_sum(InputIterator begin, InputIterator end, OutputIterator result,
BinaryOperation bin_op, __gnu_parallel::sequential_tag)
{ return _GLIBCXX_STD_P::partial_sum(begin, end, result, bin_op); }
// Sequential fallback for input iterator case.
template<typename InputIterator, typename OutputIterator, typename BinaryOperation, typename IteratorTag1, typename IteratorTag2>
inline OutputIterator
partial_sum_switch(InputIterator begin, InputIterator end, OutputIterator result, BinaryOperation bin_op, IteratorTag1, IteratorTag2)
{
return _GLIBCXX_STD_P::partial_sum(begin, end, result, bin_op);
}
// Parallel algorithm for random access iterators.
template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
OutputIterator
partial_sum_switch(InputIterator begin, InputIterator end,
OutputIterator result, BinaryOperation bin_op,
random_access_iterator_tag, random_access_iterator_tag)
{
if (_GLIBCXX_PARALLEL_CONDITION(static_cast<__gnu_parallel::sequence_index_t>(end - begin) >= __gnu_parallel::Settings::partial_sum_minimal_n))
return __gnu_parallel::parallel_partial_sum(begin, end, result, bin_op);
else
return partial_sum(begin, end, result, bin_op, __gnu_parallel::sequential_tag());
}
// Public interface.
template<typename InputIterator, typename OutputIterator>
inline OutputIterator
partial_sum(InputIterator begin, InputIterator end, OutputIterator result)
{
typedef typename iterator_traits<InputIterator>::value_type value_type;
return partial_sum(begin, end, result, std::plus<value_type>());
}
// Public interface
template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
inline OutputIterator
partial_sum(InputIterator begin, InputIterator end, OutputIterator result,
BinaryOperation binary_op)
{
typedef iterator_traits<InputIterator> traitsi_type;
typedef typename traitsi_type::iterator_category iteratori_category;
typedef iterator_traits<OutputIterator> traitso_type;
typedef typename traitso_type::iterator_category iteratoro_category;
return partial_sum_switch(begin, end, result, binary_op,
iteratori_category(), iteratoro_category());
}
// Sequential fallback.
template<typename InputIterator, typename OutputIterator>
inline OutputIterator
adjacent_difference(InputIterator begin, InputIterator end,
OutputIterator result, __gnu_parallel::sequential_tag)
{ return _GLIBCXX_STD_P::adjacent_difference(begin, end, result); }
// Sequential fallback.
template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
inline OutputIterator
adjacent_difference(InputIterator begin, InputIterator end,
OutputIterator result, BinaryOperation bin_op,
__gnu_parallel::sequential_tag)
{
return _GLIBCXX_STD_P::adjacent_difference(begin, end, result, bin_op);
}
// Sequential fallback for input iterator case.
template<typename InputIterator, typename OutputIterator, typename BinaryOperation, typename IteratorTag1, typename IteratorTag2>
inline OutputIterator
adjacent_difference_switch(InputIterator begin, InputIterator end,
OutputIterator result, BinaryOperation bin_op,
IteratorTag1, IteratorTag2, __gnu_parallel::parallelism)
{ return adjacent_difference(begin, end, result, bin_op); }
// Parallel algorithm for random access iterators.
template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
OutputIterator
adjacent_difference_switch(InputIterator begin, InputIterator end,
OutputIterator result, BinaryOperation bin_op,
random_access_iterator_tag, random_access_iterator_tag,
__gnu_parallel::parallelism parallelism_tag)
{
if (_GLIBCXX_PARALLEL_CONDITION(static_cast<__gnu_parallel::sequence_index_t>(end - begin) >= __gnu_parallel::Settings::adjacent_difference_minimal_n && __gnu_parallel::is_parallel(parallelism_tag)))
{
bool dummy = true;
typedef __gnu_parallel::iterator_pair<InputIterator, OutputIterator, random_access_iterator_tag> ip;
*result = *begin;
ip begin_pair(begin + 1, result + 1), end_pair(end, result + (end - begin));
__gnu_parallel::adjacent_difference_selector<ip> functionality;
__gnu_parallel::for_each_template_random_access(begin_pair, end_pair, bin_op, functionality, __gnu_parallel::dummy_reduct(), dummy, dummy, -1, parallelism_tag);
return functionality.finish_iterator;
}
else
return adjacent_difference(begin, end, result, bin_op, __gnu_parallel::sequential_tag());
}
// Public interface.
template<typename InputIterator, typename OutputIterator>
inline OutputIterator
adjacent_difference(InputIterator begin, InputIterator end,
OutputIterator result,
__gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced)
{
typedef iterator_traits<InputIterator> traits_type;
typedef typename traits_type::value_type value_type;
return adjacent_difference(begin, end, result, std::minus<value_type>());
}
// Public interface.
template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
inline OutputIterator
adjacent_difference(InputIterator begin, InputIterator end,
OutputIterator result, BinaryOperation binary_op,
__gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced)
{
typedef iterator_traits<InputIterator> traitsi_type;
typedef typename traitsi_type::iterator_category iteratori_category;
typedef iterator_traits<OutputIterator> traitso_type;
typedef typename traitso_type::iterator_category iteratoro_category;
return adjacent_difference_switch(begin, end, result, binary_op,
iteratori_category(),
iteratoro_category(), parallelism_tag);
}
} // end namespace
} // end namespace
#endif /* _GLIBCXX_NUMERIC_H */

View File

@ -0,0 +1,152 @@
// <numeric> parallel extensions -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/numericfwd.h
* This file is a GNU parallel extension to the Standard C++ Library.
*/
#ifndef _GLIBCXX_PARALLEL_NUMERICFWD_H
#define _GLIBCXX_PARALLEL_NUMERICFWD_H 1
#pragma GCC system_header
#include <parallel/tags.h>
#include <parallel/settings.h>
namespace std
{
namespace __parallel
{
template<typename _IIter, typename T>
inline T
accumulate(_IIter, _IIter, T, __gnu_parallel::sequential_tag);
template<typename _IIter, typename T, typename _BinaryOper>
inline T
accumulate(_IIter, _IIter, T, _BinaryOper, __gnu_parallel::sequential_tag);
template<typename _IIter, typename T>
inline T
accumulate(_IIter, _IIter, T, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_unbalanced);
template<typename _IIter, typename T, typename _BinaryOper>
inline T
accumulate(_IIter, _IIter, T, _BinaryOper, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_unbalanced);
template<typename _IIter, typename T, typename _Tag>
inline T
accumulate_switch(_IIter, _IIter, T, _Tag, __gnu_parallel::parallelism parallelism_tag);
template<typename _IIter, typename T, typename _BinaryOper, typename _Tag>
T
accumulate_switch(_IIter, _IIter, T, _BinaryOper, _Tag, __gnu_parallel::parallelism parallelism_tag);
template<typename _RAIter, typename T, typename _BinaryOper>
T
accumulate_switch(_RAIter, _RAIter, T, _BinaryOper, random_access_iterator_tag, __gnu_parallel::parallelism parallelism_tag);
template<typename _IIter, typename _OIter>
inline _OIter
adjacent_difference(_IIter, _IIter, _OIter, __gnu_parallel::sequential_tag);
template<typename _IIter, typename _OIter, typename _BinaryOper>
inline _OIter
adjacent_difference(_IIter, _IIter, _OIter, _BinaryOper, __gnu_parallel::sequential_tag);
template<typename _IIter, typename _OIter>
inline _OIter
adjacent_difference(_IIter, _IIter, _OIter, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _IIter, typename _OIter, typename _BinaryOper>
inline _OIter
adjacent_difference(_IIter, _IIter, _OIter, _BinaryOper, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_balanced);
template<typename _IIter, typename _OIter, typename _BinaryOper, typename _Tag1, typename _Tag2>
inline _OIter
adjacent_difference_switch(_IIter, _IIter, _OIter, _BinaryOper, _Tag1, _Tag2, __gnu_parallel::parallelism);
template<typename _IIter, typename _OIter, typename _BinaryOper>
_OIter
adjacent_difference_switch(_IIter, _IIter, _OIter, _BinaryOper, random_access_iterator_tag, random_access_iterator_tag, __gnu_parallel::parallelism parallelism_tag);
template<typename _IIter1, typename _IIter2, typename T, typename BinaryFunction1, typename BinaryFunction2>
inline T
inner_product(_IIter1, _IIter1, _IIter2, T, BinaryFunction1, BinaryFunction2, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename T>
inline T
inner_product(_IIter1, _IIter1, _IIter2, T, __gnu_parallel::sequential_tag);
template<typename _IIter1, typename _IIter2, typename T, typename BinaryFunction1, typename BinaryFunction2>
inline T
inner_product(_IIter1, _IIter1, _IIter2, T, BinaryFunction1, BinaryFunction2, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_unbalanced);
template<typename _IIter1, typename _IIter2, typename T>
inline T
inner_product(_IIter1, _IIter1, _IIter2, T, __gnu_parallel::parallelism parallelism_tag = __gnu_parallel::parallel_unbalanced);
template<typename _RAIter1, typename _RAIter2, typename T, typename BinaryFunction1, typename BinaryFunction2>
T
inner_product_switch(_RAIter1, _RAIter1, _RAIter2, T, BinaryFunction1, BinaryFunction2, random_access_iterator_tag, random_access_iterator_tag, __gnu_parallel::parallelism parallelism_tag);
template<typename _IIter1, typename _IIter2, typename T, typename BinaryFunction1, typename BinaryFunction2, typename _Tag1, typename _Tag2>
inline T
inner_product_switch(_IIter1, _IIter1, _IIter2, T, BinaryFunction1, BinaryFunction2, _Tag1, _Tag2, __gnu_parallel::parallelism parallelism_tag);
template<typename _IIter, typename _OIter>
inline _OIter
partial_sum(_IIter, _IIter, _OIter, __gnu_parallel::sequential_tag);
template<typename _IIter, typename _OIter, typename _BinaryOper>
inline _OIter
partial_sum(_IIter, _IIter, _OIter, _BinaryOper, __gnu_parallel::sequential_tag);
template<typename _IIter, typename _OIter>
inline _OIter
partial_sum(_IIter, _IIter, _OIter result);
template<typename _IIter, typename _OIter, typename _BinaryOper>
inline _OIter
partial_sum(_IIter, _IIter, _OIter, _BinaryOper);
template<typename _IIter, typename _OIter, typename _BinaryOper, typename _Tag1, typename _Tag2>
inline _OIter
partial_sum_switch(_IIter, _IIter, _OIter, _BinaryOper, _Tag1, _Tag2);
template<typename _IIter, typename _OIter, typename _BinaryOper>
_OIter
partial_sum_switch(_IIter, _IIter, _OIter, _BinaryOper, random_access_iterator_tag, random_access_iterator_tag);
} // end namespace
} // end namespace
#endif

View File

@ -0,0 +1,105 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/omp_loop.h
* @brief Parallelization of embarrassingly parallel execution by
* means of an OpenMP for loop.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze.
#ifndef _GLIBCXX_PARALLEL_OMP_LOOP_H
#define _GLIBCXX_PARALLEL_OMP_LOOP_H 1
#include <omp.h>
#include <parallel/settings.h>
#include <parallel/basic_iterator.h>
namespace __gnu_parallel
{
/** @brief Embarrassingly parallel algorithm for random access
* iterators, using an OpenMP for loop.
*
* @param begin Begin iterator of element sequence.
* @param end End iterator of element sequence.
* @param o User-supplied functor (comparator, predicate, adding
* functor, etc.).
* @param f Functor to "process" an element with op (depends on
* desired functionality, e. g. for std::for_each(), ...).
* @param r Functor to "add" a single result to the already
* processed elements (depends on functionality).
* @param base Base value for reduction.
* @param output Pointer to position where final result is written to
* @param bound Maximum number of elements processed (e. g. for
* std::count_n()).
* @return User-supplied functor (that may contain a part of the result).
*/
template<typename RandomAccessIterator, typename Op, typename Fu, typename Red, typename Result>
Op
for_each_template_random_access_omp_loop(RandomAccessIterator begin, RandomAccessIterator end, Op o, Fu& f, Red r, Result base, Result& output, typename std::iterator_traits<RandomAccessIterator>::difference_type bound)
{
typedef typename std::iterator_traits<RandomAccessIterator>::difference_type difference_type;
thread_index_t num_threads = (get_max_threads() < (end - begin)) ? get_max_threads() : static_cast<thread_index_t>((end - begin));
Result *thread_results = new Result[num_threads];
difference_type length = end - begin;
for (thread_index_t i = 0; i < num_threads; i++)
{
thread_results[i] = r(thread_results[i], f(o, begin+i));
}
#pragma omp parallel num_threads(num_threads)
{
#pragma omp for schedule(dynamic, Settings::workstealing_chunk_size)
for (difference_type pos = 0; pos < length; pos++)
{
thread_results[omp_get_thread_num()] = r(thread_results[omp_get_thread_num()], f(o, begin+pos));
}
}
for (thread_index_t i = 0; i < num_threads; i++)
{
output = r(output, thread_results[i]);
}
delete [] thread_results;
// Points to last element processed (needed as return value for
// some algorithms like transform).
f.finish_iterator = begin + length;
return o;
}
} // end namespace
#endif

View File

@ -0,0 +1,111 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/omp_loop_static.h
* @brief Parallelization of embarrassingly parallel execution by
* means of an OpenMP for loop with static scheduling.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze.
#ifndef _GLIBCXX_PARALLEL_OMP_LOOP_STATIC_H
#define _GLIBCXX_PARALLEL_OMP_LOOP_STATIC_H 1
#include <omp.h>
#include <parallel/settings.h>
#include <parallel/basic_iterator.h>
namespace __gnu_parallel
{
/** @brief Embarrassingly parallel algorithm for random access
* iterators, using an OpenMP for loop with static scheduling.
*
* @param begin Begin iterator of element sequence.
* @param end End iterator of element sequence.
* @param o User-supplied functor (comparator, predicate, adding
* functor, ...).
* @param f Functor to "process" an element with op (depends on
* desired functionality, e. g. for std::for_each(), ...).
* @param r Functor to "add" a single result to the already processed
* elements (depends on functionality).
* @param base Base value for reduction.
* @param output Pointer to position where final result is written to
* @param bound Maximum number of elements processed (e. g. for
* std::count_n()).
* @return User-supplied functor (that may contain a part of the result).
*/
template<typename RandomAccessIterator, typename Op, typename Fu, typename Red, typename Result>
Op
for_each_template_random_access_omp_loop_static(RandomAccessIterator begin,
RandomAccessIterator end,
Op o, Fu& f, Red r,
Result base, Result& output,
typename std::iterator_traits<RandomAccessIterator>::difference_type bound)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::difference_type difference_type;
thread_index_t num_threads = (get_max_threads() < (end - begin)) ? get_max_threads() : (end - begin);
Result *thread_results = new Result[num_threads];
difference_type length = end - begin;
for (thread_index_t i = 0; i < num_threads; i++)
{
thread_results[i] = r(thread_results[i], f(o, begin+i));
}
#pragma omp parallel num_threads(num_threads)
{
#pragma omp for schedule(static, Settings::workstealing_chunk_size)
for (difference_type pos = 0; pos < length; pos++)
{
thread_results[omp_get_thread_num()] = r(thread_results[omp_get_thread_num()], f(o, begin+pos));
}
}
for (thread_index_t i = 0; i < num_threads; i++)
{
output = r(output, thread_results[i]);
}
delete [] thread_results;
// Points to last element processed (needed as return value for
// some algorithms like transform).
f.finish_iterator = begin + length;
return o;
}
} // end namespace
#endif

View File

@ -0,0 +1,120 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/par_loop.h
* @brief Parallelization of embarrassingly parallel execution by
* means of equal splitting.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze.
#ifndef _GLIBCXX_PARALLEL_PAR_LOOP_H
#define _GLIBCXX_PARALLEL_PAR_LOOP_H 1
#include <omp.h>
#include <parallel/settings.h>
namespace __gnu_parallel
{
/** @brief Embarrassingly parallel algorithm for random access
* iterators, using hand-crafted parallelization by equal splitting
* the work.
*
* @param begin Begin iterator of element sequence.
* @param end End iterator of element sequence.
* @param o User-supplied functor (comparator, predicate, adding
* functor, ...)
* @param f Functor to "process" an element with op (depends on
* desired functionality, e. g. for std::for_each(), ...).
* @param r Functor to "add" a single result to the already
* processed elements (depends on functionality).
* @param base Base value for reduction.
* @param output Pointer to position where final result is written to
* @param bound Maximum number of elements processed (e. g. for
* std::count_n()).
* @return User-supplied functor (that may contain a part of the result).
*/
template<typename RandomAccessIterator, typename Op, typename Fu, typename Red, typename Result>
Op
for_each_template_random_access_ed(RandomAccessIterator begin,
RandomAccessIterator end, Op o, Fu& f,
Red r, Result base, Result& output,
typename std::iterator_traits<RandomAccessIterator>::difference_type bound)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::difference_type difference_type;
const difference_type length = end - begin;
const difference_type settings_threads = static_cast<difference_type>(get_max_threads());
const difference_type dmin = settings_threads < length ? settings_threads : length;
const difference_type dmax = dmin > 1 ? dmin : 1;
thread_index_t num_threads = static_cast<thread_index_t>(dmax);
Result *thread_results = new Result[num_threads];
#pragma omp parallel num_threads(num_threads)
{
// Neutral element.
Result reduct = Result();
thread_index_t p = num_threads;
thread_index_t iam = omp_get_thread_num();
difference_type start = iam * length / p;
difference_type limit = (iam == p - 1) ? length : (iam + 1) * length / p;
if (start < limit)
{
reduct = f(o, begin + start);
start++;
}
for (; start < limit; start++)
reduct = r(reduct, f(o, begin + start));
thread_results[iam] = reduct;
}
for (thread_index_t i = 0; i < num_threads; i++)
output = r(output, thread_results[i]);
// Points to last element processed (needed as return value for
// some algorithms like transform).
f.finish_iterator = begin + length;
return o;
}
} // end namespace
#endif

View File

@ -0,0 +1,48 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/parallel.h
* @brief End-user include file. Provides advanced settings and
* tuning options.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze and Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_PARALLEL_H
#define _GLIBCXX_PARALLEL_PARALLEL_H 1
#include <parallel/features.h>
#include <parallel/compiletime_settings.h>
#include <parallel/types.h>
#include <parallel/tags.h>
#include <parallel/settings.h>
#endif

View File

@ -0,0 +1,191 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/partial_sum.h
* @brief Parallel implementation of std::partial_sum(), i. e. prefix
* sums.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_PARTIAL_SUM_H
#define _GLIBCXX_PARALLEL_PARTIAL_SUM_H 1
#include <omp.h>
#include <bits/stl_algobase.h>
#include <parallel/parallel.h>
#include <parallel/numericfwd.h>
namespace __gnu_parallel
{
// Problem: there is no 0-element given.
/** @brief Base case prefix sum routine.
* @param begin Begin iterator of input sequence.
* @param end End iterator of input sequence.
* @param result Begin iterator of output sequence.
* @param bin_op Associative binary function.
* @param value Start value. Must be passed since the neutral
* element is unknown in general.
* @return End iterator of output sequence. */
template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
inline OutputIterator
parallel_partial_sum_basecase(InputIterator begin, InputIterator end,
OutputIterator result, BinaryOperation bin_op,
typename std::iterator_traits<InputIterator>::value_type value)
{
if (begin == end)
return result;
while (begin != end)
{
value = bin_op(value, *begin);
*result = value;
result++;
begin++;
}
return result;
}
/** @brief Parallel partial sum implmenetation, two-phase approach,
no recursion.
* @param begin Begin iterator of input sequence.
* @param end End iterator of input sequence.
* @param result Begin iterator of output sequence.
* @param bin_op Associative binary function.
* @param n Length of sequence.
* @param num_threads Number of threads to use.
* @return End iterator of output sequence.
*/
template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
OutputIterator
parallel_partial_sum_linear(InputIterator begin, InputIterator end,
OutputIterator result, BinaryOperation bin_op,
typename std::iterator_traits<InputIterator>::difference_type n, int num_threads)
{
typedef std::iterator_traits<InputIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
if (num_threads > (n - 1))
num_threads = static_cast<thread_index_t>(n - 1);
if (num_threads < 2)
{
*result = *begin;
return parallel_partial_sum_basecase(begin + 1, end, result + 1, bin_op, *begin);
}
difference_type borders[num_threads + 2];
if (Settings::partial_sum_dilatation == 1.0f)
equally_split(n, num_threads + 1, borders);
else
{
difference_type chunk_length = (int)((double)n / ((double)num_threads + Settings::partial_sum_dilatation)), borderstart = n - num_threads * chunk_length;
borders[0] = 0;
for (int i = 1; i < (num_threads + 1); i++)
{
borders[i] = borderstart;
borderstart += chunk_length;
}
borders[num_threads + 1] = n;
}
value_type* sums = new value_type[num_threads];
OutputIterator target_end;
#pragma omp parallel num_threads(num_threads)
{
int id = omp_get_thread_num();
if (id == 0)
{
*result = *begin;
parallel_partial_sum_basecase(begin + 1, begin + borders[1], result + 1, bin_op, *begin);
sums[0] = *(result + borders[1] - 1);
}
else
{
sums[id] = std::accumulate(begin + borders[id] + 1, begin + borders[id + 1], *(begin + borders[id]), bin_op, __gnu_parallel::sequential_tag());
}
#pragma omp barrier
#pragma omp single
parallel_partial_sum_basecase(sums + 1, sums + num_threads, sums + 1, bin_op, sums[0]);
#pragma omp barrier
// Still same team.
parallel_partial_sum_basecase(begin + borders[id + 1], begin + borders[id + 2], result + borders[id + 1], bin_op, sums[id]);
}
delete[] sums;
return result + n;
}
/** @brief Parallel partial sum front-end.
* @param begin Begin iterator of input sequence.
* @param end End iterator of input sequence.
* @param result Begin iterator of output sequence.
* @param bin_op Associative binary function.
* @return End iterator of output sequence. */
template<typename InputIterator, typename OutputIterator, typename BinaryOperation>
OutputIterator
parallel_partial_sum(InputIterator begin, InputIterator end,
OutputIterator result, BinaryOperation bin_op)
{
_GLIBCXX_CALL(begin - end);
typedef std::iterator_traits<InputIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
difference_type n = end - begin;
int num_threads = get_max_threads();
switch (Settings::partial_sum_algorithm)
{
case Settings::LINEAR:
// Need an initial offset.
return parallel_partial_sum_linear(begin, end, result, bin_op,
n, num_threads);
default:
// Partial_sum algorithm not implemented.
_GLIBCXX_PARALLEL_ASSERT(0);
return end;
}
}
}
#endif

View File

@ -0,0 +1,389 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/partition.h
* @brief Parallel implementation of std::partition(),
* std::nth_element(), and std::partial_sort().
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler and Felix Putze.
#ifndef _GLIBCXX_PARALLEL_PARTITION_H
#define _GLIBCXX_PARALLEL_PARTITION_H 1
#include <parallel/basic_iterator.h>
#include <parallel/sort.h>
#include <bits/stl_algo.h>
#include <parallel/parallel.h>
/** @brief Decide whether to declare certain variable volatile in this file. */
#define _GLIBCXX_VOLATILE volatile
namespace __gnu_parallel
{
/** @brief Parallel implementation of std::partition.
* @param begin Begin iterator of input sequence to split.
* @param end End iterator of input sequence to split.
* @param pred Partition predicate, possibly including some kind of pivot.
* @param max_num_threads Maximum number of threads to use for this task.
* @return Number of elements not fulfilling the predicate. */
template<typename RandomAccessIterator, typename Predicate>
inline typename std::iterator_traits<RandomAccessIterator>::difference_type
parallel_partition(RandomAccessIterator begin, RandomAccessIterator end,
Predicate pred, thread_index_t max_num_threads)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
difference_type n = end - begin;
_GLIBCXX_CALL(n)
// Shared.
_GLIBCXX_VOLATILE difference_type left = 0, right = n - 1;
_GLIBCXX_VOLATILE difference_type leftover_left, leftover_right, leftnew, rightnew;
bool* reserved_left, * reserved_right;
reserved_left = new bool[max_num_threads];
reserved_right = new bool[max_num_threads];
difference_type chunk_size;
if (Settings::partition_chunk_share > 0.0)
chunk_size = std::max((difference_type)Settings::partition_chunk_size, (difference_type)((double)n * Settings::partition_chunk_share / (double)max_num_threads));
else
chunk_size = Settings::partition_chunk_size;
// At least good for two processors.
while (right - left + 1 >= 2 * max_num_threads * chunk_size)
{
difference_type num_chunks = (right - left + 1) / chunk_size;
thread_index_t num_threads = (int)std::min((difference_type)max_num_threads, num_chunks / 2);
for (int r = 0; r < num_threads; r++)
{
reserved_left[r] = false;
reserved_right[r] = false;
}
leftover_left = 0;
leftover_right = 0;
#pragma omp parallel num_threads(num_threads)
{
// Private.
difference_type thread_left, thread_left_border, thread_right, thread_right_border;
thread_left = left + 1;
// Just to satify the condition below.
thread_left_border = thread_left - 1;
thread_right = n - 1;
thread_right_border = thread_right + 1;
bool iam_finished = false;
while (!iam_finished)
{
if (thread_left > thread_left_border)
#pragma omp critical
{
if (left + (chunk_size - 1) > right)
iam_finished = true;
else
{
thread_left = left;
thread_left_border = left + (chunk_size - 1);
left += chunk_size;
}
}
if (thread_right < thread_right_border)
#pragma omp critical
{
if (left > right - (chunk_size - 1))
iam_finished = true;
else
{
thread_right = right;
thread_right_border = right - (chunk_size - 1);
right -= chunk_size;
}
}
if (iam_finished)
break;
// Swap as usual.
while (thread_left < thread_right)
{
while (pred(begin[thread_left]) && thread_left <= thread_left_border)
thread_left++;
while (!pred(begin[thread_right]) && thread_right >= thread_right_border)
thread_right--;
if (thread_left > thread_left_border || thread_right < thread_right_border)
// Fetch new chunk(s).
break;
std::swap(begin[thread_left], begin[thread_right]);
thread_left++;
thread_right--;
}
}
// Now swap the leftover chunks to the right places.
if (thread_left <= thread_left_border)
#pragma omp atomic
leftover_left++;
if (thread_right >= thread_right_border)
#pragma omp atomic
leftover_right++;
#pragma omp barrier
#pragma omp single
{
leftnew = left - leftover_left * chunk_size;
rightnew = right + leftover_right * chunk_size;
}
#pragma omp barrier
// <=> thread_left_border + (chunk_size - 1) >= leftnew
if (thread_left <= thread_left_border
&& thread_left_border >= leftnew)
{
// Chunk already in place, reserve spot.
reserved_left[(left - (thread_left_border + 1)) / chunk_size] = true;
}
// <=> thread_right_border - (chunk_size - 1) <= rightnew
if (thread_right >= thread_right_border
&& thread_right_border <= rightnew)
{
// Chunk already in place, reserve spot.
reserved_right[((thread_right_border - 1) - right) / chunk_size] = true;
}
#pragma omp barrier
if (thread_left <= thread_left_border && thread_left_border < leftnew)
{
// Find spot and swap.
difference_type swapstart = -1;
#pragma omp critical
{
for (int r = 0; r < leftover_left; r++)
if (!reserved_left[r])
{
reserved_left[r] = true;
swapstart = left - (r + 1) * chunk_size;
break;
}
}
#if _GLIBCXX_ASSERTIONS
_GLIBCXX_PARALLEL_ASSERT(swapstart != -1);
#endif
std::swap_ranges(begin + thread_left_border - (chunk_size - 1), begin + thread_left_border + 1, begin + swapstart);
}
if (thread_right >= thread_right_border
&& thread_right_border > rightnew)
{
// Find spot and swap
difference_type swapstart = -1;
#pragma omp critical
{
for (int r = 0; r < leftover_right; r++)
if (!reserved_right[r])
{
reserved_right[r] = true;
swapstart = right + r * chunk_size + 1;
break;
}
}
#if _GLIBCXX_ASSERTIONS
_GLIBCXX_PARALLEL_ASSERT(swapstart != -1);
#endif
std::swap_ranges(begin + thread_right_border, begin + thread_right_border + chunk_size, begin + swapstart);
}
#if _GLIBCXX_ASSERTIONS
#pragma omp barrier
#pragma omp single
{
for (int r = 0; r < leftover_left; r++)
_GLIBCXX_PARALLEL_ASSERT(reserved_left[r]);
for (int r = 0; r < leftover_right; r++)
_GLIBCXX_PARALLEL_ASSERT(reserved_right[r]);
}
#pragma omp barrier
#endif
#pragma omp barrier
left = leftnew;
right = rightnew;
}
} // end "recursion"
difference_type final_left = left, final_right = right;
while (final_left < final_right)
{
// Go right until key is geq than pivot.
while (pred(begin[final_left]) && final_left < final_right)
final_left++;
// Go left until key is less than pivot.
while (!pred(begin[final_right]) && final_left < final_right)
final_right--;
if (final_left == final_right)
break;
std::swap(begin[final_left], begin[final_right]);
final_left++;
final_right--;
}
// All elements on the left side are < piv, all elements on the
// right are >= piv
delete[] reserved_left;
delete[] reserved_right;
// Element "between" final_left and final_right might not have
// been regarded yet
if (final_left < n && !pred(begin[final_left]))
// Really swapped.
return final_left;
else
return final_left + 1;
}
/**
* @brief Parallel implementation of std::nth_element().
* @param begin Begin iterator of input sequence.
* @param nth Iterator of element that must be in position afterwards.
* @param end End iterator of input sequence.
* @param comp Comparator.
*/
template<typename RandomAccessIterator, typename Comparator>
void
parallel_nth_element(RandomAccessIterator begin, RandomAccessIterator nth, RandomAccessIterator end, Comparator comp)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
_GLIBCXX_CALL(end - begin)
RandomAccessIterator split;
value_type pivot;
random_number rng;
difference_type minimum_length = std::max<difference_type>(2, Settings::partition_minimal_n);
// Break if input range to small.
while (static_cast<sequence_index_t>(end - begin) >= minimum_length)
{
difference_type n = end - begin;
RandomAccessIterator pivot_pos = begin + rng(n);
// Swap pivot_pos value to end.
if (pivot_pos != (end - 1))
std::swap(*pivot_pos, *(end - 1));
pivot_pos = end - 1;
// XXX Comparator must have first_value_type, second_value_type, result_type
// Comparator == __gnu_parallel::lexicographic<S, int, __gnu_parallel::less<S, S> >
// pivot_pos == std::pair<S, int>*
// XXX binder2nd only for RandomAccessIterators??
__gnu_parallel::binder2nd<Comparator, value_type, value_type, bool> pred(comp, *pivot_pos);
// Divide, leave pivot unchanged in last place.
RandomAccessIterator split_pos1, split_pos2;
split_pos1 = begin + parallel_partition(begin, end - 1, pred, get_max_threads());
// Left side: < pivot_pos; right side: >= pivot_pos
// Swap pivot back to middle.
if (split_pos1 != pivot_pos)
std::swap(*split_pos1, *pivot_pos);
pivot_pos = split_pos1;
// In case all elements are equal, split_pos1 == 0
if ((split_pos1 + 1 - begin) < (n >> 7) || (end - split_pos1) < (n >> 7))
{
// Very unequal split, one part smaller than one 128th
// elements not stricly larger than the pivot.
__gnu_parallel::unary_negate<__gnu_parallel::binder1st<Comparator, value_type, value_type, bool>, value_type> pred(__gnu_parallel::binder1st<Comparator, value_type, value_type, bool>(comp, *pivot_pos));
// Find other end of pivot-equal range.
split_pos2 = __gnu_sequential::partition(split_pos1 + 1, end, pred);
}
else
// Only skip the pivot.
split_pos2 = split_pos1 + 1;
// Compare iterators.
if (split_pos2 <= nth)
begin = split_pos2;
else if (nth < split_pos1)
end = split_pos1;
else
break;
}
// Only at most Settings::partition_minimal_n elements left.
__gnu_sequential::sort(begin, end, comp);
}
/** @brief Parallel implementation of std::partial_sort().
* @param begin Begin iterator of input sequence.
* @param middle Sort until this position.
* @param end End iterator of input sequence.
* @param comp Comparator. */
template<typename RandomAccessIterator, typename Comparator>
void
parallel_partial_sort(RandomAccessIterator begin, RandomAccessIterator middle, RandomAccessIterator end, Comparator comp)
{
parallel_nth_element(begin, middle, end, comp);
std::sort(begin, middle, comp);
}
} //namespace __gnu_parallel
#undef _GLIBCXX_VOLATILE
#endif

View File

@ -0,0 +1,153 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/queue.h
* @brief Lock-free double-ended queue.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_QUEUE_H
#define _GLIBCXX_PARALLEL_QUEUE_H 1
#include <parallel/types.h>
#include <parallel/base.h>
#include <parallel/compatibility.h>
/** @brief Decide whether to declare certain variable volatile in this file. */
#define _GLIBCXX_VOLATILE volatile
namespace __gnu_parallel
{
/**@brief Double-ended queue of bounded size, allowing lock-free
* atomic access. push_front() and pop_front() must not be called
* concurrently to each other, while pop_back() can be called
* concurrently at all times.
* @c empty(), @c size(), and @c top() are intentionally not provided.
* Calling them would not make sense in a concurrent setting.
* @param T Contained element type. */
template<typename T>
class RestrictedBoundedConcurrentQueue
{
private:
/** @brief Array of elements, seen as cyclic buffer. */
T* base;
/** @brief Maximal number of elements contained at the same time. */
sequence_index_t max_size;
/** @brief Cyclic begin and end pointers contained in one
atomically changeable value. */
_GLIBCXX_VOLATILE lcas_t borders;
public:
/** @brief Constructor. Not to be called concurrent, of course.
* @param max_size Maximal number of elements to be contained. */
RestrictedBoundedConcurrentQueue(sequence_index_t max_size)
{
this->max_size = max_size;
base = new T[max_size];
borders = encode2(0, 0);
#pragma omp flush
}
/** @brief Destructor. Not to be called concurrent, of course. */
~RestrictedBoundedConcurrentQueue()
{
delete[] base;
}
/** @brief Pushes one element into the queue at the front end.
* Must not be called concurrently with pop_front(). */
void push_front(const T& t)
{
lcas_t former_borders = borders;
int former_front, former_back;
decode2(former_borders, former_front, former_back);
*(base + former_front % max_size) = t;
#if _GLIBCXX_ASSERTIONS
// Otherwise: front - back > max_size eventually.
_GLIBCXX_PARALLEL_ASSERT(((former_front + 1) - former_back) <= max_size);
#endif
fetch_and_add(&borders, encode2(1, 0));
}
/** @brief Pops one element from the queue at the front end.
* Must not be called concurrently with pop_front(). */
bool pop_front(T& t)
{
int former_front, former_back;
#pragma omp flush
decode2(borders, former_front, former_back);
while (former_front > former_back)
{
// Chance.
lcas_t former_borders = encode2(former_front, former_back);
lcas_t new_borders = encode2(former_front - 1, former_back);
if (compare_and_swap(&borders, former_borders, new_borders))
{
t = *(base + (former_front - 1) % max_size);
return true;
}
#pragma omp flush
decode2(borders, former_front, former_back);
}
return false;
}
/** @brief Pops one element from the queue at the front end.
* Must not be called concurrently with pop_front(). */
bool pop_back(T& t) //queue behavior
{
int former_front, former_back;
#pragma omp flush
decode2(borders, former_front, former_back);
while (former_front > former_back)
{
// Chance.
lcas_t former_borders = encode2(former_front, former_back);
lcas_t new_borders = encode2(former_front, former_back + 1);
if (compare_and_swap(&borders, former_borders, new_borders))
{
t = *(base + former_back % max_size);
return true;
}
#pragma omp flush
decode2(borders, former_front, former_back);
}
return false;
}
};
} //namespace __gnu_parallel
#undef _GLIBCXX_VOLATILE
#endif

View File

@ -0,0 +1,172 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/quicksort.h
* @brief Implementation of a unbalanced parallel quicksort (in-place).
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_QUICKSORT_H
#define _GLIBCXX_PARALLEL_QUICKSORT_H 1
#include <parallel/parallel.h>
#include <parallel/partition.h>
namespace __gnu_parallel
{
/** @brief Unbalanced quicksort divide step.
* @param begin Begin iterator of subsequence.
* @param end End iterator of subsequence.
* @param comp Comparator.
* @param pivot_rank Desired rank of the pivot.
* @param num_samples Chosse pivot from that many samples.
* @param num_threads Number of threads that are allowed to work on
* this part.
*/
template<typename RandomAccessIterator, typename Comparator>
inline typename std::iterator_traits<RandomAccessIterator>::difference_type
parallel_sort_qs_divide(RandomAccessIterator begin, RandomAccessIterator end,
Comparator comp,
typename std::iterator_traits<RandomAccessIterator>::difference_type pivot_rank,
typename std::iterator_traits<RandomAccessIterator>::difference_type num_samples, thread_index_t num_threads)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
difference_type n = end - begin;
num_samples = std::min(num_samples, n);
value_type samples[num_samples];
for (difference_type s = 0; s < num_samples; s++)
samples[s] = begin[(unsigned long long)s * n / num_samples];
__gnu_sequential::sort(samples, samples + num_samples, comp);
value_type& pivot = samples[pivot_rank * num_samples / n];
__gnu_parallel::binder2nd<Comparator, value_type, value_type, bool> pred(comp, pivot);
difference_type split = parallel_partition(begin, end, pred, num_threads);
return split;
}
/** @brief Unbalanced quicksort conquer step.
* @param begin Begin iterator of subsequence.
* @param end End iterator of subsequence.
* @param comp Comparator.
* @param num_threads Number of threads that are allowed to work on
* this part.
*/
template<typename RandomAccessIterator, typename Comparator>
inline void
parallel_sort_qs_conquer(RandomAccessIterator begin, RandomAccessIterator end, Comparator comp, int num_threads)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
if (num_threads <= 1)
{
__gnu_sequential::sort(begin, end, comp);
return;
}
difference_type n = end - begin, pivot_rank;
if (n <= 1)
return;
thread_index_t num_processors_left;
if ((num_threads % 2) == 1)
num_processors_left = num_threads / 2 + 1;
else
num_processors_left = num_threads / 2;
pivot_rank = n * num_processors_left / num_threads;
difference_type split = parallel_sort_qs_divide(begin, end, comp, pivot_rank,
Settings::sort_qs_num_samples_preset, num_threads);
#pragma omp parallel sections
{
#pragma omp section
parallel_sort_qs_conquer(begin, begin + split, comp, num_processors_left);
#pragma omp section
parallel_sort_qs_conquer(begin + split, end, comp, num_threads - num_processors_left);
}
}
/** @brief Unbalanced quicksort main call.
* @param begin Begin iterator of input sequence.
* @param end End iterator input sequence, ignored.
* @param comp Comparator.
* @param n Length of input sequence.
* @param num_threads Number of threads that are allowed to work on
* this part.
*/
template<typename RandomAccessIterator, typename Comparator>
inline void
parallel_sort_qs(RandomAccessIterator begin, RandomAccessIterator end,
Comparator comp,
typename std::iterator_traits<RandomAccessIterator>::difference_type n, int num_threads)
{
_GLIBCXX_CALL(n)
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
if (n == 0)
return;
// At least one element per processor.
if (num_threads > n)
num_threads = static_cast<thread_index_t>(n);
Settings::sort_qs_num_samples_preset = 100;
// Hard to avoid.
omp_set_num_threads(num_threads);
bool old_nested = (omp_get_nested() != 0);
omp_set_nested(true);
parallel_sort_qs_conquer(begin, begin + n, comp, num_threads);
omp_set_nested(old_nested);
}
} //namespace __gnu_parallel
#endif

View File

@ -0,0 +1,386 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/random_number.h
* @brief Random number generator based on the Mersenne twister.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_RANDOM_NUMBER_H
#define _GLIBCXX_PARALLEL_RANDOM_NUMBER_H 1
#include <parallel/types.h>
namespace __gnu_parallel
{
// XXX use tr1 random number.
// http://www.math.keio.ac.jp/matumoto/emt.html
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
class mersenne_twister
{
public:
typedef UIntType result_type;
static const int word_size = w;
static const int state_size = n;
static const int shift_size = m;
static const int mask_bits = r;
static const UIntType parameter_a = a;
static const int output_u = u;
static const int output_s = s;
static const UIntType output_b = b;
static const int output_t = t;
static const UIntType output_c = c;
static const int output_l = l;
static const bool has_fixed_range = false;
mersenne_twister() { seed(); }
#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x520)
// Work around overload resolution problem (Gennadiy E. Rozental)
explicit mersenne_twister(const UIntType& value)
#else
explicit mersenne_twister(UIntType value)
#endif
{ seed(value); }
template<typename It> mersenne_twister(It& first, It last) { seed(first,last); }
template<typename Generator>
explicit mersenne_twister(Generator & gen) { seed(gen); }
// compiler-generated copy ctor and assignment operator are fine
void seed() { seed(UIntType(5489)); }
#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x520)
// Work around overload resolution problem (Gennadiy E. Rozental)
void seed(const UIntType& value)
#else
void seed(UIntType value)
#endif
{
// New seeding algorithm from
// http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html
// In the previous versions, MSBs of the seed affected only MSBs of the
// state x[].
const UIntType mask = ~0u;
x[0] = value & mask;
for (i = 1; i < n; i++) {
// See Knuth "The Art of Computer Programming" Vol. 2, 3rd ed., page 106
x[i] = (1812433253UL * (x[i-1] ^ (x[i-1] >> (w-2))) + i) & mask;
}
}
// For GCC, moving this function out-of-line prevents inlining, which may
// reduce overall object code size. However, MSVC does not grok
// out-of-line definitions of member function templates.
template<typename Generator>
void seed(Generator & gen)
{
// I could have used std::generate_n, but it takes "gen" by value
for (int j = 0; j < n; j++)
x[j] = gen();
i = n;
}
template<typename It>
void seed(It& first, It last)
{
int j;
for (j = 0; j < n && first != last; ++j, ++first)
x[j] = *first;
i = n;
/* if (first == last && j < n)
throw std::invalid_argument("mersenne_twister::seed");*/
}
result_type min() const { return 0; }
result_type max() const
{
// avoid "left shift count >= with of type" warning
result_type res = 0;
for (int i = 0; i < w; ++i)
res |= (1u << i);
return res;
}
result_type operator()();
static bool validation(result_type v) { return val == v; }
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
friend bool operator==(const mersenne_twister& x, const mersenne_twister& y)
{
for (int j = 0; j < state_size; ++j)
if (x.compute(j) != y.compute(j))
return false;
return true;
}
friend bool operator!=(const mersenne_twister& x, const mersenne_twister& y)
{ return !(x == y); }
#else
// Use a member function; Streamable concept not supported.
bool operator==(const mersenne_twister& rhs) const
{
for (int j = 0; j < state_size; ++j)
if (compute(j) != rhs.compute(j))
return false;
return true;
}
bool operator!=(const mersenne_twister& rhs) const
{ return !(*this == rhs); }
#endif
private:
// returns x(i-n+index), where index is in 0..n-1
UIntType compute(unsigned int index) const
{
// equivalent to (i-n+index) % 2n, but doesn't produce negative numbers
return x[ (i + n + index) % (2*n) ];
}
void twist(int block);
// state representation: next output is o(x(i))
// x[0] ... x[k] x[k+1] ... x[n-1] x[n] ... x[2*n-1] represents
// x(i-k) ... x(i) x(i+1) ... x(i-k+n-1) x(i-k-n) ... x[i(i-k-1)]
// The goal is to always have x(i-n) ... x(i-1) available for
// operator== and save/restore.
UIntType x[2*n];
int i;
};
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
// A definition is required even for integral static constants
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const bool mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::has_fixed_range;
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const int mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::state_size;
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const int mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::shift_size;
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const int mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::mask_bits;
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const UIntType mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::parameter_a;
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const int mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::output_u;
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const int mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::output_s;
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const UIntType mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::output_b;
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const int mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::output_t;
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const UIntType mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::output_c;
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
const int mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::output_l;
#endif
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
void mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::twist(int block)
{
const UIntType upper_mask = (~0u) << r;
const UIntType lower_mask = ~upper_mask;
if (block == 0) {
for (int j = n; j < 2*n; j++) {
UIntType y = (x[j-n] & upper_mask) | (x[j-(n-1)] & lower_mask);
x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0);
}
} else if (block == 1) {
// split loop to avoid costly modulo operations
{ // extra scope for MSVC brokenness w.r.t. for scope
for (int j = 0; j < n-m; j++) {
UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask);
x[j] = x[j+n+m] ^ (y >> 1) ^ (y&1 ? a : 0);
}
}
for (int j = n-m; j < n-1; j++) {
UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask);
x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0);
}
// last iteration
UIntType y = (x[2*n-1] & upper_mask) | (x[0] & lower_mask);
x[n-1] = x[m-1] ^ (y >> 1) ^ (y&1 ? a : 0);
i = 0;
}
}
template<typename UIntType, int w, int n, int m, int r, UIntType a, int u,
int s, UIntType b, int t, UIntType c, int l, UIntType val>
inline typename mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::result_type
mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::operator()()
{
if (i == n)
twist(0);
else if (i >= 2*n)
twist(1);
// Step 4
UIntType z = x[i];
++i;
z ^= (z >> u);
z ^= ((z << s) & b);
z ^= ((z << t) & c);
z ^= (z >> l);
return z;
}
typedef mersenne_twister<uint32,32,351,175,19,0xccab8ee7,11,
7,0x31b6ab00,15,0xffe50000,17, 0xa37d3c92> mt11213b;
// validation by experiment from mt19937.c
typedef mersenne_twister<uint32,32,624,397,31,0x9908b0df,11,
7,0x9d2c5680,15,0xefc60000,18, 3346425566U> mt19937;
/** @brief Random number generator, based on the Mersenne twister. */
class random_number
{
private:
mt19937 mt;
uint64 supremum, RAND_SUP;
double supremum_reciprocal, RAND_SUP_REC;
uint64 cache; /* assumed to be twice as long as the usual random number */
int bits_left; /* bit results */
static inline uint32 scale_down(uint64 x,
#if _GLIBCXX_SCALE_DOWN_FPU
uint64 /*supremum*/, double supremum_reciprocal)
#else
uint64 supremum, double /*supremum_reciprocal*/)
#endif
{
#if _GLIBCXX_SCALE_DOWN_FPU
return (uint32)(x * supremum_reciprocal);
#else
return static_cast<uint32>(x % supremum);
#endif
}
public:
/** @brief Default constructor. Seed with 0. */
random_number() :
mt(0),
supremum(0x100000000ULL),
RAND_SUP(1ULL << (sizeof(uint32) * 8)),
supremum_reciprocal((double)supremum / (double)RAND_SUP),
RAND_SUP_REC(1.0 / (double)RAND_SUP),
cache(0), bits_left(0)
{
}
/** @brief Constructor.
* @param seed Random seed.
* @param supremum Generate integer random numbers in the interval @c [0,supremum). */
random_number(uint32 seed, uint64 supremum = 0x100000000ULL) :
mt(seed),
supremum(supremum),
RAND_SUP(1ULL << (sizeof(uint32) * 8)),
supremum_reciprocal((double)supremum / (double)RAND_SUP),
RAND_SUP_REC(1.0 / (double)RAND_SUP),
cache(0), bits_left(0)
{
}
/** @brief Generate unsigned random 32-bit integer. */
inline uint32 operator()()
{
return scale_down(mt(), supremum, supremum_reciprocal);
}
/** @brief Generate unsigned random 32-bit integer in the interval @c [0,local_supremum). */
inline uint32 operator()(uint64 local_supremum)
{
return scale_down(mt(), local_supremum, (double)local_supremum * RAND_SUP_REC);
}
/** @brief Set the random seed.
* @param seed to set. */
inline void set_seed(uint32 seed)
{
mt.seed(seed);
cache = mt();
bits_left = 32;
}
/** @brief Generate a number of random bits, compile-time parameter. */
template<int bits>
inline unsigned long genrand_bits()
{
unsigned long res = cache & ((1 << bits) - 1);
cache = cache >> bits;
bits_left -= bits;
if (bits_left < 32)
{
cache |= (((uint64)mt()) << bits_left);
bits_left += 32;
}
return res;
}
/** @brief Generate a number of random bits, run-time parameter.
* @param bits Number of bits to generate. */
inline unsigned long genrand_bits(int bits)
{
unsigned long res = cache & ((1 << bits) - 1);
cache = cache >> bits;
bits_left -= bits;
if (bits_left < 32)
{
cache |= (((uint64)mt()) << bits_left);
bits_left += 32;
}
return res;
}
};
} // namespace __gnu_parallel
#endif

View File

@ -0,0 +1,516 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/random_shuffle.h
* @brief Parallel implementation of std::random_shuffle().
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_RANDOM_SHUFFLE_H
#define _GLIBCXX_PARALLEL_RANDOM_SHUFFLE_H 1
#include <limits>
#include <parallel/basic_iterator.h>
#include <bits/stl_algo.h>
#include <parallel/parallel.h>
#include <parallel/base.h>
#include <parallel/random_number.h>
#include <parallel/timing.h>
namespace __gnu_parallel
{
/** @brief Type to hold the index of a bin.
*
* Since many variables of this type are allocated, it should be
* chosen as small as possible.
*/
typedef unsigned short bin_index;
/** @brief Data known to every thread participating in
__gnu_parallel::parallel_random_shuffle(). */
template<typename RandomAccessIterator>
struct DRandomShufflingGlobalData
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
/** @brief Begin iterator of the source. */
RandomAccessIterator& source;
/** @brief Temporary arrays for each thread. */
value_type** temporaries;
/** @brief Two-dimensional array to hold the thread-bin distribution.
*
* Dimensions (num_threads + 1) x (num_bins + 1). */
difference_type** dist;
/** @brief Start indexes of the threads' chunks. */
difference_type* starts;
/** @brief Number of the thread that will further process the
corresponding bin. */
thread_index_t* bin_proc;
/** @brief Number of bins to distribute to. */
int num_bins;
/** @brief Number of bits needed to address the bins. */
int num_bits;
/** @brief Constructor. */
DRandomShufflingGlobalData(RandomAccessIterator& _source)
: source(_source) { }
};
/** @brief Local data for a thread participating in
__gnu_parallel::parallel_random_shuffle().
*/
template<typename RandomAccessIterator, typename RandomNumberGenerator>
struct DRSSorterPU
{
/** @brief Number of threads participating in total. */
int num_threads;
/** @brief Number of owning thread. */
int iam;
/** @brief Begin index for bins taken care of by this thread. */
bin_index bins_begin;
/** @brief End index for bins taken care of by this thread. */
bin_index bins_end;
/** @brief Random seed for this thread. */
uint32 seed;
/** @brief Pointer to global data. */
DRandomShufflingGlobalData<RandomAccessIterator>* sd;
};
/** @brief Generate a random number in @c [0,2^logp).
* @param logp Logarithm (basis 2) of the upper range bound.
* @param rng Random number generator to use.
*/
template<typename RandomNumberGenerator>
inline int random_number_pow2(int logp, RandomNumberGenerator& rng)
{
return rng.genrand_bits(logp);
}
/** @brief Random shuffle code executed by each thread.
* @param pus Arary of thread-local data records. */
template<typename RandomAccessIterator, typename RandomNumberGenerator>
inline void parallel_random_shuffle_drs_pu(DRSSorterPU<RandomAccessIterator, RandomNumberGenerator>* pus)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
Timing<sequential_tag> t;
t.tic();
DRSSorterPU<RandomAccessIterator, RandomNumberGenerator>* d = &pus[omp_get_thread_num()];
DRandomShufflingGlobalData<RandomAccessIterator>* sd = d->sd;
thread_index_t iam = d->iam;
// Indexing: dist[bin][processor]
difference_type length = sd->starts[iam + 1] - sd->starts[iam];
bin_index* oracles = new bin_index[length];
difference_type* dist = new difference_type[sd->num_bins + 1];
bin_index* bin_proc = new bin_index[sd->num_bins];
value_type** temporaries = new value_type*[d->num_threads];
// Compute oracles and count appearances.
for (bin_index b = 0; b < sd->num_bins + 1; b++)
dist[b] = 0;
int num_bits = sd->num_bits;
random_number rng(d->seed);
// First main loop.
for (difference_type i = 0; i < length; i++)
{
bin_index oracle = random_number_pow2(num_bits, rng);
oracles[i] = oracle;
// To allow prefix (partial) sum.
dist[oracle + 1]++;
}
for (bin_index b = 0; b < sd->num_bins + 1; b++)
sd->dist[b][iam + 1] = dist[b];
t.tic();
#pragma omp barrier
t.tic();
#pragma omp single
{
// Sum up bins, sd->dist[s + 1][d->num_threads] now contains the
// total number of items in bin s
for (bin_index s = 0; s < sd->num_bins; s++)
partial_sum(sd->dist[s + 1], sd->dist[s + 1] + d->num_threads + 1, sd->dist[s + 1]);
}
#pragma omp barrier
t.tic();
sequence_index_t offset = 0, global_offset = 0;
for (bin_index s = 0; s < d->bins_begin; s++)
global_offset += sd->dist[s + 1][d->num_threads];
#pragma omp barrier
for (bin_index s = d->bins_begin; s < d->bins_end; s++)
{
for (int t = 0; t < d->num_threads + 1; t++)
sd->dist[s + 1][t] += offset;
offset = sd->dist[s + 1][d->num_threads];
}
sd->temporaries[iam] = new value_type[offset];
t.tic();
#pragma omp barrier
t.tic();
// Draw local copies to avoid false sharing.
for (bin_index b = 0; b < sd->num_bins + 1; b++)
dist[b] = sd->dist[b][iam];
for (bin_index b = 0; b < sd->num_bins; b++)
bin_proc[b] = sd->bin_proc[b];
for (thread_index_t t = 0; t < d->num_threads; t++)
temporaries[t] = sd->temporaries[t];
RandomAccessIterator source = sd->source;
difference_type start = sd->starts[iam];
// Distribute according to oracles, second main loop.
for (difference_type i = 0; i < length; i++)
{
bin_index target_bin = oracles[i];
thread_index_t target_p = bin_proc[target_bin];
// Last column [d->num_threads] stays unchanged.
temporaries[target_p][dist[target_bin + 1]++] = *(source + i + start);
}
delete[] oracles;
delete[] dist;
delete[] bin_proc;
delete[] temporaries;
t.tic();
#pragma omp barrier
t.tic();
// Shuffle bins internally.
for (bin_index b = d->bins_begin; b < d->bins_end; b++)
{
value_type* begin = sd->temporaries[iam] + ((b == d->bins_begin) ? 0 : sd->dist[b][d->num_threads]),
* end = sd->temporaries[iam] + sd->dist[b + 1][d->num_threads];
sequential_random_shuffle(begin, end, rng);
std::copy(begin, end, sd->source + global_offset + ((b == d->bins_begin) ? 0 : sd->dist[b][d->num_threads]));
}
delete[] sd->temporaries[iam];
t.tic();
t.print();
}
/** @brief Round up to the next greater power of 2.
* @param x Integer to round up */
template<typename T>
T round_up_to_pow2(T x)
{
if (x <= 1)
return 1;
else
return (T)1 << (log2(x - 1) + 1);
}
/** @brief Main parallel random shuffle step.
* @param begin Begin iterator of sequence.
* @param end End iterator of sequence.
* @param n Length of sequence.
* @param num_threads Number of threads to use.
* @param rng Random number generator to use.
*/
template<typename RandomAccessIterator, typename RandomNumberGenerator>
inline void
parallel_random_shuffle_drs(RandomAccessIterator begin, RandomAccessIterator end, typename std::iterator_traits<RandomAccessIterator>::difference_type n, int num_threads, RandomNumberGenerator& rng)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
_GLIBCXX_CALL(n)
if (num_threads > n)
num_threads = static_cast<thread_index_t>(n);
bin_index num_bins, num_bins_cache;
#if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_L1
// Try the L1 cache first.
// Must fit into L1.
num_bins_cache = std::max((difference_type)1, (difference_type)(n / (Settings::L1_cache_size_lb / sizeof(value_type))));
num_bins_cache = round_up_to_pow2(num_bins_cache);
// No more buckets than TLB entries, power of 2
// Power of 2 and at least one element per bin, at most the TLB size.
num_bins = std::min(n, (difference_type)num_bins_cache);
#if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_TLB
// 2 TLB entries needed per bin.
num_bins = std::min((difference_type)Settings::TLB_size / 2, num_bins);
#endif
num_bins = round_up_to_pow2(num_bins);
if (num_bins < num_bins_cache)
{
#endif
// Now try the L2 cache
// Must fit into L2
num_bins_cache = static_cast<bin_index>(std::max((difference_type)1, (difference_type)(n / (Settings::L2_cache_size / sizeof(value_type)))));
num_bins_cache = round_up_to_pow2(num_bins_cache);
// No more buckets than TLB entries, power of 2.
num_bins = static_cast<bin_index>(std::min(n, (difference_type)num_bins_cache));
// Power of 2 and at least one element per bin, at most the TLB size.
#if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_TLB
// 2 TLB entries needed per bin.
num_bins = std::min((difference_type)Settings::TLB_size / 2, num_bins);
#endif
num_bins = round_up_to_pow2(num_bins);
#if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_L1
}
#endif
num_threads = std::min((bin_index)num_threads, (bin_index)num_bins);
if (num_threads <= 1)
return sequential_random_shuffle(begin, end, rng);
DRandomShufflingGlobalData<RandomAccessIterator> sd(begin);
DRSSorterPU<RandomAccessIterator, random_number >* pus = new DRSSorterPU<RandomAccessIterator, random_number >[num_threads];
sd.temporaries = new value_type*[num_threads];
//sd.oracles = new bin_index[n];
sd.dist = new difference_type*[num_bins + 1];
sd.bin_proc = new thread_index_t[num_bins];
for (bin_index b = 0; b < num_bins + 1; b++)
sd.dist[b] = new difference_type[num_threads + 1];
for (bin_index b = 0; b < (num_bins + 1); b++)
{
sd.dist[0][0] = 0;
sd.dist[b][0] = 0;
}
difference_type* starts = sd.starts = new difference_type[num_threads + 1];
int bin_cursor = 0;
sd.num_bins = num_bins;
sd.num_bits = log2(num_bins);
difference_type chunk_length = n / num_threads, split = n % num_threads, start = 0;
int bin_chunk_length = num_bins / num_threads, bin_split = num_bins % num_threads;
for (int i = 0; i < num_threads; i++)
{
starts[i] = start;
start += (i < split) ? (chunk_length + 1) : chunk_length;
int j = pus[i].bins_begin = bin_cursor;
// Range of bins for this processor.
bin_cursor += (i < bin_split) ? (bin_chunk_length + 1) : bin_chunk_length;
pus[i].bins_end = bin_cursor;
for (; j < bin_cursor; j++)
sd.bin_proc[j] = i;
pus[i].num_threads = num_threads;
pus[i].iam = i;
pus[i].seed = rng(std::numeric_limits<uint32>::max());
pus[i].sd = &sd;
}
starts[num_threads] = start;
// Now shuffle in parallel.
#pragma omp parallel num_threads(num_threads)
parallel_random_shuffle_drs_pu(pus);
delete[] starts;
delete[] sd.bin_proc;
for (int s = 0; s < (num_bins + 1); s++)
delete[] sd.dist[s];
delete[] sd.dist;
delete[] sd.temporaries;
delete[] pus;
}
/** @brief Sequential cache-efficient random shuffle.
* @param begin Begin iterator of sequence.
* @param end End iterator of sequence.
* @param rng Random number generator to use.
*/
template<typename RandomAccessIterator, typename RandomNumberGenerator>
inline void
sequential_random_shuffle(RandomAccessIterator begin, RandomAccessIterator end, RandomNumberGenerator& rng)
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
difference_type n = end - begin;
bin_index num_bins, num_bins_cache;
#if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_L1
// Try the L1 cache first, must fit into L1.
num_bins_cache = std::max((difference_type)1, (difference_type)(n / (Settings::L1_cache_size_lb / sizeof(value_type))));
num_bins_cache = round_up_to_pow2(num_bins_cache);
// No more buckets than TLB entries, power of 2
// Power of 2 and at least one element per bin, at most the TLB size
num_bins = std::min(n, (difference_type)num_bins_cache);
#if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_TLB
// 2 TLB entries needed per bin
num_bins = std::min((difference_type)Settings::TLB_size / 2, num_bins);
#endif
num_bins = round_up_to_pow2(num_bins);
if (num_bins < num_bins_cache)
{
#endif
// Now try the L2 cache, must fit into L2.
num_bins_cache = static_cast<bin_index>(std::max((difference_type)1, (difference_type)(n / (Settings::L2_cache_size / sizeof(value_type)))));
num_bins_cache = round_up_to_pow2(num_bins_cache);
// No more buckets than TLB entries, power of 2
// Power of 2 and at least one element per bin, at most the TLB size.
num_bins = static_cast<bin_index>(std::min(n, (difference_type)num_bins_cache));
#if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_TLB
// 2 TLB entries needed per bin
num_bins = std::min((difference_type)Settings::TLB_size / 2, num_bins);
#endif
num_bins = round_up_to_pow2(num_bins);
#if _GLIBCXX_RANDOM_SHUFFLE_CONSIDER_L1
}
#endif
int num_bits = log2(num_bins);
if (num_bins > 1)
{
value_type* target = new value_type[n];
bin_index* oracles = new bin_index[n];
difference_type* dist0 = new difference_type[num_bins + 1], * dist1 = new difference_type[num_bins + 1];
for (int b = 0; b < num_bins + 1; b++)
dist0[b] = 0;
Timing<sequential_tag> t;
t.tic();
random_number bitrng(rng(0xFFFFFFFF));
for (difference_type i = 0; i < n; i++)
{
bin_index oracle = random_number_pow2(num_bits, bitrng);
oracles[i] = oracle;
// To allow prefix (partial) sum.
dist0[oracle + 1]++;
}
t.tic();
// Sum up bins.
partial_sum(dist0, dist0 + num_bins + 1, dist0);
for (int b = 0; b < num_bins + 1; b++)
dist1[b] = dist0[b];
t.tic();
// Distribute according to oracles.
for (difference_type i = 0; i < n; i++)
target[(dist0[oracles[i]])++] = *(begin + i);
for (int b = 0; b < num_bins; b++)
{
sequential_random_shuffle(target + dist1[b], target + dist1[b + 1],
rng);
t.tic();
}
t.print();
delete[] dist0;
delete[] dist1;
delete[] oracles;
delete[] target;
}
else
__gnu_sequential::random_shuffle(begin, end, rng);
}
/** @brief Parallel random public call.
* @param begin Begin iterator of sequence.
* @param end End iterator of sequence.
* @param rng Random number generator to use.
*/
template<typename RandomAccessIterator, typename RandomNumberGenerator>
inline void
parallel_random_shuffle(RandomAccessIterator begin, RandomAccessIterator end, RandomNumberGenerator rng = random_number())
{
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::difference_type difference_type;
difference_type n = end - begin;
parallel_random_shuffle_drs(begin, end, n, get_max_threads(), rng) ;
}
}
#endif

View File

@ -0,0 +1,157 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/search.h
* @brief Parallel implementation base for std::search() and
* std::search_n().
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze.
#ifndef _GLIBCXX_PARALLEL_SEARCH_H
#define _GLIBCXX_PARALLEL_SEARCH_H 1
#include <bits/stl_algobase.h>
#include <parallel/parallel.h>
#include <parallel/equally_split.h>
namespace __gnu_parallel
{
/**
* @brief Precalculate advances for Knuth-Morris-Pratt algorithm.
* @param elements Begin iterator of sequence to search for.
* @param length Length of sequence to search for.
* @param advances Returned offsets.
*/
template<typename RandomAccessIterator, typename _DifferenceTp>
void
calc_borders(RandomAccessIterator elements, _DifferenceTp length, _DifferenceTp* off)
{
typedef _DifferenceTp difference_type;
off[0] = -1;
if (length > 1)
off[1] = 0;
difference_type k = 0;
for (difference_type j = 2; j <= length; j++)
{
while ((k >= 0) && (elements[k] != elements[j-1]))
k = off[k];
off[j] = ++k;
}
}
// Generic parallel find algorithm (requires random access iterator).
/** @brief Parallel std::search.
* @param begin1 Begin iterator of first sequence.
* @param end1 End iterator of first sequence.
* @param begin2 Begin iterator of second sequence.
* @param end2 End iterator of second sequence.
* @param pred Find predicate.
* @return Place of finding in first sequences. */
template<typename _RandomAccessIterator1, typename _RandomAccessIterator2, typename Pred>
_RandomAccessIterator1
search_template(_RandomAccessIterator1 begin1, _RandomAccessIterator1 end1,
_RandomAccessIterator2 begin2, _RandomAccessIterator2 end2,
Pred pred)
{
typedef std::iterator_traits<_RandomAccessIterator1> traits_type;
typedef typename traits_type::difference_type difference_type;
_GLIBCXX_CALL((end1 - begin1) + (end2 - begin2));
difference_type pattern_length = end2 - begin2;
// Pattern too short.
if(pattern_length <= 0)
return end1;
// Last point to start search.
difference_type input_length = (end1 - begin1) - pattern_length;
// Where is first occurence of pattern? defaults to end.
difference_type res = (end1 - begin1);
// Pattern too long.
if (input_length < 0)
return end1;
thread_index_t num_threads = std::max<difference_type>(1, std::min<difference_type>(input_length, __gnu_parallel::get_max_threads()));
difference_type borders[num_threads + 1];
__gnu_parallel::equally_split(input_length, num_threads, borders);
difference_type advances[pattern_length];
calc_borders(begin2, pattern_length, advances);
#pragma omp parallel num_threads(num_threads)
{
thread_index_t iam = omp_get_thread_num();
difference_type start = borders[iam], stop = borders[iam + 1];
difference_type pos_in_pattern = 0;
bool found_pattern = false;
while (start <= stop && !found_pattern)
{
// Get new value of res.
#pragma omp flush(res)
// No chance for this thread to find first occurence.
if (res < start)
break;
while (pred(begin1[start + pos_in_pattern], begin2[pos_in_pattern]))
{
++pos_in_pattern;
if (pos_in_pattern == pattern_length)
{
// Found new candidate for res.
#pragma omp critical (res)
res = std::min(res, start);
found_pattern = true;
break;
}
}
// Make safe jump.
start += (pos_in_pattern - advances[pos_in_pattern]);
pos_in_pattern = (advances[pos_in_pattern] < 0) ? 0 : advances[pos_in_pattern];
}
}
// Return iterator on found element.
return (begin1 + res);
}
} // end namespace
#endif

View File

@ -0,0 +1,529 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/**
* @file parallel/set_operations.h
* @brief Parallel implementations of set operations for random-access
* iterators.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Marius Elvert and Felix Bondarenko.
#ifndef _GLIBCXX_PARALLEL_SET_OPERATIONS_H
#define _GLIBCXX_PARALLEL_SET_OPERATIONS_H 1
#include <omp.h>
#include <parallel/settings.h>
#include <parallel/multiseq_selection.h>
namespace __gnu_parallel
{
template<typename InputIterator, typename OutputIterator>
inline OutputIterator
copy_tail(std::pair<InputIterator, InputIterator> b,
std::pair<InputIterator, InputIterator> e, OutputIterator r)
{
if (b.first != e.first)
{
do
{
*r++ = *b.first++;
}
while (b.first != e.first);
}
else
{
while (b.second != e.second)
*r++ = *b.second++;
}
return r;
}
template<typename InputIterator, typename OutputIterator, typename Comparator>
struct symmetric_difference_func
{
typedef std::iterator_traits<InputIterator> traits_type;
typedef typename traits_type::difference_type difference_type;
typedef typename std::pair<InputIterator, InputIterator> iterator_pair;
symmetric_difference_func(Comparator c) : comp(c) {}
Comparator comp;
inline OutputIterator invoke(InputIterator a, InputIterator b,
InputIterator c, InputIterator d,
OutputIterator r) const
{
while (a != b && c != d)
{
if (comp(*a, *c))
{
*r = *a;
++a;
++r;
}
else if (comp(*c, *a))
{
*r = *c;
++c;
++r;
}
else
{
++a;
++c;
}
}
return std::copy(c, d, std::copy(a, b, r));
}
inline difference_type
count(InputIterator a, InputIterator b, InputIterator c, InputIterator d) const
{
difference_type counter = 0;
while (a != b && c != d)
{
if (comp(*a, *c))
{
++a;
++counter;
}
else if (comp(*c, *a))
{
++c;
++counter;
}
else
{
++a;
++c;
}
}
return counter + (b - a) + (d - c);
}
inline OutputIterator
first_empty(InputIterator c, InputIterator d, OutputIterator out) const
{ return std::copy(c, d, out); }
inline OutputIterator
second_empty(InputIterator a, InputIterator b, OutputIterator out) const
{ return std::copy(a, b, out); }
};
template<typename InputIterator, typename OutputIterator, typename Comparator>
struct difference_func
{
typedef std::iterator_traits<InputIterator> traits_type;
typedef typename traits_type::difference_type difference_type;
typedef typename std::pair<InputIterator, InputIterator> iterator_pair;
difference_func(Comparator c) : comp(c) {}
Comparator comp;
inline OutputIterator
invoke(InputIterator a, InputIterator b, InputIterator c, InputIterator d,
OutputIterator r) const
{
while (a != b && c != d)
{
if (comp(*a, *c))
{
*r = *a;
++a;
++r;
}
else if (comp(*c, *a))
{ ++c; }
else
{
++a;
++c;
}
}
return std::copy(a, b, r);
}
inline difference_type
count(InputIterator a, InputIterator b, InputIterator c, InputIterator d) const
{
difference_type counter = 0;
while (a != b && c != d)
{
if (comp(*a, *c))
{
++a;
++counter;
}
else if (comp(*c, *a))
{ ++c; }
else
{ ++a; ++c; }
}
return counter + (b - a);
}
inline OutputIterator
first_empty(InputIterator c, InputIterator d, OutputIterator out) const
{ return out; }
inline OutputIterator
second_empty(InputIterator a, InputIterator b, OutputIterator out) const
{ return std::copy(a, b, out); }
};
template<typename InputIterator, typename OutputIterator, typename Comparator>
struct intersection_func
{
typedef std::iterator_traits<InputIterator> traits_type;
typedef typename traits_type::difference_type difference_type;
typedef typename std::pair<InputIterator, InputIterator> iterator_pair;
intersection_func(Comparator c) : comp(c) {}
Comparator comp;
inline OutputIterator
invoke(InputIterator a, InputIterator b, InputIterator c, InputIterator d,
OutputIterator r) const
{
while (a != b && c != d)
{
if (comp(*a, *c))
{ ++a; }
else if (comp(*c, *a))
{ ++c; }
else
{
*r = *a;
++a;
++c;
++r;
}
}
return r;
}
inline difference_type
count(InputIterator a, InputIterator b, InputIterator c, InputIterator d) const
{
difference_type counter = 0;
while (a != b && c != d)
{
if (comp(*a, *c))
{ ++a; }
else if (comp(*c, *a))
{ ++c; }
else
{
++a;
++c;
++counter;
}
}
return counter;
}
inline OutputIterator
first_empty(InputIterator c, InputIterator d, OutputIterator out) const
{ return out; }
inline OutputIterator
second_empty(InputIterator a, InputIterator b, OutputIterator out) const
{ return out; }
};
template<class InputIterator, class OutputIterator, class Comparator>
struct union_func
{
typedef typename std::iterator_traits<InputIterator>::difference_type difference_type;
union_func(Comparator c) : comp(c) {}
Comparator comp;
inline OutputIterator
invoke(InputIterator a, const InputIterator b, InputIterator c,
const InputIterator d, OutputIterator r) const
{
while (a != b && c != d)
{
if (comp(*a, *c))
{
*r = *a;
++a;
}
else if (comp(*c, *a))
{
*r = *c;
++c;
}
else
{
*r = *a;
++a;
++c;
}
++r;
}
return std::copy(c, d, std::copy(a, b, r));
}
inline difference_type
count(InputIterator a, const InputIterator b, InputIterator c,
const InputIterator d) const
{
difference_type counter = 0;
while (a != b && c != d)
{
if (comp(*a, *c))
{ ++a; }
else if (comp(*c, *a))
{ ++c; }
else
{
++a;
++c;
}
++counter;
}
counter += (b - a);
counter += (d - c);
return counter;
}
inline OutputIterator
first_empty(InputIterator c, InputIterator d, OutputIterator out) const
{ return std::copy(c, d, out); }
inline OutputIterator
second_empty(InputIterator a, InputIterator b, OutputIterator out) const
{ return std::copy(a, b, out); }
};
template<typename InputIterator, typename OutputIterator, typename Operation>
OutputIterator
parallel_set_operation(InputIterator begin1, InputIterator end1,
InputIterator begin2, InputIterator end2,
OutputIterator result, Operation op)
{
_GLIBCXX_CALL((end1 - begin1) + (end2 - begin2))
typedef std::iterator_traits<InputIterator> traits_type;
typedef typename traits_type::difference_type difference_type;
typedef typename std::pair<InputIterator, InputIterator> iterator_pair;
if (begin1 == end1)
return op.first_empty(begin2, end2, result);
if (begin2 == end2)
return op.second_empty(begin1, end1, result);
const difference_type size = (end1 - begin1) + (end2 - begin2);
thread_index_t num_threads = std::min<difference_type>(std::min(end1 - begin1, end2 - begin2), get_max_threads());
difference_type borders[num_threads + 2];
equally_split(size, num_threads + 1, borders);
const iterator_pair sequence[ 2 ] = { std::make_pair(begin1, end1), std::make_pair(begin2, end2) } ;
iterator_pair block_begins[num_threads + 1];
// Very start.
block_begins[0] = std::make_pair(begin1, begin2);
difference_type length[num_threads];
OutputIterator return_value = result;
#pragma omp parallel num_threads(num_threads)
{
Timing<sequential_tag> t;
t.tic();
// Result from multiseq_partition.
InputIterator offset[2];
const int iam = omp_get_thread_num();
const difference_type rank = borders[iam + 1];
multiseq_partition(sequence, sequence + 2, rank, offset, op.comp);
// allowed to read?
// together
// *(offset[ 0 ] - 1) == *offset[ 1 ]
if (offset[ 0 ] != begin1 && offset[ 1 ] != end2
&& !op.comp(*(offset[ 0 ] - 1), *offset[ 1 ])
&& !op.comp(*offset[ 1 ], *(offset[ 0 ] - 1)))
{
// Avoid split between globally equal elements: move one to
// front in first sequence.
--offset[ 0 ];
}
iterator_pair block_end = block_begins[ iam + 1 ] = iterator_pair(offset[ 0 ], offset[ 1 ]);
t.tic();
// Make sure all threads have their block_begin result written out.
#pragma omp barrier
t.tic();
iterator_pair block_begin = block_begins[ iam ];
// Begin working for the first block, while the others except
// the last start to count.
if (iam == 0)
{
// The first thread can copy already.
length[ iam ] = op.invoke(block_begin.first, block_end.first, block_begin.second, block_end.second, result) - result;
}
else
{
length[ iam ] = op.count(block_begin.first, block_end.first,
block_begin.second, block_end.second);
}
t.tic();
// Make sure everyone wrote their lengths.
#pragma omp barrier
t.tic();
OutputIterator r = result;
if (iam == 0)
{
// Do the last block.
for (int i = 0; i < num_threads; ++i)
r += length[i];
block_begin = block_begins[num_threads];
// Return the result iterator of the last block.
return_value = op.invoke(block_begin.first, end1, block_begin.second, end2, r);
}
else
{
for (int i = 0; i < iam; ++i)
r += length[ i ];
// Reset begins for copy pass.
op.invoke(block_begin.first, block_end.first,
block_begin.second, block_end.second, r);
}
t.tic();
t.print();
}
return return_value;
}
template<typename InputIterator, typename OutputIterator, typename Comparator>
OutputIterator
parallel_set_union(InputIterator begin1, InputIterator end1,
InputIterator begin2, InputIterator end2,
OutputIterator result, Comparator comp)
{
return parallel_set_operation(begin1, end1, begin2, end2, result,
union_func< InputIterator, OutputIterator, Comparator>(comp));
}
template<typename InputIterator, typename OutputIterator, typename Comparator>
OutputIterator
parallel_set_intersection(InputIterator begin1, InputIterator end1,
InputIterator begin2, InputIterator end2,
OutputIterator result, Comparator comp)
{
return parallel_set_operation(begin1, end1, begin2, end2, result,
intersection_func<InputIterator, OutputIterator, Comparator>(comp));
}
template<typename InputIterator, typename OutputIterator>
OutputIterator
set_intersection(InputIterator begin1, InputIterator end1, InputIterator begin2, InputIterator end2, OutputIterator result)
{
typedef std::iterator_traits<InputIterator> traits_type;
typedef typename traits_type::value_type value_type;
return set_intersection(begin1, end1, begin2, end2, result,
std::less<value_type>());
}
template<typename InputIterator, typename OutputIterator, typename Comparator>
OutputIterator
parallel_set_difference(InputIterator begin1, InputIterator end1,
InputIterator begin2, InputIterator end2,
OutputIterator result, Comparator comp)
{
return parallel_set_operation(begin1, end1, begin2, end2, result,
difference_func<InputIterator, OutputIterator, Comparator>(comp));
}
template<typename InputIterator, typename OutputIterator, typename Comparator>
OutputIterator
parallel_set_symmetric_difference(InputIterator begin1, InputIterator end1, InputIterator begin2, InputIterator end2, OutputIterator result, Comparator comp)
{
return parallel_set_operation(begin1, end1, begin2, end2, result,
symmetric_difference_func<InputIterator, OutputIterator, Comparator>(comp));
}
}
#endif // _GLIBCXX_SET_ALGORITHM_

View File

@ -0,0 +1,388 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/settings.h
* @brief Settings and tuning parameters, heuristics to decide
* whether to use parallelized algorithms.
* This file is a GNU parallel extension to the Standard C++ Library.
*
* @section parallelization_decision The decision whether to run an algorithm in parallel.
*
* There are several ways the user can switch on and off the
* parallel execution of an algorithm, both at compile- and
* run-time.
*
* Only sequential execution can be forced at compile-time.
* This reduces code size and protects code parts that have
* non-thread-safe side effects.
*
* Ultimately forcing parallel execution at compile-time does
* make much sense.
* Often, the sequential algorithm implementation is used as
* a subroutine, so no reduction in code size can be achieved.
* Also, the machine the program is run on might have only one
* processor core, so to avoid overhead, the algorithm is
* executed sequentially.
*
* To force sequential execution of an algorithm ultimately
* at compile-time, the user must add the tag
* __gnu_parallel::sequential_tag() to the end of the
* parameter list, e. g.
*
* \code
* std::sort(v.begin(), v.end(), __gnu_parallel::sequential_tag());
* \endcode
*
* This is compatible with all overloaded algorithm variants.
* No additional code will be instantiated, at all.
* The same holds for most algorithm calls with iterators
* not providing random access.
*
* If the algorithm call is not forced to be executed sequentially
* at compile-time, the decision is made at run-time, for each call.
* First, the two (conceptually) global variables
* __gnu_parallel::Settings::force_sequential and
* __gnu_parallel::Settings::force_parallel are executed.
* If the former one is true, the sequential algorithm is executed.
* If the latter one is true and the former one is false,
* the algorithm is executed in parallel.
*
* If none of these conditions has fired so far, a heuristic is used.
* The parallel algorithm implementation is called only if the
* input size is sufficiently large.
* For most algorithms, the input size is the (combined) length of
* the input sequence(s).
* The threshold can be set by the user, individually for each
* algorithm.
* The according variables are called
* __gnu_parallel::Settings::[algorithm]_minimal_n .
*
* For some of the algorithms, there are even more tuning options,
* e. g. the ability to choose from multiple algorithm variants.
* See the __gnu_parallel::Settings class for details.
*/
// Written by Johannes Singler and Felix Putze.
#ifndef _GLIBCXX_PARALLEL_SETTINGS_H
#define _GLIBCXX_PARALLEL_SETTINGS_H 1
#include <omp.h>
#include <parallel/types.h>
/**
* @brief The extensible condition on whether the parallel variant of
* an algorithm sould be called.
* @param c A condition that is overruled by
* __gnu_parallel::Settings::force_parallel, i. e. usually a decision based on
* the input size.
*/
#define _GLIBCXX_PARALLEL_CONDITION(c) (!(__gnu_parallel::Settings::force_sequential) && ((__gnu_parallel::get_max_threads() > 1 && (c)) || __gnu_parallel::Settings::force_parallel))
namespace __gnu_parallel
{
// NB: Including this file cannot produce (unresolved) symbols from
// the OpenMP runtime unless the parallel mode is actually invoked
// and active, which imples that the OpenMP runtime is actually
// going to be linked in.
inline int
get_max_threads()
{ return omp_get_max_threads() > 1 ? omp_get_max_threads() : 1; }
namespace
{
// XXX look at _Tune in mt_allocator.h
/** @brief Run-time settings for the parallel mode. */
struct Settings
{
/** @brief Different parallel sorting algorithms to choose
from: multi-way mergesort, quicksort, load-balanced
quicksort. */
enum SortAlgorithm
{ MWMS, QS, QS_BALANCED };
/** @brief Different merging algorithms: bubblesort-alike,
loser-tree variants, enum sentinel */
enum MultiwayMergeAlgorithm
{ BUBBLE, LOSER_TREE_EXPLICIT, LOSER_TREE, LOSER_TREE_COMBINED, LOSER_TREE_SENTINEL, MWM_ALGORITHM_LAST };
/** @brief Different splitting strategies for sorting/merging:
by sampling, exact */
enum Splitting
{ SAMPLING, EXACT };
/** @brief Different partial sum algorithms: recursive, linear */
enum PartialSumAlgorithm
{ RECURSIVE, LINEAR };
/** @brief Different find distribution strategies: growing
blocks, equal-sized blocks, equal splitting. */
enum FindDistribution
{ GROWING_BLOCKS, CONSTANT_SIZE_BLOCKS, EQUAL_SPLIT };
/** @brief Force all algorithms to be executed sequentially.
* This setting cannot be overwritten. */
static volatile bool force_sequential;
/** @brief Force all algorithms to be executed in parallel.
* This setting can be overriden by __gnu_parallel::sequential_tag
* (compile-time), and force_sequential (run-time). */
static volatile bool force_parallel;
/** @brief Algorithm to use for sorting. */
static volatile SortAlgorithm sort_algorithm;
/** @brief Strategy to use for splitting the input when
sorting (MWMS). */
static volatile Splitting sort_splitting;
/** @brief Minimal input size for parallel sorting. */
static volatile sequence_index_t sort_minimal_n;
/** @brief Oversampling factor for parallel std::sort (MWMS). */
static volatile unsigned int sort_mwms_oversampling;
/** @brief Such many samples to take to find a good pivot
(quicksort). */
static volatile unsigned int sort_qs_num_samples_preset;
/** @brief Maximal subsequence length to swtich to unbalanced
* base case. Applies to std::sort with dynamically
* load-balanced quicksort. */
static volatile sequence_index_t sort_qsb_base_case_maximal_n;
/** @brief Minimal input size for parallel std::partition. */
static volatile sequence_index_t partition_minimal_n;
/** @brief Chunk size for parallel std::partition. */
static volatile sequence_index_t partition_chunk_size;
/** @brief Chunk size for parallel std::partition, relative to
* input size. If >0.0, this value overrides
* partition_chunk_size. */
static volatile double partition_chunk_share;
/** @brief Minimal input size for parallel std::nth_element. */
static volatile sequence_index_t nth_element_minimal_n;
/** @brief Minimal input size for parallel std::partial_sort. */
static volatile sequence_index_t partial_sort_minimal_n;
/** @brief Minimal input size for parallel std::adjacent_difference. */
static volatile unsigned int adjacent_difference_minimal_n;
/** @brief Minimal input size for parallel std::partial_sum. */
static volatile unsigned int partial_sum_minimal_n;
/** @brief Algorithm to use for std::partial_sum. */
static volatile PartialSumAlgorithm partial_sum_algorithm;
/** @brief Assume "sum and write result" to be that factor
* slower than just "sum". This value is used for
* std::partial_sum. */
static volatile float partial_sum_dilatation;
/** @brief Minimal input size for parallel std::random_shuffle. */
static volatile unsigned int random_shuffle_minimal_n;
/** @brief Minimal input size for parallel std::merge. */
static volatile sequence_index_t merge_minimal_n;
/** @brief Splitting strategy for parallel std::merge. */
static volatile Splitting merge_splitting;
/** @brief Oversampling factor for parallel std::merge.
* Such many samples per thread are collected. */
static volatile unsigned int merge_oversampling;
/** @brief Algorithm to use for parallel
__gnu_parallel::multiway_merge. */
static volatile MultiwayMergeAlgorithm multiway_merge_algorithm;
/** @brief Splitting strategy to use for parallel
__gnu_parallel::multiway_merge. */
static volatile Splitting multiway_merge_splitting;
//// Oversampling factor for parallel __gnu_parallel::multiway_merge.
static volatile unsigned int multiway_merge_oversampling;
/// Minimal input size for parallel __gnu_parallel::multiway_merge.
static volatile sequence_index_t multiway_merge_minimal_n;
/// Oversampling factor for parallel __gnu_parallel::multiway_merge.
static volatile int multiway_merge_minimal_k;
/** @brief Minimal input size for parallel std::unique_copy. */
static volatile sequence_index_t unique_copy_minimal_n;
static volatile sequence_index_t workstealing_chunk_size;
/** @brief Minimal input size for parallel std::for_each. */
static volatile sequence_index_t for_each_minimal_n;
/** @brief Minimal input size for parallel std::count and
std::count_if. */
static volatile sequence_index_t count_minimal_n;
/** @brief Minimal input size for parallel std::transform. */
static volatile sequence_index_t transform_minimal_n;
/** @brief Minimal input size for parallel std::replace and
std::replace_if. */
static volatile sequence_index_t replace_minimal_n;
/** @brief Minimal input size for parallel std::generate. */
static volatile sequence_index_t generate_minimal_n;
/** @brief Minimal input size for parallel std::fill. */
static volatile sequence_index_t fill_minimal_n;
/** @brief Minimal input size for parallel std::min_element. */
static volatile sequence_index_t min_element_minimal_n;
/** @brief Minimal input size for parallel std::max_element. */
static volatile sequence_index_t max_element_minimal_n;
/** @brief Minimal input size for parallel std::accumulate. */
static volatile sequence_index_t accumulate_minimal_n;
/** @brief Distribution strategy for parallel std::find. */
static volatile FindDistribution find_distribution;
/** @brief Start with looking for that many elements
sequentially, for std::find. */
static volatile sequence_index_t find_sequential_search_size;
/** @brief Initial block size for parallel std::find. */
static volatile sequence_index_t find_initial_block_size;
/** @brief Maximal block size for parallel std::find. */
static volatile sequence_index_t find_maximum_block_size;
/** @brief Block size increase factor for parallel std::find. */
static volatile double find_increasing_factor;
//set operations
/** @brief Minimal input size for parallel std::set_union. */
static volatile sequence_index_t set_union_minimal_n;
/** @brief Minimal input size for parallel
std::set_symmetric_difference. */
static volatile sequence_index_t set_symmetric_difference_minimal_n;
/** @brief Minimal input size for parallel std::set_difference. */
static volatile sequence_index_t set_difference_minimal_n;
/** @brief Minimal input size for parallel std::set_intersection. */
static volatile sequence_index_t set_intersection_minimal_n;
//hardware dependent tuning parameters
/** @brief Size of the L1 cache in bytes (underestimation). */
static volatile unsigned long long L1_cache_size;
/** @brief Size of the L2 cache in bytes (underestimation). */
static volatile unsigned long long L2_cache_size;
/** @brief Size of the Translation Lookaside Buffer
(underestimation). */
static volatile unsigned int TLB_size;
/** @brief Overestimation of cache line size. Used to avoid
* false sharing, i. e. elements of different threads are at
* least this amount apart. */
static unsigned int cache_line_size;
//statistics
/** @brief Statistic on the number of stolen ranges in
load-balanced quicksort.*/
static volatile sequence_index_t qsb_steals;
};
volatile bool Settings::force_parallel = false;
volatile bool Settings::force_sequential = false;
volatile Settings::SortAlgorithm Settings::sort_algorithm = Settings::MWMS;
volatile Settings::Splitting Settings::sort_splitting = Settings::EXACT;
volatile sequence_index_t Settings::sort_minimal_n = 1000;
volatile unsigned int Settings::sort_mwms_oversampling = 10;
volatile unsigned int Settings::sort_qs_num_samples_preset = 100;
volatile sequence_index_t Settings::sort_qsb_base_case_maximal_n = 100;
volatile sequence_index_t Settings::partition_minimal_n = 1000;
volatile sequence_index_t Settings::nth_element_minimal_n = 1000;
volatile sequence_index_t Settings::partial_sort_minimal_n = 1000;
volatile sequence_index_t Settings::partition_chunk_size = 1000;
volatile double Settings::partition_chunk_share = 0.0;
volatile unsigned int Settings::adjacent_difference_minimal_n = 1000;
volatile Settings::PartialSumAlgorithm Settings::partial_sum_algorithm = Settings::LINEAR;
volatile unsigned int Settings::partial_sum_minimal_n = 1000;
volatile float Settings::partial_sum_dilatation = 1.0f;
volatile unsigned int Settings::random_shuffle_minimal_n = 1000;
volatile Settings::Splitting Settings::merge_splitting = Settings::EXACT;
volatile sequence_index_t Settings::merge_minimal_n = 1000;
volatile unsigned int Settings::merge_oversampling = 10;
volatile sequence_index_t Settings::multiway_merge_minimal_n = 1000;
volatile int Settings::multiway_merge_minimal_k = 2;
// unique copy
volatile sequence_index_t Settings::unique_copy_minimal_n = 10000;
volatile Settings::MultiwayMergeAlgorithm Settings::multiway_merge_algorithm = Settings::LOSER_TREE;
volatile Settings::Splitting Settings::multiway_merge_splitting = Settings::EXACT;
volatile unsigned int Settings::multiway_merge_oversampling = 10;
volatile Settings::FindDistribution Settings::find_distribution = Settings::CONSTANT_SIZE_BLOCKS;
volatile sequence_index_t Settings::find_sequential_search_size = 256;
volatile sequence_index_t Settings::find_initial_block_size = 256;
volatile sequence_index_t Settings::find_maximum_block_size = 8192;
volatile double Settings::find_increasing_factor = 2.0;
volatile sequence_index_t Settings::workstealing_chunk_size = 100;
volatile sequence_index_t Settings::for_each_minimal_n = 1000;
volatile sequence_index_t Settings::count_minimal_n = 1000;
volatile sequence_index_t Settings::transform_minimal_n = 1000;
volatile sequence_index_t Settings::replace_minimal_n = 1000;
volatile sequence_index_t Settings::generate_minimal_n = 1000;
volatile sequence_index_t Settings::fill_minimal_n = 1000;
volatile sequence_index_t Settings::min_element_minimal_n = 1000;
volatile sequence_index_t Settings::max_element_minimal_n = 1000;
volatile sequence_index_t Settings::accumulate_minimal_n = 1000;
//set operations
volatile sequence_index_t Settings::set_union_minimal_n = 1000;
volatile sequence_index_t Settings::set_intersection_minimal_n = 1000;
volatile sequence_index_t Settings::set_difference_minimal_n = 1000;
volatile sequence_index_t Settings::set_symmetric_difference_minimal_n = 1000;
volatile unsigned long long Settings::L1_cache_size = 16 << 10;
volatile unsigned long long Settings::L2_cache_size = 256 << 10;
volatile unsigned int Settings::TLB_size = 128;
unsigned int Settings::cache_line_size = 64;
//statistics
volatile sequence_index_t Settings::qsb_steals = 0;
} // end anonymous namespace
}
#endif /* _GLIBCXX_SETTINGS_H */

View File

@ -0,0 +1,104 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/sort.h
* @brief Parallel sorting algorithm switch.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_SORT_H
#define _GLIBCXX_PARALLEL_SORT_H 1
#include <parallel/basic_iterator.h>
#include <parallel/features.h>
#include <parallel/parallel.h>
#if _GLIBCXX_ASSERTIONS
#include <parallel/checkers.h>
#endif
#if _GLIBCXX_MERGESORT
#include <parallel/multiway_mergesort.h>
#endif
#if _GLIBCXX_QUICKSORT
#include <parallel/quicksort.h>
#endif
#if _GLIBCXX_BAL_QUICKSORT
#include <parallel/balanced_quicksort.h>
#endif
namespace __gnu_parallel
{
/**
* @brief Choose a parallel sorting algorithm.
* @param begin Begin iterator of input sequence.
* @param end End iterator of input sequence.
* @param comp Comparator.
* @param stable Sort stable.
* @callgraph
*/
template<typename RandomAccessIterator, typename Comparator>
inline void
parallel_sort(RandomAccessIterator begin, RandomAccessIterator end,
Comparator comp, bool stable)
{
_GLIBCXX_CALL(end - begin)
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
if (begin != end)
{
difference_type n = end - begin;
if (false) ;
#if _GLIBCXX_MERGESORT
else if (Settings::sort_algorithm == Settings::MWMS || stable)
parallel_sort_mwms(begin, end, comp, n, get_max_threads(), stable);
#endif
#if _GLIBCXX_QUICKSORT
else if (Settings::sort_algorithm == Settings::QS && !stable)
parallel_sort_qs(begin, end, comp, n, get_max_threads());
#endif
#if _GLIBCXX_BAL_QUICKSORT
else if (Settings::sort_algorithm == Settings::QS_BALANCED && !stable)
parallel_sort_qsb(begin, end, comp, n, get_max_threads());
#endif
else
__gnu_sequential::sort(begin, end, comp);
}
}
} // end namespace __gnu_parallel
#endif

View File

@ -0,0 +1,124 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/**
* @file parallel/tags.h
* @brief Tags for compile-time options.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler and Felix Putze.
#ifndef _GLIBCXX_PARALLEL_TAGS_H
#define _GLIBCXX_PARALLEL_TAGS_H 1
// Parallel mode namespaces.
namespace std
{
namespace __parallel { }
}
/**
* @namespace __gnu_sequential
* @brief GNU sequential classes for public use.
*/
namespace __gnu_sequential { }
/**
* @namespace __gnu_parallel
* @brief GNU parallel classes for public use.
*/
namespace __gnu_parallel
{
// Import all the parallel versions of components in namespace std.
using namespace std::__parallel;
enum parallelism
{
/// Not parallel.
sequential,
/// Parallel unbalanced (equal-sized chunks).
parallel_unbalanced,
/// Parallel balanced (work-stealing).
parallel_balanced,
/// Parallel with OpenMP dynamic load-balancing.
parallel_omp_loop,
/// Parallel with OpenMP static load-balancing.
parallel_omp_loop_static,
/// Parallel with OpenMP taskqueue construct.
parallel_taskqueue
};
inline bool
is_parallel(const parallelism __p) { return __p != sequential; }
/** @brief Forces sequential execution at compile time. */
struct sequential_tag { };
/** @brief Recommends parallel execution at compile time. */
struct parallel_tag { };
/** @brief Recommends parallel execution using dynamic
load-balancing at compile time. */
struct balanced_tag : public parallel_tag { };
/** @brief Recommends parallel execution using static
load-balancing at compile time. */
struct unbalanced_tag : public parallel_tag { };
/** @brief Recommends parallel execution using OpenMP dynamic
load-balancing at compile time. */
struct omp_loop_tag : public parallel_tag { };
/** @brief Recommends parallel execution using OpenMP static
load-balancing at compile time. */
struct omp_loop_static_tag : public parallel_tag { };
/** @brief Selects the growing block size variant for std::find().
@see _GLIBCXX_FIND_GROWING_BLOCKS */
struct growing_blocks_tag { };
/** @brief Selects the constant block size variant for std::find().
@see _GLIBCXX_FIND_CONSTANT_SIZE_BLOCKS */
struct constant_size_blocks_tag { };
/** @brief Selects the equal splitting variant for std::find().
@see _GLIBCXX_FIND_EQUAL_SPLIT */
struct equal_split_tag { };
}
#endif /* _GLIBCXX_TAGS_H */

View File

@ -0,0 +1,217 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/timing.h
* @brief Provides a simple tool to do performance debugging, also in
* parallel code.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_TIMING_H
#define _GLIBCXX_PARALLEL_TIMING_H 1
#include <omp.h>
#include <cstdio>
#include <cstring>
#include <parallel/tags.h>
namespace __gnu_parallel
{
// XXX integrate with existing performance testing infrastructure.
/** @brief Type of of point in time, used for the Timing classes. */
typedef double point_in_time;
template<typename tag, typename must_be_int = int>
class Timing;
/** @brief A class that provides simple run time measurements, also
for parallel code.
* @param tag If parallel_tag, then the measurements are actually done.
* Otherwise, no code at all is emitted by the compiler. */
template<typename must_be_int>
class Timing<parallel_tag, must_be_int>
{
private:
static const int max_points_in_time = 100;
point_in_time points_in_time[max_points_in_time];
point_in_time active, last_start;
int pos;
char* str;
const char* tags[max_points_in_time];
public:
Timing()
{
str = NULL;
pos = 0;
active = 0.0;
last_start = -1.0;
}
~Timing()
{
delete[] str;
}
/** @brief Take a running time measurement.
* @param tag Optional description that will be output again with
* the timings.
* It should describe the operation before the tic(). To time a
* series of @c n operations, there should be @c n+1 calls to
* tic(), and one call to print(). */
inline void
tic(const char* tag = NULL)
{
points_in_time[pos] = omp_get_wtime();
tags[pos] = tag;
pos++;
}
/** @brief Start the running time measurement.
*
* Should be paired with stop(). */
inline void
start()
{
_GLIBCXX_PARALLEL_ASSERT(last_start == -1.0);
last_start = omp_get_wtime();
}
/** @brief Stop the running time measurement.
*
* Should be paired with start(). */
inline void
stop()
{
_GLIBCXX_PARALLEL_ASSERT(last_start != -1.0);
active += (omp_get_wtime() - last_start);
last_start = -1.0;
}
/** @brief Reset running time accumulation. */
inline void
reset()
{
active = 0.0;
last_start = -1.0;
}
/** @brief Accumulate the time between all pairs of start() and
stop() so far */
inline point_in_time
active_time()
{ return active; }
/** @brief Total time between first and last tic() */
inline point_in_time
total_time()
{ return (points_in_time[pos - 1] - points_in_time[0]) * 1000.0; }
private:
/** @brief Construct string to print out, presenting the timings. */
const char*
c_str()
{
// Avoid stream library here, to avoid cyclic dependencies in
// header files.
char tmp[1000];
if (!str)
str = new char[pos * 200];
else
str[0] = '\0';
sprintf(str, "t %2d T[ms]", omp_get_thread_num());
strcat(str, "\n");
for (int i = 0; i < pos; )
{
point_in_time last = points_in_time[i];
i++;
if (i == pos)
break;
if (tags[i] == NULL)
sprintf(tmp, "%2d: ", i - 1);
else
sprintf(tmp, "%20s: ", tags[i]);
strcat(str, tmp);
sprintf(tmp, "%7.2f ", (points_in_time[i] - last) * 1000.0);
strcat(str, tmp);
strcat(str, "\n");
}
return str;
}
public:
/** @brief Print the running times between the tic()s. */
void
print()
{
printf("print\n");
#pragma omp barrier
#pragma omp master
printf("\n\n");
#pragma omp critical
printf("%s\n", c_str());
}
};
/** @brief A class that provides simple run time measurements, also
for parallel code.
* @param tag If parallel_tag, then the measurements are actually done,
* otherwise, no code at all is emitted by the compiler.
*/
template<typename must_be_int>
class Timing<sequential_tag, must_be_int>
{
private:
static const char* empty_string;
public:
inline void tic(const char* /*tag*/ = NULL) { }
inline void start() { }
inline void stop() { }
inline void reset() { }
inline point_in_time active_time() { return -1.0; }
inline point_in_time total_time() { return -1.0; }
inline const char* c_str() { return empty_string; }
inline void print() { }
};
template<typename must_be_int>
const char* Timing<sequential_tag, must_be_int>::empty_string = "";
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/types.h
* @brief Basic typedefs.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler and Felix Putze.
#ifndef _GLIBCXX_PARALLEL_TYPES_H
#define _GLIBCXX_PARALLEL_TYPES_H 1
#include <cstdlib>
namespace __gnu_parallel
{
// XXX need to use <cstdint>
/** @brief 8-bit signed integer. */
typedef char int8;
/** @brief 8-bit unsigned integer. */
typedef unsigned char uint8;
/** @brief 16-bit signed integer. */
typedef short int16;
/** @brief 16-bit unsigned integer. */
typedef unsigned short uint16;
/** @brief 32-bit signed integer. */
typedef int int32;
/** @brief 32-bit unsigned integer. */
typedef unsigned int uint32;
/** @brief 64-bit signed integer. */
typedef long long int64;
/** @brief 64-bit unsigned integer. */
typedef unsigned long long uint64;
/**
* @brief Unsigned integer to index elements.
* The total number of elements for each algorithm must fit into this type.
*/
typedef uint64 sequence_index_t;
/**
* @brief Unsigned integer to index a thread number.
* The maximum thread number (for each processor) must fit into this type.
*/
typedef uint16 thread_index_t;
/**
* @brief Longest compare-and-swappable integer type on this platform.
*/
typedef int64 lcas_t;
/**
* @brief Number of bits of ::lcas_t.
*/
static const int lcas_t_bits = sizeof(lcas_t) * 8;
/**
* @brief ::lcas_t with the right half of bits set to 1.
*/
static const lcas_t lcas_t_mask = (((lcas_t)1 << (lcas_t_bits / 2)) - 1);
}
#endif /* _GLIBCXX_TYPES_H */

View File

@ -0,0 +1,193 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/unique_copy.h
* @brief Parallel implementations of std::unique_copy().
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Robert Geisberger and Robin Dapp.
#ifndef _GLIBCXX_PARALLEL_UNIQUE_H
#define _GLIBCXX_PARALLEL_UNIQUE_H 1
#include <parallel/parallel.h>
#include <parallel/multiseq_selection.h>
namespace __gnu_parallel
{
/** @brief Parallel std::unique_copy(), without explicit equality predicate.
* @param first Begin iterator of input sequence.
* @param last End iterator of input sequence.
* @param result Begin iterator of result sequence.
* @param binary_pred Equality predicate.
* @return End iterator of result sequence. */
template<typename InputIterator, class OutputIterator, class BinaryPredicate>
inline OutputIterator
parallel_unique_copy(InputIterator first, InputIterator last,
OutputIterator result, BinaryPredicate binary_pred)
{
_GLIBCXX_CALL(last - first)
typedef std::iterator_traits<InputIterator> traits_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::difference_type difference_type;
difference_type size = last - first;
int num_threads = __gnu_parallel::get_max_threads();
difference_type counter[num_threads + 1];
if (size == 0)
return result;
// Let the first thread process two parts.
difference_type borders[num_threads + 2];
__gnu_parallel::equally_split(size, num_threads + 1, borders);
// First part contains at least one element.
#pragma omp parallel num_threads(num_threads)
{
int iam = omp_get_thread_num();
difference_type begin, end;
// Check for length without duplicates
// Needed for position in output
difference_type i = 0;
OutputIterator out = result;
if (iam == 0)
{
begin = borders[0] + 1; // == 1
end = borders[iam + 1];
i++;
new (static_cast<void *>(&*out)) value_type(*first);
out++;
for (InputIterator iter = first + begin; iter < first + end; ++iter)
{
if (!binary_pred(*iter, *(iter-1)))
{
i++;
new (static_cast<void *>(&*out)) value_type(*iter);
out++;
}
}
}
else
{
begin = borders[iam]; //one part
end = borders[iam + 1];
for (InputIterator iter = first + begin; iter < first + end; ++iter)
{
if (!binary_pred(*iter, *(iter-1)))
{
i++;
}
}
}
counter[iam] = i;
// Last part still untouched.
difference_type begin_output;
#pragma omp barrier
// Store result in output on calculated positions.
begin_output = 0;
if (iam == 0)
{
for (int t = 0; t < num_threads; t++)
begin_output += counter[t];
i = 0;
OutputIterator iter_out = result + begin_output;
begin = borders[num_threads];
end = size;
for (InputIterator iter = first + begin; iter < first + end; ++iter)
{
if (iter == first || !binary_pred(*iter, *(iter-1)))
{
i++;
new (static_cast<void *>(&*iter_out)) value_type(*iter);
iter_out++;
}
}
counter[num_threads] = i;
}
else
{
for (int t = 0; t < iam; t++)
begin_output += counter[t];
OutputIterator iter_out = result + begin_output;
for (InputIterator iter = first + begin; iter < first + end; ++iter)
{
if (!binary_pred(*iter, *(iter-1)))
{
new (static_cast<void *> (&*iter_out)) value_type(*iter);
iter_out++;
}
}
}
}
difference_type end_output = 0;
for (int t = 0; t < num_threads + 1; t++)
end_output += counter[t];
return result + end_output;
}
/** @brief Parallel std::unique_copy(), without explicit equality predicate
* @param first Begin iterator of input sequence.
* @param last End iterator of input sequence.
* @param result Begin iterator of result sequence.
* @return End iterator of result sequence. */
template<typename InputIterator, class OutputIterator>
inline OutputIterator
parallel_unique_copy(InputIterator first, InputIterator last,
OutputIterator result)
{
typedef typename std::iterator_traits<InputIterator>::value_type value_type;
return parallel_unique_copy(first, last, result, std::equal_to<value_type>());
}
}//namespace __gnu_parallel
#endif

View File

@ -0,0 +1,289 @@
// -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
/** @file parallel/workstealing.h
* @brief Parallelization of embarrassingly parallel execution by
* means of work-stealing.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Felix Putze.
#ifndef _GLIBCXX_PARALLEL_WORKSTEALING_H
#define _GLIBCXX_PARALLEL_WORKSTEALING_H 1
#include <parallel/parallel.h>
#include <parallel/random_number.h>
#include <parallel/compatibility.h>
namespace __gnu_parallel
{
#define _GLIBCXX_JOB_VOLATILE volatile
/** @brief One job for a certain thread. */
template<typename _DifferenceTp>
struct Job
{
typedef _DifferenceTp difference_type;
/** @brief First element.
*
* Changed by owning and stealing thread. By stealing thread,
* always incremented. */
_GLIBCXX_JOB_VOLATILE difference_type first;
/** @brief Last element.
*
* Changed by owning thread only. */
_GLIBCXX_JOB_VOLATILE difference_type last;
/** @brief Number of elements, i. e. @c last-first+1.
*
* Changed by owning thread only. */
_GLIBCXX_JOB_VOLATILE difference_type load;
};
/** @brief Work stealing algorithm for random access iterators.
*
* Uses O(1) additional memory. Synchronization at job lists is
* done with atomic operations.
* @param begin Begin iterator of element sequence.
* @param end End iterator of element sequence.
* @param op User-supplied functor (comparator, predicate, adding
* functor, ...).
* @param f Functor to "process" an element with op (depends on
* desired functionality, e. g. for std::for_each(), ...).
* @param r Functor to "add" a single result to the already
* processed elements (depends on functionality).
* @param base Base value for reduction.
* @param output Pointer to position where final result is written to
* @param bound Maximum number of elements processed (e. g. for
* std::count_n()).
* @return User-supplied functor (that may contain a part of the result).
*/
template<typename RandomAccessIterator, typename Op, typename Fu, typename Red, typename Result>
Op
for_each_template_random_access_workstealing(RandomAccessIterator begin,
RandomAccessIterator end,
Op op, Fu& f, Red r,
Result base, Result& output,
typename std::iterator_traits<RandomAccessIterator>::difference_type bound)
{
_GLIBCXX_CALL(end - begin)
typedef std::iterator_traits<RandomAccessIterator> traits_type;
typedef typename traits_type::difference_type difference_type;
difference_type chunk_size = static_cast<difference_type>(Settings::workstealing_chunk_size);
// How many jobs?
difference_type length = (bound < 0) ? (end - begin) : bound;
// To avoid false sharing in a cache line.
const int stride = Settings::cache_line_size * 10 / sizeof(Job<difference_type>) + 1;
// Total number of threads currently working.
thread_index_t busy = 0;
thread_index_t num_threads = get_max_threads();
difference_type num_threads_min = num_threads < end - begin ? num_threads : end - begin;
// No more threads than jobs, at least one thread.
difference_type num_threads_max = num_threads_min > 1 ? num_threads_min : 1;
num_threads = static_cast<thread_index_t>(num_threads_max);
// Create job description array.
Job<difference_type> *job = new Job<difference_type>[num_threads * stride];
// Write base value to output.
output = base;
#pragma omp parallel shared(busy) num_threads(num_threads)
{
// Initialization phase.
// Flags for every thread if it is doing productive work.
bool iam_working = false;
// Thread id.
thread_index_t iam = omp_get_thread_num();
// This job.
Job<difference_type>& my_job = job[iam * stride];
// Random number (for work stealing).
thread_index_t victim;
// Local value for reduction.
Result result = Result();
// Number of elements to steal in one attempt.
difference_type steal;
// Every thread has its own random number generator (modulo num_threads).
random_number rand_gen(iam, num_threads);
#pragma omp atomic
// This thread is currently working.
busy++;
iam_working = true;
// How many jobs per thread? last thread gets the rest.
my_job.first = static_cast<difference_type>(iam * (length / num_threads));
my_job.last = (iam == (num_threads - 1)) ? (length - 1) : ((iam + 1) * (length / num_threads) - 1);
my_job.load = my_job.last - my_job.first + 1;
// Init result with first value (to have a base value for reduction).
if (my_job.first <= my_job.last)
{
// Cannot use volatile variable directly.
difference_type my_first = my_job.first;
result = f(op, begin + my_first);
my_job.first++;
my_job.load--;
}
RandomAccessIterator current;
#pragma omp barrier
// Actual work phase
// Work on own or stolen start
while (busy > 0)
{
// Work until no productive thread left.
#pragma omp flush(busy)
// Thread has own work to do
while (my_job.first <= my_job.last)
{
// fetch-and-add call
// Reserve current job block (size chunk_size) in my queue.
difference_type current_job = fetch_and_add<difference_type>(&(my_job.first), chunk_size);
// Update load, to make the three values consistent,
// first might have been changed in the meantime
my_job.load = my_job.last - my_job.first + 1;
for (difference_type job_counter = 0; job_counter < chunk_size && current_job <= my_job.last; job_counter++)
{
// Yes: process it!
current = begin + current_job;
current_job++;
// Do actual work.
result = r(result, f(op, current));
}
#pragma omp flush(busy)
}
// After reaching this point, a thread's job list is empty.
if (iam_working)
{
#pragma omp atomic
// This thread no longer has work.
busy--;
iam_working = false;
}
difference_type supposed_first, supposed_last, supposed_load;
do
{
// Find random nonempty deque (not own) and do consistency check.
yield();
#pragma omp flush(busy)
victim = rand_gen();
supposed_first = job[victim * stride].first;
supposed_last = job[victim * stride].last;
supposed_load = job[victim * stride].load;
}
while (busy > 0
&& ((supposed_load <= 0) || ((supposed_first + supposed_load - 1) != supposed_last)));
if (busy == 0)
break;
if (supposed_load > 0)
{
// Has work and work to do.
// Number of elements to steal (at least one).
steal = (supposed_load < 2) ? 1 : supposed_load / 2;
// Protects against stealing threads
// omp_set_lock(&(job[victim * stride].lock));
// Push victim's start forward.
difference_type stolen_first = fetch_and_add<difference_type>(&(job[victim * stride].first), steal);
difference_type stolen_try = stolen_first + steal - difference_type(1);
// Protects against working thread
// omp_unset_lock(&(job[victim * stride].lock));
my_job.first = stolen_first;
// Avoid std::min dependencies.
my_job.last = stolen_try < supposed_last ? stolen_try : supposed_last;
my_job.load = my_job.last - my_job.first + 1;
//omp_unset_lock(&(my_job.lock));
#pragma omp atomic
// Has potential work again.
busy++;
iam_working = true;
#pragma omp flush(busy)
}
#pragma omp flush(busy)
} // end while busy > 0
#pragma omp critical(writeOutput)
// Add accumulated result to output.
output = r(output, result);
//omp_destroy_lock(&(my_job.lock));
}
delete[] job;
// Points to last element processed (needed as return value for
// some algorithms like transform)
f.finish_iterator = begin + length;
return op;
}
} // end namespace
#endif

View File

@ -66,4 +66,8 @@
#include <bits/stl_algobase.h>
#include <bits/stl_algo.h>
#ifdef _GLIBCXX_PARALLEL
# include <parallel/algorithm>
#endif
#endif /* _GLIBCXX_ALGORITHM */

View File

@ -62,7 +62,7 @@
((__n) < 1 ? 0 : ((__n) + _GLIBCXX_BITSET_BITS_PER_WORD - 1) \
/ _GLIBCXX_BITSET_BITS_PER_WORD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
/**
* @if maint

View File

@ -67,4 +67,8 @@
#include <bits/stl_iterator_base_types.h>
#include <bits/stl_numeric.h>
#ifdef _GLIBCXX_PARALLEL
# include <parallel/numeric>
#endif
#endif /* _GLIBCXX_NUMERIC */

View File

@ -49,8 +49,12 @@
#include <bits/cpp_type_traits.h>
#include <bits/localefwd.h> // For operators >>, <<, and getline.
#include <bits/ostream_insert.h>
#include <bits/stl_iterator_base_types.h>
#include <bits/stl_iterator_base_funcs.h>
#include <bits/stl_iterator.h>
#include <bits/stl_function.h> // For less
#include <ext/numeric_traits.h>
#include <bits/stl_algobase.h>
#include <bits/basic_string.h>
#ifndef _GLIBCXX_EXPORT_TEMPLATE

View File

@ -86,6 +86,7 @@ AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
ATOMICITY_SRCDIR = @ATOMICITY_SRCDIR@
ATOMIC_FLAGS = @ATOMIC_FLAGS@
ATOMIC_WORD_SRCDIR = @ATOMIC_WORD_SRCDIR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@ -123,6 +124,8 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
ENABLE_PARALLEL_FALSE = @ENABLE_PARALLEL_FALSE@
ENABLE_PARALLEL_TRUE = @ENABLE_PARALLEL_TRUE@
ENABLE_SYMVERS_DARWIN_FALSE = @ENABLE_SYMVERS_DARWIN_FALSE@
ENABLE_SYMVERS_DARWIN_TRUE = @ENABLE_SYMVERS_DARWIN_TRUE@
ENABLE_SYMVERS_FALSE = @ENABLE_SYMVERS_FALSE@

View File

@ -141,6 +141,7 @@ AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
ATOMICITY_SRCDIR = @ATOMICITY_SRCDIR@
ATOMIC_FLAGS = @ATOMIC_FLAGS@
ATOMIC_WORD_SRCDIR = @ATOMIC_WORD_SRCDIR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@ -178,6 +179,8 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
ENABLE_PARALLEL_FALSE = @ENABLE_PARALLEL_FALSE@
ENABLE_PARALLEL_TRUE = @ENABLE_PARALLEL_TRUE@
ENABLE_SYMVERS_DARWIN_FALSE = @ENABLE_SYMVERS_DARWIN_FALSE@
ENABLE_SYMVERS_DARWIN_TRUE = @ENABLE_SYMVERS_DARWIN_TRUE@
ENABLE_SYMVERS_FALSE = @ENABLE_SYMVERS_FALSE@

View File

@ -71,6 +71,7 @@ AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
ATOMICITY_SRCDIR = @ATOMICITY_SRCDIR@
ATOMIC_FLAGS = @ATOMIC_FLAGS@
ATOMIC_WORD_SRCDIR = @ATOMIC_WORD_SRCDIR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@ -108,6 +109,8 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
ENABLE_PARALLEL_FALSE = @ENABLE_PARALLEL_FALSE@
ENABLE_PARALLEL_TRUE = @ENABLE_PARALLEL_TRUE@
ENABLE_SYMVERS_DARWIN_FALSE = @ENABLE_SYMVERS_DARWIN_FALSE@
ENABLE_SYMVERS_DARWIN_TRUE = @ENABLE_SYMVERS_DARWIN_TRUE@
ENABLE_SYMVERS_FALSE = @ENABLE_SYMVERS_FALSE@

View File

@ -32,10 +32,12 @@ SH_FLAG="-Wl,--rpath -Wl,$BUILD_DIR/../../gcc \
-Wl,--rpath -Wl,$BUILD_DIR/src/.libs"
ST_FLAG="-static"
LINK=$SH_FLAG
CXX="$COMPILER $INCLUDES $PCH_FLAGS $FLAGS $LINK"
CXX="$COMPILER $INCLUDES $FLAGS $CXXFLAGS $LINK"
LIBS="./libtestc++.a"
TESTS_FILE="testsuite_files_performance"
echo CXX is $CXX
for NAME in `cat $TESTS_FILE`
do
RUN=true
@ -79,7 +81,7 @@ do
EXE_NAME="`echo $FILE_NAME.exe`"
$CXX $TESTNAME $LIBS -o $EXE_NAME
if [ -f $EXE_NAME ]; then
./$EXE_NAME >& tmp.$FILE_NAME
./$EXE_NAME >& tmp.$FILE_NAME
else
echo "compile error:"
echo "$CXX $TESTNAME $LIBS -o $EXE_NAME"

View File

@ -58,6 +58,13 @@ case ${query} in
CXXFLAGS_config="@SECTION_FLAGS@ @CXXFLAGS@ @EXTRA_CXX_FLAGS@"
echo ${CXXFLAGS_default} ${CXXFLAGS_config}
;;
--cxxparallelflags)
CXXFLAGS_parallel="-D_GLIBCXX_PARALLEL -fopenmp
-B${BUILD_DIR}/../libgomp
-I${BUILD_DIR}/../libgomp
-L${BUILD_DIR}/../libgomp/.libs -lgomp"
echo ${CXXFLAGS_parallel}
;;
--cxxpchflags)
PCHFLAGS="@glibcxx_PCHFLAGS@"
echo ${PCHFLAGS}

View File

@ -112,8 +112,7 @@ atomicity.cc: ${atomicity_file}
# Source files linked in via configuration/make substitution for a
# particular host, but with ad hoc naming rules.
host_sources_extra = \
basic_file.cc \
c++locale.cc
basic_file.cc c++locale.cc ${ldbl_compat_sources} ${parallel_sources}
c++locale.cc: ${glibcxx_srcdir}/$(CLOCALE_CC)
$(LN_S) ${glibcxx_srcdir}/$(CLOCALE_CC) ./$@ || true
@ -121,6 +120,12 @@ c++locale.cc: ${glibcxx_srcdir}/$(CLOCALE_CC)
basic_file.cc: ${glibcxx_srcdir}/$(BASIC_FILE_CC)
$(LN_S) ${glibcxx_srcdir}/$(BASIC_FILE_CC) ./$@ || true
if ENABLE_PARALLEL
parallel_sources = parallel_list.cc
else
parallel_sources =
endif
if GLIBCXX_LDBL_COMPAT
ldbl_compat_sources = compatibility-ldbl.cc
else
@ -137,7 +142,6 @@ sources = \
complex_io.cc \
ctype.cc \
debug.cc \
debug_list.cc \
functexcept.cc \
hash.cc \
hash_c++0x.cc \
@ -148,6 +152,7 @@ sources = \
ios_locale.cc \
limits.cc \
list.cc \
debug_list.cc \
locale.cc \
locale_init.cc \
locale_facets.cc \
@ -175,8 +180,7 @@ sources = \
wlocale-inst.cc \
wstring-inst.cc \
${host_sources} \
${host_sources_extra} \
${ldbl_compat_sources}
${host_sources_extra}
VPATH = $(top_srcdir)/src:$(top_srcdir)
@ -207,6 +211,12 @@ concept-inst.lo: concept-inst.cc
concept-inst.o: concept-inst.cc
$(CXXCOMPILE) -D_GLIBCXX_CONCEPT_CHECKS -fimplicit-templates -c $<
# Use special rules for parallel_list.cc compile.
parallel_list.lo: parallel_list.cc
$(LTCXXCOMPILE) -I$(glibcxx_builddir)/../libgomp -c $<
parallel_list.o: parallel_list.cc
$(CXXCOMPILE) -I$(glibcxx_builddir)/../libgomp -c $<
# Use special rules for the C++0x sources so that the proper flags are passed.
system_error.lo: system_error.cc
$(LTCXXCOMPILE) -std=gnu++0x -c $<

View File

@ -69,9 +69,9 @@ toolexeclibLTLIBRARIES_INSTALL = $(INSTALL)
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
am__libstdc___la_SOURCES_DIST = bitmap_allocator.cc pool_allocator.cc \
mt_allocator.cc codecvt.cc compatibility.cc complex_io.cc \
ctype.cc debug.cc debug_list.cc functexcept.cc hash.cc \
hash_c++0x.cc globals_io.cc ios.cc ios_failure.cc ios_init.cc \
ios_locale.cc limits.cc list.cc locale.cc locale_init.cc \
ctype.cc debug.cc functexcept.cc hash.cc hash_c++0x.cc \
globals_io.cc ios.cc ios_failure.cc ios_init.cc ios_locale.cc \
limits.cc list.cc debug_list.cc locale.cc locale_init.cc \
locale_facets.cc localename.cc stdexcept.cc strstream.cc \
system_error.cc tree.cc allocator-inst.cc concept-inst.cc \
fstream-inst.cc ext-inst.cc ios-inst.cc iostream-inst.cc \
@ -81,25 +81,28 @@ am__libstdc___la_SOURCES_DIST = bitmap_allocator.cc pool_allocator.cc \
wstring-inst.cc atomicity.cc codecvt_members.cc \
collate_members.cc ctype_members.cc messages_members.cc \
monetary_members.cc numeric_members.cc time_members.cc \
basic_file.cc c++locale.cc compatibility-ldbl.cc
basic_file.cc c++locale.cc compatibility-ldbl.cc \
parallel_list.cc
am__objects_1 = atomicity.lo codecvt_members.lo collate_members.lo \
ctype_members.lo messages_members.lo monetary_members.lo \
numeric_members.lo time_members.lo
am__objects_2 = basic_file.lo c++locale.lo
@GLIBCXX_LDBL_COMPAT_TRUE@am__objects_3 = compatibility-ldbl.lo
am__objects_4 = bitmap_allocator.lo pool_allocator.lo mt_allocator.lo \
@GLIBCXX_LDBL_COMPAT_TRUE@am__objects_2 = compatibility-ldbl.lo
@ENABLE_PARALLEL_TRUE@am__objects_3 = parallel_list.lo
am__objects_4 = basic_file.lo c++locale.lo $(am__objects_2) \
$(am__objects_3)
am__objects_5 = bitmap_allocator.lo pool_allocator.lo mt_allocator.lo \
codecvt.lo compatibility.lo complex_io.lo ctype.lo debug.lo \
debug_list.lo functexcept.lo hash.lo hash_c++0x.lo \
globals_io.lo ios.lo ios_failure.lo ios_init.lo ios_locale.lo \
limits.lo list.lo locale.lo locale_init.lo locale_facets.lo \
functexcept.lo hash.lo hash_c++0x.lo globals_io.lo ios.lo \
ios_failure.lo ios_init.lo ios_locale.lo limits.lo list.lo \
debug_list.lo locale.lo locale_init.lo locale_facets.lo \
localename.lo stdexcept.lo strstream.lo system_error.lo \
tree.lo allocator-inst.lo concept-inst.lo fstream-inst.lo \
ext-inst.lo ios-inst.lo iostream-inst.lo istream-inst.lo \
istream.lo locale-inst.lo misc-inst.lo ostream-inst.lo \
sstream-inst.lo streambuf-inst.lo streambuf.lo string-inst.lo \
valarray-inst.lo wlocale-inst.lo wstring-inst.lo \
$(am__objects_1) $(am__objects_2) $(am__objects_3)
am_libstdc___la_OBJECTS = $(am__objects_4)
$(am__objects_1) $(am__objects_4)
am_libstdc___la_OBJECTS = $(am__objects_5)
libstdc___la_OBJECTS = $(am_libstdc___la_OBJECTS)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp =
@ -121,6 +124,7 @@ AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
ATOMICITY_SRCDIR = @ATOMICITY_SRCDIR@
ATOMIC_FLAGS = @ATOMIC_FLAGS@
ATOMIC_WORD_SRCDIR = @ATOMIC_WORD_SRCDIR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@ -158,6 +162,8 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
ENABLE_PARALLEL_FALSE = @ENABLE_PARALLEL_FALSE@
ENABLE_PARALLEL_TRUE = @ENABLE_PARALLEL_TRUE@
ENABLE_SYMVERS_DARWIN_FALSE = @ENABLE_SYMVERS_DARWIN_FALSE@
ENABLE_SYMVERS_DARWIN_TRUE = @ENABLE_SYMVERS_DARWIN_TRUE@
ENABLE_SYMVERS_FALSE = @ENABLE_SYMVERS_FALSE@
@ -348,9 +354,10 @@ atomicity_file = ${glibcxx_srcdir}/$(ATOMICITY_SRCDIR)/atomicity.h
# Source files linked in via configuration/make substitution for a
# particular host, but with ad hoc naming rules.
host_sources_extra = \
basic_file.cc \
c++locale.cc
basic_file.cc c++locale.cc ${ldbl_compat_sources} ${parallel_sources}
@ENABLE_PARALLEL_FALSE@parallel_sources =
@ENABLE_PARALLEL_TRUE@parallel_sources = parallel_list.cc
@GLIBCXX_LDBL_COMPAT_FALSE@ldbl_compat_sources =
@GLIBCXX_LDBL_COMPAT_TRUE@ldbl_compat_sources = compatibility-ldbl.cc
@ -364,7 +371,6 @@ sources = \
complex_io.cc \
ctype.cc \
debug.cc \
debug_list.cc \
functexcept.cc \
hash.cc \
hash_c++0x.cc \
@ -375,6 +381,7 @@ sources = \
ios_locale.cc \
limits.cc \
list.cc \
debug_list.cc \
locale.cc \
locale_init.cc \
locale_facets.cc \
@ -402,8 +409,7 @@ sources = \
wlocale-inst.cc \
wstring-inst.cc \
${host_sources} \
${host_sources_extra} \
${ldbl_compat_sources}
${host_sources_extra}
libstdc___la_SOURCES = $(sources)
libstdc___la_LIBADD = \
@ -790,6 +796,12 @@ concept-inst.lo: concept-inst.cc
concept-inst.o: concept-inst.cc
$(CXXCOMPILE) -D_GLIBCXX_CONCEPT_CHECKS -fimplicit-templates -c $<
# Use special rules for parallel_list.cc compile.
parallel_list.lo: parallel_list.cc
$(LTCXXCOMPILE) -I$(glibcxx_builddir)/../libgomp -c $<
parallel_list.o: parallel_list.cc
$(CXXCOMPILE) -I$(glibcxx_builddir)/../libgomp -c $<
# Use special rules for the C++0x sources so that the proper flags are passed.
system_error.lo: system_error.cc
$(LTCXXCOMPILE) -std=gnu++0x -c $<

View File

@ -55,7 +55,7 @@
#include <list>
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD)
_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
void
_List_node_base::swap(_List_node_base& __x, _List_node_base& __y)

View File

@ -0,0 +1,32 @@
// Parallel mode support code for list -*- C++ -*-
// Copyright (C) 2007 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING. If not, write to the Free
// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
// USA.
// As a special exception, you may use this file as part of a free software
// library without restriction. Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License. This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
#define _GLIBCXX_PARALLEL
#include "list.cc"

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