gcc44: add forgotten file
[dragonfly.git] / contrib / gcc-4.4 / libstdc++-v3 / include / parallel / find.h
1 // -*- C++ -*-
2
3 // Copyright (C) 2007, 2008, 2009 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/find.h
26  *  @brief Parallel implementation base for std::find(), std::equal()
27  *  and related functions.
28  *  This file is a GNU parallel extension to the Standard C++ Library.
29  */
30
31 // Written by Felix Putze and Johannes Singler.
32
33 #ifndef _GLIBCXX_PARALLEL_FIND_H
34 #define _GLIBCXX_PARALLEL_FIND_H 1
35
36 #include <bits/stl_algobase.h>
37
38 #include <parallel/features.h>
39 #include <parallel/parallel.h>
40 #include <parallel/compatibility.h>
41 #include <parallel/equally_split.h>
42
43 namespace __gnu_parallel
44 {
45 /**
46  *  @brief Parallel std::find, switch for different algorithms.
47  *  @param begin1 Begin iterator of first sequence.
48  *  @param end1 End iterator of first sequence.
49  *  @param begin2 Begin iterator of second sequence. Must have same
50  *  length as first sequence.
51  *  @param pred Find predicate.
52  *  @param selector Functionality (e. g. std::find_if (), std::equal(),...)
53  *  @return Place of finding in both sequences.
54  */
55 template<typename RandomAccessIterator1,
56          typename RandomAccessIterator2,
57          typename Pred,
58          typename Selector>
59   inline std::pair<RandomAccessIterator1, RandomAccessIterator2>
60   find_template(RandomAccessIterator1 begin1, RandomAccessIterator1 end1,
61                 RandomAccessIterator2 begin2, Pred pred, Selector selector)
62   {
63     switch (_Settings::get().find_algorithm)
64       {
65       case GROWING_BLOCKS:
66         return find_template(begin1, end1, begin2, pred, selector,
67                              growing_blocks_tag());
68       case CONSTANT_SIZE_BLOCKS:
69         return find_template(begin1, end1, begin2, pred, selector,
70                              constant_size_blocks_tag());
71       case EQUAL_SPLIT:
72         return find_template(begin1, end1, begin2, pred, selector,
73                              equal_split_tag());
74       default:
75         _GLIBCXX_PARALLEL_ASSERT(false);
76         return std::make_pair(begin1, begin2);
77       }
78   }
79
80 #if _GLIBCXX_FIND_EQUAL_SPLIT
81
82 /**
83  *  @brief Parallel std::find, equal splitting variant.
84  *  @param begin1 Begin iterator of first sequence.
85  *  @param end1 End iterator of first sequence.
86  *  @param begin2 Begin iterator of second sequence. Second sequence
87  *  must have same length as first sequence.
88  *  @param pred Find predicate.
89  *  @param selector Functionality (e. g. std::find_if (), std::equal(),...)
90  *  @return Place of finding in both sequences.
91  */
92 template<typename RandomAccessIterator1,
93          typename RandomAccessIterator2,
94          typename Pred,
95          typename Selector>
96   std::pair<RandomAccessIterator1, RandomAccessIterator2>
97   find_template(RandomAccessIterator1 begin1,
98                 RandomAccessIterator1 end1,
99                 RandomAccessIterator2 begin2,
100                 Pred pred,
101                 Selector selector,
102                 equal_split_tag)
103   {
104     _GLIBCXX_CALL(end1 - begin1)
105
106     typedef std::iterator_traits<RandomAccessIterator1> traits_type;
107     typedef typename traits_type::difference_type difference_type;
108     typedef typename traits_type::value_type value_type;
109
110     difference_type length = end1 - begin1;
111     difference_type result = length;
112     difference_type* borders;
113
114     omp_lock_t result_lock;
115     omp_init_lock(&result_lock);
116
117     thread_index_t num_threads = get_max_threads();
118 #   pragma omp parallel num_threads(num_threads)
119       {
120 #       pragma omp single
121           {
122             num_threads = omp_get_num_threads();
123             borders = new difference_type[num_threads + 1];
124             equally_split(length, num_threads, borders);
125           } //single
126
127         thread_index_t iam = omp_get_thread_num();
128         difference_type start = borders[iam], stop = borders[iam + 1];
129
130         RandomAccessIterator1 i1 = begin1 + start;
131         RandomAccessIterator2 i2 = begin2 + start;
132         for (difference_type pos = start; pos < stop; ++pos)
133           {
134             #pragma omp flush(result)
135             // Result has been set to something lower.
136             if (result < pos)
137               break;
138
139             if (selector(i1, i2, pred))
140               {
141                 omp_set_lock(&result_lock);
142                 if (pos < result)
143                   result = pos;
144                 omp_unset_lock(&result_lock);
145                 break;
146               }
147             ++i1;
148             ++i2;
149           }
150       } //parallel
151
152     omp_destroy_lock(&result_lock);
153     delete[] borders;
154
155     return
156       std::pair<RandomAccessIterator1, RandomAccessIterator2>(begin1 + result,
157                                                               begin2 + result);
158   }
159
160 #endif
161
162 #if _GLIBCXX_FIND_GROWING_BLOCKS
163
164 /**
165  *  @brief Parallel std::find, growing block size variant.
166  *  @param begin1 Begin iterator of first sequence.
167  *  @param end1 End iterator of first sequence.
168  *  @param begin2 Begin iterator of second sequence. Second sequence
169  *  must have same length as first sequence.
170  *  @param pred Find predicate.
171  *  @param selector Functionality (e. g. std::find_if (), std::equal(),...)
172  *  @return Place of finding in both sequences.
173  *  @see __gnu_parallel::_Settings::find_sequential_search_size
174  *  @see __gnu_parallel::_Settings::find_initial_block_size
175  *  @see __gnu_parallel::_Settings::find_maximum_block_size
176  *  @see __gnu_parallel::_Settings::find_increasing_factor
177  *
178  *  There are two main differences between the growing blocks and
179  *  the constant-size blocks variants.
180  *  1. For GB, the block size grows; for CSB, the block size is fixed.
181
182  *  2. For GB, the blocks are allocated dynamically;
183  *     for CSB, the blocks are allocated in a predetermined manner,
184  *     namely spacial round-robin.
185  */
186 template<typename RandomAccessIterator1,
187          typename RandomAccessIterator2,
188          typename Pred,
189          typename Selector>
190   std::pair<RandomAccessIterator1, RandomAccessIterator2>
191   find_template(RandomAccessIterator1 begin1, RandomAccessIterator1 end1,
192                 RandomAccessIterator2 begin2, Pred pred, Selector selector,
193                 growing_blocks_tag)
194   {
195     _GLIBCXX_CALL(end1 - begin1)
196
197     typedef std::iterator_traits<RandomAccessIterator1> traits_type;
198     typedef typename traits_type::difference_type difference_type;
199     typedef typename traits_type::value_type value_type;
200
201     const _Settings& __s = _Settings::get();
202
203     difference_type length = end1 - begin1;
204
205     difference_type sequential_search_size =
206       std::min<difference_type>(length, __s.find_sequential_search_size);
207
208     // Try it sequentially first.
209     std::pair<RandomAccessIterator1, RandomAccessIterator2> find_seq_result =
210       selector.sequential_algorithm(
211           begin1, begin1 + sequential_search_size, begin2, pred);
212
213     if (find_seq_result.first != (begin1 + sequential_search_size))
214       return find_seq_result;
215
216     // Index of beginning of next free block (after sequential find).
217     difference_type next_block_start = sequential_search_size;
218     difference_type result = length;
219
220     omp_lock_t result_lock;
221     omp_init_lock(&result_lock);
222
223     thread_index_t num_threads = get_max_threads();
224 #   pragma omp parallel shared(result) num_threads(num_threads)
225       {
226 #       pragma omp single
227           num_threads = omp_get_num_threads();
228
229         // Not within first k elements -> start parallel.
230         thread_index_t iam = omp_get_thread_num();
231
232         difference_type block_size = __s.find_initial_block_size;
233         difference_type start =
234             fetch_and_add<difference_type>(&next_block_start, block_size);
235
236         // Get new block, update pointer to next block.
237         difference_type stop =
238             std::min<difference_type>(length, start + block_size);
239
240         std::pair<RandomAccessIterator1, RandomAccessIterator2> local_result;
241
242         while (start < length)
243           {
244 #           pragma omp flush(result)
245             // Get new value of result.
246             if (result < start)
247               {
248                 // No chance to find first element.
249                 break;
250               }
251
252             local_result = selector.sequential_algorithm(
253                 begin1 + start, begin1 + stop, begin2 + start, pred);
254             if (local_result.first != (begin1 + stop))
255               {
256                 omp_set_lock(&result_lock);
257                 if ((local_result.first - begin1) < result)
258                   {
259                     result = local_result.first - begin1;
260
261                     // Result cannot be in future blocks, stop algorithm.
262                     fetch_and_add<difference_type>(&next_block_start, length);
263                   }
264                   omp_unset_lock(&result_lock);
265               }
266
267             block_size =
268               std::min<difference_type>(block_size * __s.find_increasing_factor,
269                                         __s.find_maximum_block_size);
270
271             // Get new block, update pointer to next block.
272             start =
273               fetch_and_add<difference_type>(&next_block_start, block_size);
274             stop = ((length < (start + block_size))
275                     ? length : (start + block_size));
276           }
277       } //parallel
278
279     omp_destroy_lock(&result_lock);
280
281     // Return iterator on found element.
282     return
283       std::pair<RandomAccessIterator1, RandomAccessIterator2>(begin1 + result,
284                                                               begin2 + result);
285   }
286
287 #endif
288
289 #if _GLIBCXX_FIND_CONSTANT_SIZE_BLOCKS
290
291 /**
292  *   @brief Parallel std::find, constant block size variant.
293  *  @param begin1 Begin iterator of first sequence.
294  *  @param end1 End iterator of first sequence.
295  *  @param begin2 Begin iterator of second sequence. Second sequence
296  *  must have same length as first sequence.
297  *  @param pred Find predicate.
298  *  @param selector Functionality (e. g. std::find_if (), std::equal(),...)
299  *  @return Place of finding in both sequences.
300  *  @see __gnu_parallel::_Settings::find_sequential_search_size
301  *  @see __gnu_parallel::_Settings::find_block_size
302  *  There are two main differences between the growing blocks and the
303  *  constant-size blocks variants.
304  *  1. For GB, the block size grows; for CSB, the block size is fixed.
305  *  2. For GB, the blocks are allocated dynamically; for CSB, the
306  *  blocks are allocated in a predetermined manner, namely spacial
307  *  round-robin.
308  */
309 template<typename RandomAccessIterator1,
310          typename RandomAccessIterator2,
311          typename Pred,
312          typename Selector>
313   std::pair<RandomAccessIterator1, RandomAccessIterator2>
314   find_template(RandomAccessIterator1 begin1, RandomAccessIterator1 end1,
315                 RandomAccessIterator2 begin2, Pred pred, Selector selector,
316                 constant_size_blocks_tag)
317   {
318     _GLIBCXX_CALL(end1 - begin1)
319     typedef std::iterator_traits<RandomAccessIterator1> traits_type;
320     typedef typename traits_type::difference_type difference_type;
321     typedef typename traits_type::value_type value_type;
322
323     const _Settings& __s = _Settings::get();
324
325     difference_type length = end1 - begin1;
326
327     difference_type sequential_search_size = std::min<difference_type>(
328         length, __s.find_sequential_search_size);
329
330     // Try it sequentially first.
331     std::pair<RandomAccessIterator1, RandomAccessIterator2> find_seq_result =
332       selector.sequential_algorithm(begin1, begin1 + sequential_search_size,
333                                     begin2, pred);
334
335     if (find_seq_result.first != (begin1 + sequential_search_size))
336       return find_seq_result;
337
338     difference_type result = length;
339     omp_lock_t result_lock;
340     omp_init_lock(&result_lock);
341
342     // Not within first sequential_search_size elements -> start parallel.
343
344     thread_index_t num_threads = get_max_threads();
345 #   pragma omp parallel shared(result) num_threads(num_threads)
346       {
347 #       pragma omp single
348           num_threads = omp_get_num_threads();
349
350         thread_index_t iam = omp_get_thread_num();
351         difference_type block_size = __s.find_initial_block_size;
352
353         // First element of thread's current iteration.
354         difference_type iteration_start = sequential_search_size;
355
356         // Where to work (initialization).
357         difference_type start = iteration_start + iam * block_size;
358         difference_type stop =
359             std::min<difference_type>(length, start + block_size);
360
361         std::pair<RandomAccessIterator1, RandomAccessIterator2> local_result;
362
363         while (start < length)
364           {
365             // Get new value of result.
366 #           pragma omp flush(result)
367             // No chance to find first element.
368             if (result < start)
369               break;
370             local_result = selector.sequential_algorithm(
371                 begin1 + start, begin1 + stop,
372                 begin2 + start, pred);
373             if (local_result.first != (begin1 + stop))
374               {
375                 omp_set_lock(&result_lock);
376                 if ((local_result.first - begin1) < result)
377                   result = local_result.first - begin1;
378                 omp_unset_lock(&result_lock);
379                 // Will not find better value in its interval.
380                 break;
381               }
382
383             iteration_start += num_threads * block_size;
384
385             // Where to work.
386             start = iteration_start + iam * block_size;
387             stop = std::min<difference_type>(length, start + block_size);
388           }
389       } //parallel
390
391     omp_destroy_lock(&result_lock);
392
393     // Return iterator on found element.
394     return
395       std::pair<RandomAccessIterator1, RandomAccessIterator2>(begin1 + result,
396                                                               begin2 + result);
397   }
398 #endif
399 } // end namespace
400
401 #endif /* _GLIBCXX_PARALLEL_FIND_H */