Home | History | Annotate | Download | only in parallel
      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 /**
     26  * @file parallel/set_operations.h
     27  * @brief Parallel implementations of set operations for random-access
     28  * iterators.
     29  *  This file is a GNU parallel extension to the Standard C++ Library.
     30  */
     31 
     32 // Written by Marius Elvert and Felix Bondarenko.
     33 
     34 #ifndef _GLIBCXX_PARALLEL_SET_OPERATIONS_H
     35 #define _GLIBCXX_PARALLEL_SET_OPERATIONS_H 1
     36 
     37 #include <omp.h>
     38 
     39 #include <parallel/settings.h>
     40 #include <parallel/multiseq_selection.h>
     41 
     42 namespace __gnu_parallel
     43 {
     44 template<typename InputIterator, typename OutputIterator>
     45   OutputIterator
     46   copy_tail(std::pair<InputIterator, InputIterator> b,
     47             std::pair<InputIterator, InputIterator> e, OutputIterator r)
     48   {
     49     if (b.first != e.first)
     50       {
     51         do
     52           {
     53             *r++ = *b.first++;
     54           }
     55         while (b.first != e.first);
     56       }
     57     else
     58       {
     59         while (b.second != e.second)
     60           *r++ = *b.second++;
     61       }
     62     return r;
     63   }
     64 
     65 template<typename InputIterator,
     66 	 typename OutputIterator,
     67 	 typename Comparator>
     68   struct symmetric_difference_func
     69   {
     70     typedef std::iterator_traits<InputIterator> traits_type;
     71     typedef typename traits_type::difference_type difference_type;
     72     typedef typename std::pair<InputIterator, InputIterator> iterator_pair;
     73 
     74     symmetric_difference_func(Comparator c) : comp(c) {}
     75 
     76     Comparator comp;
     77 
     78     OutputIterator
     79     invoke(InputIterator a, InputIterator b,
     80 	   InputIterator c, InputIterator d,
     81 	   OutputIterator r) const
     82     {
     83       while (a != b && c != d)
     84         {
     85           if (comp(*a, *c))
     86             {
     87               *r = *a;
     88               ++a;
     89               ++r;
     90             }
     91           else if (comp(*c, *a))
     92             {
     93               *r = *c;
     94               ++c;
     95               ++r;
     96             }
     97           else
     98             {
     99               ++a;
    100               ++c;
    101             }
    102         }
    103       return std::copy(c, d, std::copy(a, b, r));
    104     }
    105 
    106     difference_type
    107     count(InputIterator a, InputIterator b,
    108 	  InputIterator c, InputIterator d) const
    109     {
    110       difference_type counter = 0;
    111 
    112       while (a != b && c != d)
    113         {
    114           if (comp(*a, *c))
    115             {
    116               ++a;
    117               ++counter;
    118             }
    119           else if (comp(*c, *a))
    120             {
    121               ++c;
    122               ++counter;
    123             }
    124           else
    125             {
    126               ++a;
    127               ++c;
    128             }
    129         }
    130 
    131       return counter + (b - a) + (d - c);
    132     }
    133 
    134     OutputIterator
    135     first_empty(InputIterator c, InputIterator d, OutputIterator out) const
    136     { return std::copy(c, d, out); }
    137 
    138     OutputIterator
    139     second_empty(InputIterator a, InputIterator b, OutputIterator out) const
    140     { return std::copy(a, b, out); }
    141   };
    142 
    143 
    144 template<typename InputIterator,
    145 	 typename OutputIterator,
    146 	 typename Comparator>
    147   struct difference_func
    148   {
    149     typedef std::iterator_traits<InputIterator> traits_type;
    150     typedef typename traits_type::difference_type difference_type;
    151     typedef typename std::pair<InputIterator, InputIterator> iterator_pair;
    152 
    153     difference_func(Comparator c) : comp(c) {}
    154 
    155     Comparator comp;
    156 
    157     OutputIterator
    158     invoke(InputIterator a, InputIterator b, InputIterator c, InputIterator d,
    159           OutputIterator r) const
    160     {
    161       while (a != b && c != d)
    162         {
    163           if (comp(*a, *c))
    164             {
    165               *r = *a;
    166               ++a;
    167               ++r;
    168             }
    169           else if (comp(*c, *a))
    170             { ++c; }
    171           else
    172             {
    173               ++a;
    174               ++c;
    175             }
    176         }
    177       return std::copy(a, b, r);
    178     }
    179 
    180     difference_type
    181     count(InputIterator a, InputIterator b,
    182 	  InputIterator c, InputIterator d) const
    183     {
    184       difference_type counter = 0;
    185 
    186       while (a != b && c != d)
    187         {
    188           if (comp(*a, *c))
    189             {
    190               ++a;
    191               ++counter;
    192             }
    193           else if (comp(*c, *a))
    194             { ++c; }
    195           else
    196             { ++a; ++c; }
    197         }
    198 
    199       return counter + (b - a);
    200     }
    201 
    202     inline OutputIterator
    203     first_empty(InputIterator c, InputIterator d, OutputIterator out) const
    204     { return out; }
    205 
    206     inline OutputIterator
    207     second_empty(InputIterator a, InputIterator b, OutputIterator out) const
    208     { return std::copy(a, b, out); }
    209   };
    210 
    211 
    212 template<typename InputIterator,
    213 	 typename OutputIterator,
    214 	 typename Comparator>
    215   struct intersection_func
    216   {
    217     typedef std::iterator_traits<InputIterator> traits_type;
    218     typedef typename traits_type::difference_type difference_type;
    219     typedef typename std::pair<InputIterator, InputIterator> iterator_pair;
    220 
    221     intersection_func(Comparator c) : comp(c) {}
    222 
    223     Comparator comp;
    224 
    225     OutputIterator
    226     invoke(InputIterator a, InputIterator b, InputIterator c, InputIterator d,
    227           OutputIterator r) const
    228     {
    229       while (a != b && c != d)
    230         {
    231           if (comp(*a, *c))
    232             { ++a; }
    233           else if (comp(*c, *a))
    234             { ++c; }
    235           else
    236             {
    237               *r = *a;
    238               ++a;
    239               ++c;
    240               ++r;
    241             }
    242         }
    243 
    244       return r;
    245     }
    246 
    247     difference_type
    248     count(InputIterator a, InputIterator b,
    249 	  InputIterator c, InputIterator d) const
    250     {
    251       difference_type counter = 0;
    252 
    253       while (a != b && c != d)
    254         {
    255           if (comp(*a, *c))
    256             { ++a; }
    257           else if (comp(*c, *a))
    258             { ++c; }
    259           else
    260             {
    261               ++a;
    262               ++c;
    263               ++counter;
    264             }
    265         }
    266 
    267       return counter;
    268     }
    269 
    270     inline OutputIterator
    271     first_empty(InputIterator c, InputIterator d, OutputIterator out) const
    272     { return out; }
    273 
    274     inline OutputIterator
    275     second_empty(InputIterator a, InputIterator b, OutputIterator out) const
    276     { return out; }
    277   };
    278 
    279 template<class InputIterator, class OutputIterator, class Comparator>
    280   struct union_func
    281   {
    282     typedef typename std::iterator_traits<InputIterator>::difference_type
    283     difference_type;
    284 
    285     union_func(Comparator c) : comp(c) {}
    286 
    287     Comparator comp;
    288 
    289     OutputIterator
    290     invoke(InputIterator a, const InputIterator b, InputIterator c,
    291           const InputIterator d, OutputIterator r) const
    292     {
    293       while (a != b && c != d)
    294         {
    295           if (comp(*a, *c))
    296             {
    297               *r = *a;
    298               ++a;
    299             }
    300           else if (comp(*c, *a))
    301             {
    302               *r = *c;
    303               ++c;
    304             }
    305           else
    306             {
    307               *r = *a;
    308               ++a;
    309               ++c;
    310             }
    311           ++r;
    312         }
    313       return std::copy(c, d, std::copy(a, b, r));
    314     }
    315 
    316     difference_type
    317     count(InputIterator a, InputIterator b,
    318 	  InputIterator c, InputIterator d) const
    319     {
    320       difference_type counter = 0;
    321 
    322       while (a != b && c != d)
    323         {
    324           if (comp(*a, *c))
    325             { ++a; }
    326           else if (comp(*c, *a))
    327             { ++c; }
    328           else
    329             {
    330               ++a;
    331               ++c;
    332             }
    333           ++counter;
    334         }
    335 
    336       counter += (b - a);
    337       counter += (d - c);
    338       return counter;
    339     }
    340 
    341     inline OutputIterator
    342     first_empty(InputIterator c, InputIterator d, OutputIterator out) const
    343     { return std::copy(c, d, out); }
    344 
    345     inline OutputIterator
    346     second_empty(InputIterator a, InputIterator b, OutputIterator out) const
    347     { return std::copy(a, b, out); }
    348   };
    349 
    350 template<typename InputIterator,
    351 	 typename OutputIterator,
    352 	 typename Operation>
    353   OutputIterator
    354   parallel_set_operation(InputIterator begin1, InputIterator end1,
    355                          InputIterator begin2, InputIterator end2,
    356                          OutputIterator result, Operation op)
    357   {
    358     _GLIBCXX_CALL((end1 - begin1) + (end2 - begin2))
    359 
    360     typedef std::iterator_traits<InputIterator> traits_type;
    361     typedef typename traits_type::difference_type difference_type;
    362     typedef typename std::pair<InputIterator, InputIterator> iterator_pair;
    363 
    364     if (begin1 == end1)
    365       return op.first_empty(begin2, end2, result);
    366 
    367     if (begin2 == end2)
    368       return op.second_empty(begin1, end1, result);
    369 
    370     const difference_type size = (end1 - begin1) + (end2 - begin2);
    371 
    372     const iterator_pair sequence[ 2 ] =
    373         { std::make_pair(begin1, end1), std::make_pair(begin2, end2) } ;
    374     OutputIterator return_value = result;
    375     difference_type *borders;
    376     iterator_pair *block_begins;
    377     difference_type* lengths;
    378 
    379     thread_index_t num_threads =
    380         std::min<difference_type>(get_max_threads(),
    381             std::min(end1 - begin1, end2 - begin2));
    382 
    383 #   pragma omp parallel num_threads(num_threads)
    384       {
    385 #       pragma omp single
    386           {
    387             num_threads = omp_get_num_threads();
    388 
    389             borders = new difference_type[num_threads + 2];
    390             equally_split(size, num_threads + 1, borders);
    391             block_begins = new iterator_pair[num_threads + 1];
    392             // Very start.
    393             block_begins[0] = std::make_pair(begin1, begin2);
    394             lengths = new difference_type[num_threads];
    395           } //single
    396 
    397         thread_index_t iam = omp_get_thread_num();
    398 
    399         // Result from multiseq_partition.
    400         InputIterator offset[2];
    401         const difference_type rank = borders[iam + 1];
    402 
    403         multiseq_partition(sequence, sequence + 2, rank, offset, op.comp);
    404 
    405         // allowed to read?
    406         // together
    407         // *(offset[ 0 ] - 1) == *offset[ 1 ]
    408         if (offset[ 0 ] != begin1 && offset[ 1 ] != end2
    409             && !op.comp(*(offset[ 0 ] - 1), *offset[ 1 ])
    410             && !op.comp(*offset[ 1 ], *(offset[ 0 ] - 1)))
    411           {
    412             // Avoid split between globally equal elements: move one to
    413             // front in first sequence.
    414             --offset[ 0 ];
    415           }
    416 
    417         iterator_pair block_end = block_begins[ iam + 1 ] =
    418             iterator_pair(offset[ 0 ], offset[ 1 ]);
    419 
    420         // Make sure all threads have their block_begin result written out.
    421 #       pragma omp barrier
    422 
    423         iterator_pair block_begin = block_begins[ iam ];
    424 
    425         // Begin working for the first block, while the others except
    426         // the last start to count.
    427         if (iam == 0)
    428           {
    429             // The first thread can copy already.
    430             lengths[ iam ] = op.invoke(block_begin.first, block_end.first,
    431                                        block_begin.second, block_end.second,
    432                                        result)
    433                               - result;
    434           }
    435         else
    436           {
    437             lengths[ iam ] = op.count(block_begin.first, block_end.first,
    438                         block_begin.second, block_end.second);
    439           }
    440 
    441         // Make sure everyone wrote their lengths.
    442 #       pragma omp barrier
    443 
    444         OutputIterator r = result;
    445 
    446         if (iam == 0)
    447           {
    448             // Do the last block.
    449             for (int i = 0; i < num_threads; ++i)
    450               r += lengths[i];
    451 
    452             block_begin = block_begins[num_threads];
    453 
    454             // Return the result iterator of the last block.
    455             return_value = op.invoke(
    456                 block_begin.first, end1, block_begin.second, end2, r);
    457 
    458           }
    459         else
    460           {
    461             for (int i = 0; i < iam; ++i)
    462               r += lengths[ i ];
    463 
    464             // Reset begins for copy pass.
    465             op.invoke(block_begin.first, block_end.first,
    466                   block_begin.second, block_end.second, r);
    467           }
    468       }
    469     return return_value;
    470   }
    471 
    472 
    473 template<typename InputIterator,
    474 	 typename OutputIterator,
    475 	 typename Comparator>
    476   inline OutputIterator
    477   parallel_set_union(InputIterator begin1, InputIterator end1,
    478                      InputIterator begin2, InputIterator end2,
    479                      OutputIterator result, Comparator comp)
    480   {
    481     return parallel_set_operation(begin1, end1, begin2, end2, result,
    482         union_func< InputIterator, OutputIterator, Comparator>(comp));
    483   }
    484 
    485 template<typename InputIterator,
    486 	 typename OutputIterator,
    487 	 typename Comparator>
    488   inline OutputIterator
    489   parallel_set_intersection(InputIterator begin1, InputIterator end1,
    490                             InputIterator begin2, InputIterator end2,
    491                             OutputIterator result, Comparator comp)
    492   {
    493     return parallel_set_operation(begin1, end1, begin2, end2, result,
    494         intersection_func<InputIterator, OutputIterator, Comparator>(comp));
    495   }
    496 
    497 template<typename InputIterator,
    498 	 typename OutputIterator,
    499 	 typename Comparator>
    500   inline OutputIterator
    501   parallel_set_difference(InputIterator begin1, InputIterator end1,
    502                           InputIterator begin2, InputIterator end2,
    503                           OutputIterator result, Comparator comp)
    504   {
    505     return parallel_set_operation(begin1, end1, begin2, end2, result,
    506         difference_func<InputIterator, OutputIterator, Comparator>(comp));
    507   }
    508 
    509 template<typename InputIterator,
    510 	 typename OutputIterator,
    511 	 typename Comparator>
    512   inline OutputIterator
    513   parallel_set_symmetric_difference(InputIterator begin1, InputIterator end1,
    514                                     InputIterator begin2, InputIterator end2,
    515                                     OutputIterator result, Comparator comp)
    516   {
    517     return parallel_set_operation(begin1, end1, begin2, end2, result,
    518         symmetric_difference_func<InputIterator, OutputIterator, Comparator>
    519             (comp));
    520   }
    521 
    522 }
    523 
    524 #endif /* _GLIBCXX_PARALLEL_SET_OPERATIONS_H */
    525