| 1 |
// -*- C++ -*- |
| 2 |
|
| 3 |
// Copyright (C) 2007-2021 Free Software Foundation, Inc. |
| 4 |
// |
| 5 |
// This file is part of the GNU ISO C++ Library. This library is free |
| 6 |
// software; you can redistribute it and/or modify it under the terms |
| 7 |
// of the GNU General Public License as published by the Free Software |
| 8 |
// Foundation; either version 3, or (at your option) any later |
| 9 |
// version. |
| 10 |
|
| 11 |
// This library is distributed in the hope that it will be useful, but |
| 12 |
// WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 |
// General Public License for more details. |
| 15 |
|
| 16 |
// Under Section 7 of GPL version 3, you are granted additional |
| 17 |
// permissions described in the GCC Runtime Library Exception, version |
| 18 |
// 3.1, as published by the Free Software Foundation. |
| 19 |
|
| 20 |
// You should have received a copy of the GNU General Public License and |
| 21 |
// a copy of the GCC Runtime Library Exception along with this program; |
| 22 |
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| 23 |
// <http://www.gnu.org/licenses/>. |
| 24 |
|
| 25 |
/** @file parallel/search.h |
| 26 |
* @brief Parallel implementation base for std::search() and |
| 27 |
* std::search_n(). |
| 28 |
* This file is a GNU parallel extension to the Standard C++ Library. |
| 29 |
*/ |
| 30 |
|
| 31 |
// Written by Felix Putze. |
| 32 |
|
| 33 |
#ifndef _GLIBCXX_PARALLEL_SEARCH_H |
| 34 |
#define _GLIBCXX_PARALLEL_SEARCH_H 1 |
| 35 |
|
| 36 |
#include <bits/stl_algobase.h> |
| 37 |
|
| 38 |
#include <parallel/parallel.h> |
| 39 |
#include <parallel/equally_split.h> |
| 40 |
|
| 41 |
namespace __gnu_parallel |
| 42 |
{ |
| 43 |
/** |
| 44 |
* @brief Precalculate __advances for Knuth-Morris-Pratt algorithm. |
| 45 |
* @param __elements Begin iterator of sequence to search for. |
| 46 |
* @param __length Length of sequence to search for. |
| 47 |
* @param __off Returned __offsets. |
| 48 |
*/ |
| 49 |
template<typename _RAIter, typename _DifferenceTp> |
| 50 |
void |
| 51 |
__calc_borders(_RAIter __elements, _DifferenceTp __length, |
| 52 |
_DifferenceTp* __off) |
| 53 |
{ |
| 54 |
typedef _DifferenceTp _DifferenceType; |
| 55 |
|
| 56 |
__off[0] = -1; |
| 57 |
if (__length > 1) |
| 58 |
__off[1] = 0; |
| 59 |
_DifferenceType __k = 0; |
| 60 |
for (_DifferenceType __j = 2; __j <= __length; __j++) |
| 61 |
{ |
| 62 |
while ((__k >= 0) && !(__elements[__k] == __elements[__j-1])) |
| 63 |
__k = __off[__k]; |
| 64 |
__off[__j] = ++__k; |
| 65 |
} |
| 66 |
} |
| 67 |
|
| 68 |
// Generic parallel find algorithm (requires random access iterator). |
| 69 |
|
| 70 |
/** @brief Parallel std::search. |
| 71 |
* @param __begin1 Begin iterator of first sequence. |
| 72 |
* @param __end1 End iterator of first sequence. |
| 73 |
* @param __begin2 Begin iterator of second sequence. |
| 74 |
* @param __end2 End iterator of second sequence. |
| 75 |
* @param __pred Find predicate. |
| 76 |
* @return Place of finding in first sequences. */ |
| 77 |
template<typename __RAIter1, |
| 78 |
typename __RAIter2, |
| 79 |
typename _Pred> |
| 80 |
__RAIter1 |
| 81 |
__search_template(__RAIter1 __begin1, __RAIter1 __end1, |
| 82 |
__RAIter2 __begin2, __RAIter2 __end2, |
| 83 |
_Pred __pred) |
| 84 |
{ |
| 85 |
typedef std::iterator_traits<__RAIter1> _TraitsType; |
| 86 |
typedef typename _TraitsType::difference_type _DifferenceType; |
| 87 |
|
| 88 |
_GLIBCXX_CALL((__end1 - __begin1) + (__end2 - __begin2)); |
| 89 |
|
| 90 |
_DifferenceType __pattern_length = __end2 - __begin2; |
| 91 |
|
| 92 |
// Pattern too short. |
| 93 |
if(__pattern_length <= 0) |
| 94 |
return __end1; |
| 95 |
|
| 96 |
// Last point to start search. |
| 97 |
_DifferenceType __input_length = (__end1 - __begin1) - __pattern_length; |
| 98 |
|
| 99 |
// Where is first occurrence of pattern? defaults to end. |
| 100 |
_DifferenceType __result = (__end1 - __begin1); |
| 101 |
_DifferenceType *__splitters; |
| 102 |
|
| 103 |
// Pattern too long. |
| 104 |
if (__input_length < 0) |
| 105 |
return __end1; |
| 106 |
|
| 107 |
omp_lock_t __result_lock; |
| 108 |
omp_init_lock(&__result_lock); |
| 109 |
|
| 110 |
_ThreadIndex __num_threads = std::max<_DifferenceType> |
| 111 |
(1, std::min<_DifferenceType>(__input_length, |
| 112 |
__get_max_threads())); |
| 113 |
|
| 114 |
_DifferenceType __advances[__pattern_length]; |
| 115 |
__calc_borders(__begin2, __pattern_length, __advances); |
| 116 |
|
| 117 |
# pragma omp parallel num_threads(__num_threads) |
| 118 |
{ |
| 119 |
# pragma omp single |
| 120 |
{ |
| 121 |
__num_threads = omp_get_num_threads(); |
| 122 |
__splitters = new _DifferenceType[__num_threads + 1]; |
| 123 |
__equally_split(__input_length, __num_threads, __splitters); |
| 124 |
} |
| 125 |
|
| 126 |
_ThreadIndex __iam = omp_get_thread_num(); |
| 127 |
|
| 128 |
_DifferenceType __start = __splitters[__iam], |
| 129 |
__stop = __splitters[__iam + 1]; |
| 130 |
|
| 131 |
_DifferenceType __pos_in_pattern = 0; |
| 132 |
bool __found_pattern = false; |
| 133 |
|
| 134 |
while (__start <= __stop && !__found_pattern) |
| 135 |
{ |
| 136 |
// Get new value of result. |
| 137 |
#pragma omp flush(__result) |
| 138 |
// No chance for this thread to find first occurrence. |
| 139 |
if (__result < __start) |
| 140 |
break; |
| 141 |
while (__pred(__begin1[__start + __pos_in_pattern], |
| 142 |
__begin2[__pos_in_pattern])) |
| 143 |
{ |
| 144 |
++__pos_in_pattern; |
| 145 |
if (__pos_in_pattern == __pattern_length) |
| 146 |
{ |
| 147 |
// Found new candidate for result. |
| 148 |
omp_set_lock(&__result_lock); |
| 149 |
__result = std::min(__result, __start); |
| 150 |
omp_unset_lock(&__result_lock); |
| 151 |
|
| 152 |
__found_pattern = true; |
| 153 |
break; |
| 154 |
} |
| 155 |
} |
| 156 |
// Make safe jump. |
| 157 |
__start += (__pos_in_pattern - __advances[__pos_in_pattern]); |
| 158 |
__pos_in_pattern = (__advances[__pos_in_pattern] < 0 |
| 159 |
? 0 : __advances[__pos_in_pattern]); |
| 160 |
} |
| 161 |
} //parallel |
| 162 |
|
| 163 |
omp_destroy_lock(&__result_lock); |
| 164 |
|
| 165 |
delete[] __splitters; |
| 166 |
|
| 167 |
// Return iterator on found element. |
| 168 |
return (__begin1 + __result); |
| 169 |
} |
| 170 |
} // end namespace |
| 171 |
|
| 172 |
#endif /* _GLIBCXX_PARALLEL_SEARCH_H */ |