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

Generated on Wed Mar 26 00:43:10 2008 for libstdc++ by  doxygen 1.5.1