# 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