unique_copy.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/unique_copy.h
00032  *  @brief Parallel implementations of std::unique_copy().
00033  *  This file is a GNU parallel extension to the Standard C++ Library.
00034  */
00035 
00036 // Written by Robert Geisberger and Robin Dapp.
00037 
00038 #ifndef _GLIBCXX_PARALLEL_UNIQUE_H
00039 #define _GLIBCXX_PARALLEL_UNIQUE_H 1
00040 
00041 #include <parallel/parallel.h>
00042 #include <parallel/multiseq_selection.h>
00043 
00044 namespace __gnu_parallel
00045 {
00046 
00047 /** @brief Parallel std::unique_copy(), w/o explicit equality predicate.
00048   *  @param first Begin iterator of input sequence.
00049   *  @param last End iterator of input sequence.
00050   *  @param result Begin iterator of result sequence.
00051   *  @param binary_pred Equality predicate.
00052   *  @return End iterator of result sequence. */
00053 template<typename InputIterator,
00054      class OutputIterator,
00055      class BinaryPredicate>
00056   OutputIterator
00057   parallel_unique_copy(InputIterator first, InputIterator last,
00058                        OutputIterator result, BinaryPredicate binary_pred)
00059   {
00060     _GLIBCXX_CALL(last - first)
00061 
00062     typedef std::iterator_traits<InputIterator> traits_type;
00063     typedef typename traits_type::value_type value_type;
00064     typedef typename traits_type::difference_type difference_type;
00065 
00066     difference_type size = last - first;
00067 
00068     if (size == 0)
00069       return result;
00070 
00071     // Let the first thread process two parts.
00072     difference_type *counter;
00073     difference_type *borders;
00074 
00075     thread_index_t num_threads = get_max_threads();
00076     // First part contains at least one element.
00077 #   pragma omp parallel num_threads(num_threads)
00078       {
00079 #       pragma omp single
00080           {
00081         num_threads = omp_get_num_threads();
00082         borders = new difference_type[num_threads + 2];
00083         equally_split(size, num_threads + 1, borders);
00084         counter = new difference_type[num_threads + 1];
00085           }
00086 
00087         thread_index_t iam = omp_get_thread_num();
00088 
00089         difference_type begin, end;
00090 
00091         // Check for length without duplicates
00092         // Needed for position in output
00093         difference_type i = 0;
00094         OutputIterator out = result;
00095 
00096         if (iam == 0)
00097         {
00098           begin = borders[0] + 1;   // == 1
00099           end = borders[iam + 1];
00100 
00101           ++i;
00102           *out++ = *first;
00103 
00104           for (InputIterator iter = first + begin; iter < first + end; ++iter)
00105             {
00106               if (!binary_pred(*iter, *(iter-1)))
00107                 {
00108                   ++i;
00109                   *out++ = *iter;
00110                 }
00111             }
00112         }
00113       else
00114         {
00115           begin = borders[iam]; //one part
00116           end = borders[iam + 1];
00117 
00118           for (InputIterator iter = first + begin; iter < first + end; ++iter)
00119             {
00120               if (!binary_pred(*iter, *(iter - 1)))
00121         ++i;
00122         }
00123         }
00124       counter[iam] = i;
00125 
00126       // Last part still untouched.
00127       difference_type begin_output;
00128 
00129 #     pragma omp barrier
00130 
00131       // Store result in output on calculated positions.
00132       begin_output = 0;
00133 
00134       if (iam == 0)
00135         {
00136           for (int t = 0; t < num_threads; ++t)
00137             begin_output += counter[t];
00138 
00139           i = 0;
00140 
00141           OutputIterator iter_out = result + begin_output;
00142 
00143           begin = borders[num_threads];
00144           end = size;
00145 
00146           for (InputIterator iter = first + begin; iter < first + end; ++iter)
00147             {
00148               if (iter == first || !binary_pred(*iter, *(iter - 1)))
00149                 {
00150                   ++i;
00151                   *iter_out++ = *iter;
00152                 }
00153             }
00154 
00155           counter[num_threads] = i;
00156         }
00157       else
00158         {
00159           for (int t = 0; t < iam; t++)
00160             begin_output += counter[t];
00161 
00162           OutputIterator iter_out = result + begin_output;
00163           for (InputIterator iter = first + begin; iter < first + end; ++iter)
00164             {
00165               if (!binary_pred(*iter, *(iter-1)))
00166         *iter_out++ = *iter;
00167         }
00168         }
00169     }
00170 
00171     difference_type end_output = 0;
00172     for (int t = 0; t < num_threads + 1; t++)
00173       end_output += counter[t];
00174 
00175     delete[] borders;
00176 
00177     return result + end_output;
00178   }
00179 
00180 /** @brief Parallel std::unique_copy(), without explicit equality predicate
00181   *  @param first Begin iterator of input sequence.
00182   *  @param last End iterator of input sequence.
00183   *  @param result Begin iterator of result sequence.
00184   *  @return End iterator of result sequence. */
00185 template<typename InputIterator, class OutputIterator>
00186   inline OutputIterator
00187   parallel_unique_copy(InputIterator first, InputIterator last,
00188                        OutputIterator result)
00189   {
00190     typedef typename std::iterator_traits<InputIterator>::value_type
00191       value_type;
00192     return parallel_unique_copy(first, last, result,
00193                 std::equal_to<value_type>());
00194   }
00195 
00196 }//namespace __gnu_parallel
00197 
00198 #endif

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