X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=i686-linux-gnu-4.7%2Fusr%2Finclude%2Fc%2B%2B%2F4.7%2Fparallel%2Fpartition.h;fp=i686-linux-gnu-4.7%2Fusr%2Finclude%2Fc%2B%2B%2F4.7%2Fparallel%2Fpartition.h;h=c651321584e117ef8b4ab3a595a095d2a05bbac7;hb=94df942c2c7bd3457276fe5b7367623cbb8c1302;hp=0000000000000000000000000000000000000000;hpb=4dd7d9155a920895ff7b1cb6b9c9c676aa62000a;p=cross.git diff --git a/i686-linux-gnu-4.7/usr/include/c++/4.7/parallel/partition.h b/i686-linux-gnu-4.7/usr/include/c++/4.7/parallel/partition.h new file mode 100644 index 0000000..c651321 --- /dev/null +++ b/i686-linux-gnu-4.7/usr/include/c++/4.7/parallel/partition.h @@ -0,0 +1,434 @@ +// -*- C++ -*- + +// Copyright (C) 2007, 2008, 2009, 2010 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 3, 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. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @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 +#include +#include +#include +#include + +/** @brief Decide whether to declare certain variables volatile. */ +#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 __num_threads Maximum number of threads to use for this task. + * @return Number of elements not fulfilling the predicate. */ + template + typename std::iterator_traits<_RAIter>::difference_type + __parallel_partition(_RAIter __begin, _RAIter __end, + _Predicate __pred, _ThreadIndex __num_threads) + { + typedef std::iterator_traits<_RAIter> _TraitsType; + typedef typename _TraitsType::value_type _ValueType; + typedef typename _TraitsType::difference_type _DifferenceType; + + _DifferenceType __n = __end - __begin; + + _GLIBCXX_CALL(__n) + + const _Settings& __s = _Settings::get(); + + // shared + _GLIBCXX_VOLATILE _DifferenceType __left = 0, __right = __n - 1, + __dist = __n, + __leftover_left, __leftover_right, + __leftnew, __rightnew; + + // just 0 or 1, but int to allow atomic operations + int* __reserved_left = 0, * __reserved_right = 0; + + _DifferenceType __chunk_size = __s.partition_chunk_size; + + //at least two chunks per thread + if (__dist >= 2 * __num_threads * __chunk_size) +# pragma omp parallel num_threads(__num_threads) + { +# pragma omp single + { + __num_threads = omp_get_num_threads(); + __reserved_left = new int[__num_threads]; + __reserved_right = new int[__num_threads]; + + if (__s.partition_chunk_share > 0.0) + __chunk_size = std::max<_DifferenceType> + (__s.partition_chunk_size, (double)__n + * __s.partition_chunk_share / (double)__num_threads); + else + __chunk_size = __s.partition_chunk_size; + } + + while (__dist >= 2 * __num_threads * __chunk_size) + { +# pragma omp single + { + _DifferenceType __num_chunks = __dist / __chunk_size; + + for (_ThreadIndex __r = 0; __r < __num_threads; ++__r) + { + __reserved_left [__r] = 0; // false + __reserved_right[__r] = 0; // false + } + __leftover_left = 0; + __leftover_right = 0; + } //implicit barrier + + // Private. + _DifferenceType __thread_left, __thread_left_border, + __thread_right, __thread_right_border; + + __thread_left = __left + 1; + // Just to satisfy the condition below. + __thread_left_border = __thread_left - 1; + + __thread_right = __n - 1; + // Just to satisfy the condition below. + __thread_right_border = __thread_right + 1; + + bool __iam_finished = false; + while (!__iam_finished) + { + if (__thread_left > __thread_left_border) + { + _DifferenceType __former_dist = + __fetch_and_add(&__dist, -__chunk_size); + if (__former_dist < __chunk_size) + { + __fetch_and_add(&__dist, __chunk_size); + __iam_finished = true; + break; + } + else + { + __thread_left = + __fetch_and_add(&__left, __chunk_size); + __thread_left_border = + __thread_left + (__chunk_size - 1); + } + } + + if (__thread_right < __thread_right_border) + { + _DifferenceType __former_dist = + __fetch_and_add(&__dist, -__chunk_size); + if (__former_dist < __chunk_size) + { + __fetch_and_add(&__dist, __chunk_size); + __iam_finished = true; + break; + } + else + { + __thread_right = + __fetch_and_add(&__right, -__chunk_size); + __thread_right_border = + __thread_right - (__chunk_size - 1); + } + } + + // 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::iter_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 + + _DifferenceType + __leftold = __left, + __leftnew = __left - __leftover_left * __chunk_size, + __rightold = __right, + __rightnew = __right + __leftover_right * __chunk_size; + + // <=> __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] = 1; + } + + // <=> __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] = 1; + } + +# pragma omp barrier + + if (__thread_left <= __thread_left_border + && __thread_left_border < __leftnew) + { + // Find spot and swap. + _DifferenceType __swapstart = -1; + for (int __r = 0; __r < __leftover_left; ++__r) + if (__reserved_left[__r] == 0 + && __compare_and_swap(&(__reserved_left[__r]), 0, 1)) + { + __swapstart = __leftold - (__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 + _DifferenceType __swapstart = -1; + for (int __r = 0; __r < __leftover_right; ++__r) + if (__reserved_right[__r] == 0 + && __compare_and_swap(&(__reserved_right[__r]), 0, 1)) + { + __swapstart = __rightold + __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 (_DifferenceType __r = 0; __r < __leftover_left; ++__r) + _GLIBCXX_PARALLEL_ASSERT(__reserved_left[__r] == 1); + for (_DifferenceType __r = 0; __r < __leftover_right; ++__r) + _GLIBCXX_PARALLEL_ASSERT(__reserved_right[__r] == 1); + } +#endif + + __left = __leftnew; + __right = __rightnew; + __dist = __right - __left + 1; + } + +# pragma omp flush(__left, __right) + } // end "recursion" //parallel + + _DifferenceType __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::iter_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 + void + __parallel_nth_element(_RAIter __begin, _RAIter __nth, + _RAIter __end, _Compare __comp) + { + typedef std::iterator_traits<_RAIter> _TraitsType; + typedef typename _TraitsType::value_type _ValueType; + typedef typename _TraitsType::difference_type _DifferenceType; + + _GLIBCXX_CALL(__end - __begin) + + _RAIter __split; + _RandomNumber __rng; + + const _Settings& __s = _Settings::get(); + _DifferenceType __minimum_length = std::max<_DifferenceType>(2, + std::max(__s.nth_element_minimal_n, __s.partition_minimal_n)); + + // Break if input range to small. + while (static_cast<_SequenceIndex>(__end - __begin) >= __minimum_length) + { + _DifferenceType __n = __end - __begin; + + _RAIter __pivot_pos = __begin + __rng(__n); + + // Swap __pivot_pos value to end. + if (__pivot_pos != (__end - 1)) + std::iter_swap(__pivot_pos, __end - 1); + __pivot_pos = __end - 1; + + // _Compare must have first_value_type, second_value_type, + // result_type + // _Compare == + // __gnu_parallel::_Lexicographic > + // __pivot_pos == std::pair* + __gnu_parallel::__binder2nd<_Compare, _ValueType, _ValueType, bool> + __pred(__comp, *__pivot_pos); + + // Divide, leave pivot unchanged in last place. + _RAIter __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::iter_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 strictly larger than the pivot. + __gnu_parallel::__unary_negate<__gnu_parallel:: + __binder1st<_Compare, _ValueType, + _ValueType, bool>, _ValueType> + __pred(__gnu_parallel::__binder1st<_Compare, _ValueType, + _ValueType, 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::nth_element(__begin, __nth, __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 + void + __parallel_partial_sort(_RAIter __begin, + _RAIter __middle, + _RAIter __end, _Compare __comp) + { + __parallel_nth_element(__begin, __middle, __end, __comp); + std::sort(__begin, __middle, __comp); + } + +} //namespace __gnu_parallel + +#undef _GLIBCXX_VOLATILE + +#endif /* _GLIBCXX_PARALLEL_PARTITION_H */