# search.h

Go to the documentation of this file.

    00001 // -*- C++ -*-
    00002
    00003 // Copyright (C) 2007, 2008 Free Software Foundation, Inc.
    00004 //
    00005 // This file is part of the GNU ISO C++ Library.  This library is free
    00006 // software; you can redistribute it and/or modify it under the terms
    00007 // of the GNU General Public License as published by the Free Software
    00008 // Foundation; either version 2, or (at your option) any later
    00009 // version.
    00010
    00011 // This library is distributed in the hope that it will be useful, but
    00012 // WITHOUT ANY WARRANTY; without even the implied warranty of
    00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00014 // General Public License for more details.
    00015
    00016 // You should have received a copy of the GNU General Public License
    00017 // along with this library; see the file COPYING.  If not, write to
    00018 // the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
    00019 // MA 02111-1307, USA.
    00020
    00021 // As a special exception, you may use this file as part of a free
    00022 // software library without restriction.  Specifically, if other files
    00023 // instantiate templates or use macros or inline functions from this
    00024 // file, or you compile this file and link it with other files to
    00025 // produce an executable, this file does not by itself cause the
    00026 // resulting executable to be covered by the GNU General Public
    00027 // License.  This exception does not however invalidate any other
    00028 // reasons why the executable file might be covered by the GNU General
    00029 // Public License.
    00030
    00031 /** @file parallel/search.h
    00032  *  @brief Parallel implementation base for std::search() and
    00033  *  std::search_n().
    00034  *  This file is a GNU parallel extension to the Standard C++ Library.
    00035  */
    00036
    00037 // Written by Felix Putze.
    00038
    00039 #ifndef _GLIBCXX_PARALLEL_SEARCH_H
    00040 #define _GLIBCXX_PARALLEL_SEARCH_H 1
    00041
    00042 #include <bits/stl_algobase.h>
    00043
    00044 #include <parallel/parallel.h>
    00045 #include <parallel/equally_split.h>
    00046
    00047
    00048 namespace __gnu_parallel
    00049 {
    00050   /**
    00051    *  @brief Precalculate advances for Knuth-Morris-Pratt algorithm.
    00052    *  @param elements Begin iterator of sequence to search for.
    00053    *  @param length Length of sequence to search for.
    00054    *  @param advances Returned offsets.
    00055    */
    00056 template<typename RandomAccessIterator, typename _DifferenceTp>
    00057   void
    00058   calc_borders(RandomAccessIterator elements, _DifferenceTp length,
    00059               _DifferenceTp* off)
    00060   {
    00061     typedef _DifferenceTp difference_type;
    00062
    00063     off[0] = -1;
    00064     if (length > 1)
    00065       off[1] = 0;
    00066     difference_type k = 0;
    00067     for (difference_type j = 2; j <= length; j++)
    00068       {
    00069         while ((k >= 0) && !(elements[k] == elements[j-1]))
    00070           k = off[k];
    00071         off[j] = ++k;
    00072       }
    00073   }
    00074
    00075   // Generic parallel find algorithm (requires random access iterator).
    00076
    00077   /** @brief Parallel std::search.
    00078    *  @param begin1 Begin iterator of first sequence.
    00079    *  @param end1 End iterator of first sequence.
    00080    *  @param begin2 Begin iterator of second sequence.
    00081    *  @param end2 End iterator of second sequence.
    00082    *  @param pred Find predicate.
    00083    *  @return Place of finding in first sequences. */
    00084 template<typename _RandomAccessIterator1,
    00085      typename _RandomAccessIterator2,
    00086      typename Pred>
    00087   _RandomAccessIterator1
    00088   search_template(_RandomAccessIterator1 begin1, _RandomAccessIterator1 end1,
    00089                   _RandomAccessIterator2 begin2, _RandomAccessIterator2 end2,
    00090                   Pred pred)
    00091   {
    00092     typedef std::iterator_traits<_RandomAccessIterator1> traits_type;
    00093     typedef typename traits_type::difference_type difference_type;
    00094
    00095     _GLIBCXX_CALL((end1 - begin1) + (end2 - begin2));
    00096
    00097     difference_type pattern_length = end2 - begin2;
    00098
    00099     // Pattern too short.
    00100     if(pattern_length <= 0)
    00101       return end1;
    00102
    00103     // Last point to start search.
    00104     difference_type input_length = (end1 - begin1) - pattern_length;
    00105
    00106     // Where is first occurrence of pattern? defaults to end.
    00107     difference_type result = (end1 - begin1);
    00108     difference_type *splitters;
    00109
    00110     // Pattern too long.
    00111     if (input_length < 0)
    00112       return end1;
    00113
    00114     omp_lock_t result_lock;
    00115     omp_init_lock(&result_lock);
    00116
    00117     thread_index_t num_threads =
    00118         std::max<difference_type>(1,
    00119             std::min<difference_type>(input_length, get_max_threads()));
    00120
    00121     difference_type advances[pattern_length];
    00122     calc_borders(begin2, pattern_length, advances);
    00123
    00124 #   pragma omp parallel num_threads(num_threads)
    00125       {
    00126 #       pragma omp single
    00127           {
    00128             num_threads = omp_get_num_threads();
    00129             splitters = new difference_type[num_threads + 1];
    00130             equally_split(input_length, num_threads, splitters);
    00131           }
    00132
    00133         thread_index_t iam = omp_get_thread_num();
    00134
    00135         difference_type start = splitters[iam], stop = splitters[iam + 1];
    00136
    00137         difference_type pos_in_pattern = 0;
    00138         bool found_pattern = false;
    00139
    00140         while (start <= stop && !found_pattern)
    00141           {
    00142             // Get new value of result.
    00143             #pragma omp flush(result)
    00144             // No chance for this thread to find first occurrence.
    00145             if (result < start)
    00146               break;
    00147             while (pred(begin1[start + pos_in_pattern],
    00148                          begin2[pos_in_pattern]))
    00149               {
    00150                 ++pos_in_pattern;
    00151                 if (pos_in_pattern == pattern_length)
    00152                   {
    00153                     // Found new candidate for result.
    00154                             omp_set_lock(&result_lock);
    00155                     result = std::min(result, start);
    00156                             omp_unset_lock(&result_lock);
    00157
    00158                     found_pattern = true;
    00159                     break;
    00160                   }
    00161               }
    00162             // Make safe jump.
    00163             start += (pos_in_pattern - advances[pos_in_pattern]);
    00164             pos_in_pattern =
    00165                 (advances[pos_in_pattern] < 0) ? 0 : advances[pos_in_pattern];
    00166           }
    00167       } //parallel
    00168
    00169     omp_destroy_lock(&result_lock);
    00170
    00171     delete[] splitters;
    00172
    00173     // Return iterator on found element.
    00174     return (begin1 + result);
    00175   }
    00176 } // end namespace
    00177
    00178 #endif