]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/include/parallel/tree.h
Add parallel mode.
[thirdparty/gcc.git] / libstdc++-v3 / include / parallel / tree.h
1 // -*- C++ -*-
2
3 // Copyright (C) 2007 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 2, 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 // You should have received a copy of the GNU General Public License
17 // along with this library; see the file COPYING. If not, write to
18 // the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
19 // MA 02111-1307, USA.
20
21 // As a special exception, you may use this file as part of a free
22 // software library without restriction. Specifically, if other files
23 // instantiate templates or use macros or inline functions from this
24 // file, or you compile this file and link it with other files to
25 // produce an executable, this file does not by itself cause the
26 // resulting executable to be covered by the GNU General Public
27 // License. This exception does not however invalidate any other
28 // reasons why the executable file might be covered by the GNU General
29 // Public License.
30
31 /** @file parallel/tree.h
32 * @brief Parallel red-black tree operations.
33 * This file is a GNU parallel extension to the Standard C++ Library.
34 */
35
36 // Written by Leonor Frias Moya, Johannes Singler.
37
38 #ifndef _GLIBCXX_PARALLEL_TREE_H
39 #define _GLIBCXX_PARALLEL_TREE_H 1
40
41 #include <parallel/parallel.h>
42 #include <functional>
43 #include <cmath>
44 #include <algorithm>
45 #include <iterator>
46 #include <functional>
47 #include <iostream>
48 //#include <ext/malloc_allocator.h>
49 #include <bits/stl_tree.h>
50
51 #include <parallel/list_partition.h>
52
53 //#define _GLIBCXX_TIMING
54 #ifdef _GLIBCXX_TIMING
55 #define _timing_tag parallel_tag
56 #else
57 #define _timing_tag sequential_tag
58 #endif
59
60 namespace std
61 {
62 // XXX Declaration should go to stl_tree.h.
63 void
64 _Rb_tree_rotate_left(_Rb_tree_node_base* const __x,
65 _Rb_tree_node_base*& __root);
66
67 void
68 _Rb_tree_rotate_right(_Rb_tree_node_base* const __x,
69 _Rb_tree_node_base*& __root);
70 }
71
72
73 namespace __gnu_parallel
74 {
75 // XXX move into parallel/type_traits.h if <type_traits> doesn't work.
76 /** @brief Helper class: remove the const modifier from the first
77 component, if present. Set kind component.
78 * @param T Simple type, nothing to unconst */
79 template<typename T>
80 struct unconst_first_component
81 {
82 /** @brief New type after removing the const */
83 typedef T type;
84 };
85
86 /** @brief Helper class: remove the const modifier from the first
87 component, if present. Map kind component
88 * @param Key First component, from which to remove the const modifier
89 * @param Load Second component
90 * @sa unconst_first_component */
91 template<typename Key, typename Load>
92 struct unconst_first_component<std::pair<const Key, Load> >
93 {
94 /** @brief New type after removing the const */
95 typedef std::pair<Key, Load> type;
96 };
97
98 /** @brief Helper class: set the appropriate comparator to deal with
99 * repetitions. Comparator for unique dictionaries.
100 *
101 * StrictlyLess and LessEqual are part of a mechanism to deal with
102 * repetitions transparently whatever the actual policy is.
103 * @param _Key Keys to compare
104 * @param _Compare Comparator equal to conceptual < */
105 template<typename _Key, typename _Compare>
106 struct StrictlyLess : public std::binary_function<_Key, _Key, bool>
107 {
108 /** @brief Comparator equal to conceptual < */
109 _Compare c;
110
111 /** @brief Constructor given a Comparator */
112 StrictlyLess(const _Compare& _c) : c(_c) { }
113
114 /** @brief Copy constructor */
115 StrictlyLess(const StrictlyLess<_Key, _Compare>& strictly_less)
116 : c(strictly_less.c) { }
117
118 /** @brief Operator() */
119 bool operator()(const _Key& k1, const _Key& k2) const
120 {
121 return c(k1, k2);
122 }
123 };
124
125 /** @brief Helper class: set the appropriate comparator to deal with
126 * repetitions. Comparator for non-unique dictionaries.
127 *
128 * StrictlyLess and LessEqual are part of a mechanism to deal with
129 * repetitions transparently whatever the actual policy is.
130 * @param _Key Keys to compare
131 * @param _Compare Comparator equal to conceptual <= */
132 template<typename _Key, typename _Compare>
133 struct LessEqual : public std::binary_function<_Key, _Key, bool>
134 {
135 /** @brief Comparator equal to conceptual < */
136 _Compare c;
137
138 /** @brief Constructor given a Comparator */
139 LessEqual(const _Compare& _c) : c(_c) { }
140
141 /** @brief Copy constructor */
142 LessEqual(const LessEqual<_Key, _Compare>& less_equal)
143 : c(less_equal.c) { }
144
145 /** @brief Operator() */
146 bool operator()(const _Key& k1, const _Key& k2) const
147 { return !c(k2, k1); }
148 };
149
150
151 /** @brief Parallel red-black tree.
152 *
153 * Extension of the sequential red-black tree. Specifically,
154 * parallel bulk insertion operations are provided.
155 * @param _Key Keys to compare
156 * @param _Val Elements to store in the tree
157 * @param _KeyOfValue Obtains the key from an element <
158 * @param _Compare Comparator equal to conceptual <
159 * @param _Alloc Allocator for the elements */
160 template<typename _Key, typename _Val, typename _KeyOfValue,
161 typename _Compare, typename _Alloc = std::allocator<_Val> >
162 class _Rb_tree : public std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>
163 {
164 private:
165 /** @brief Sequential tree */
166 typedef std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc> base_type;
167
168 /** @brief Renaming of base node type */
169 typedef typename std::_Rb_tree_node<_Val> _Rb_tree_node;
170
171 /** @brief Renaming of libstdc++ node type */
172 typedef typename std::_Rb_tree_node_base _Rb_tree_node_base;
173
174 /** @brief Renaming of base key_type */
175 typedef typename base_type::key_type key_type;
176
177 /** @brief Renaming of base value_type */
178 typedef typename base_type::value_type value_type;
179
180 /** @brief Helper class to unconst the first component of
181 * value_type if exists.
182 *
183 * This helper class is needed for map, but may discard qualifiers
184 * for set; however, a set with a const element type is not useful
185 * and should fail in some other place anyway.
186 */
187 typedef typename unconst_first_component<value_type>::type nc_value_type;
188
189 /** @brief Pointer to a node */
190 typedef _Rb_tree_node* _Rb_tree_node_ptr;
191
192 /** @brief Wrapper comparator class to deal with repetitions
193 transparently according to dictionary type with key _Key and
194 comparator _Compare. Unique dictionaries object
195 */
196 StrictlyLess<_Key, _Compare> strictly_less;
197
198 /** @brief Wrapper comparator class to deal with repetitions
199 transparently according to dictionary type with key _Key and
200 comparator _Compare. Non-unique dictionaries object
201 */
202 LessEqual<_Key, _Compare> less_equal;
203
204 public:
205 /** @brief Renaming of base size_type */
206 typedef typename base_type::size_type size_type;
207
208 /** @brief Constructor with a given comparator and allocator.
209 *
210 * Delegates the basic initialization to the sequential class and
211 * initializes the helper comparators of the parallel class
212 * @param c Comparator object with which to initialize the class
213 * comparator and the helper comparators
214 * @param a Allocator object with which to initialize the class comparator
215 */
216 _Rb_tree(const _Compare& c, const _Alloc& a)
217 : base_type(c, a), strictly_less(base_type::_M_impl._M_key_compare), less_equal(base_type::_M_impl._M_key_compare)
218 { }
219
220 /** @brief Copy constructor.
221 *
222 * Delegates the basic initialization to the sequential class and
223 * initializes the helper comparators of the parallel class
224 * @param __x Parallel red-black instance to copy
225 */
226 _Rb_tree(const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __x)
227 : base_type(__x), strictly_less(base_type::_M_impl._M_key_compare), less_equal(base_type::_M_impl._M_key_compare)
228 { }
229
230 /** @brief Parallel replacement of the sequential
231 * std::_Rb_tree::_M_insert_unique()
232 *
233 * Parallel bulk insertion and construction. If the container is
234 * empty, bulk construction is performed. Otherwise, bulk
235 * insertion is performed
236 * @param __first First element of the input
237 * @param __last Last element of the input
238 */
239 template<typename _InputIterator>
240 void
241 _M_insert_unique(_InputIterator __first, _InputIterator __last)
242 {
243 if (__first==__last) return;
244 if (_GLIBCXX_PARALLEL_CONDITION(true))
245 if (base_type::_M_impl._M_node_count == 0)
246 {
247 _M_bulk_insertion_construction(__first, __last, true, strictly_less);
248 _GLIBCXX_PARALLEL_ASSERT(rb_verify());
249 }
250 else
251 {
252 _M_bulk_insertion_construction(__first, __last, false, strictly_less);
253 _GLIBCXX_PARALLEL_ASSERT(rb_verify());
254 }
255 else
256 {
257 base_type::_M_insert_unique(__first, __last);
258 }
259 }
260
261 /** @brief Parallel replacement of the sequential
262 * std::_Rb_tree::_M_insert_equal()
263 *
264 * Parallel bulk insertion and construction. If the container is
265 * empty, bulk construction is performed. Otherwise, bulk
266 * insertion is performed
267 * @param __first First element of the input
268 * @param __last Last element of the input */
269 template<typename _InputIterator>
270 void
271 _M_insert_equal(_InputIterator __first, _InputIterator __last)
272 {
273 if (__first==__last) return;
274 if (_GLIBCXX_PARALLEL_CONDITION(true))
275 if (base_type::_M_impl._M_node_count == 0)
276 _M_bulk_insertion_construction(__first, __last, true, less_equal);
277 else
278 _M_bulk_insertion_construction(__first, __last, false, less_equal);
279 else
280 base_type::_M_insert_equal(__first, __last);
281 _GLIBCXX_PARALLEL_ASSERT(rb_verify());
282 }
283
284 private:
285
286 /** @brief Helper class of _Rb_tree: node linking.
287 *
288 * Nodes linking forming an almost complete tree. The last level
289 * is coloured red, the rest are black
290 * @param ranker Calculates the position of a node in an array of nodes
291 */
292 template<typename ranker>
293 class nodes_initializer
294 {
295 /** @brief Renaming of tree size_type */
296
297 typedef typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::size_type size_type;
298 public:
299
300 /** @brief mask[%i]= 0..01..1, where the number of 1s is %i+1 */
301 size_type mask[sizeof(size_type)*8];
302
303 /** @brief Array of nodes (initial address) */
304 const _Rb_tree_node_ptr* r_init;
305
306 /** @brief Total number of (used) nodes */
307 size_type n;
308
309 /** @brief Rank of the last tree node that can be calculated
310 taking into account a complete tree
311 */
312 size_type splitting_point;
313
314 /** @brief Rank of the tree root */
315 size_type rank_root;
316
317 /** @brief Height of the tree */
318 int height;
319
320 /** @brief Number of threads into which divide the work */
321 const thread_index_t num_threads;
322
323 /** @brief Helper object to mind potential gaps in r_init */
324 const ranker& rank;
325
326 /** @brief Constructor
327 * @param r Array of nodes
328 * @param _n Total number of (used) nodes
329 * @param _num_threads Number of threads into which divide the work
330 * @param _rank Helper object to mind potential gaps in @c r_init */
331 nodes_initializer(const _Rb_tree_node_ptr* r, const size_type _n, const thread_index_t _num_threads, const ranker& _rank):
332 r_init(r),
333 n(_n),
334 num_threads(_num_threads),
335 rank(_rank)
336 {
337 height = log2(n);
338 splitting_point = 2 * (n - ((1 << height) - 1)) -1;
339
340 // Rank root.
341 size_type max = 1 << (height + 1);
342 rank_root= (max-2) >> 1;
343 if (rank_root > splitting_point)
344 rank_root = complete_to_original(rank_root);
345
346 mask[0] = 0x1;
347 for (unsigned int i = 1; i < sizeof(size_type)*8; ++i)
348 {
349 mask[i] = (mask[i-1] << 1) + 1;
350 }
351 }
352
353 /** @brief Query for tree height
354 * @return Tree height */
355 int get_height() const
356 {
357 return height;
358 }
359
360 /** @brief Query for the splitting point
361 * @return Splitting point */
362 size_type get_shifted_splitting_point() const
363 {
364 return rank.get_shifted_rank(splitting_point, 0);
365 }
366
367 /** @brief Query for the tree root node
368 * @return Tree root node */
369 _Rb_tree_node_ptr get_root() const
370 {
371 return r_init[rank.get_shifted_rank(rank_root,num_threads/2)];
372 }
373
374 /** @brief Calculation of the parent position in the array of nodes
375 * @hideinitializer */
376 #define CALCULATE_PARENT \
377 if (p_s> splitting_point) \
378 p_s = complete_to_original(p_s); \
379 int s_r = rank.get_shifted_rank(p_s,iam); \
380 r->_M_parent = r_init[s_r]; \
381 \
382 /** @brief Link a node with its parent and children taking into
383 account that its rank (without gaps) is different to that in
384 a complete tree
385 * @param r Pointer to the node
386 * @param iam Partition of the array in which the node is, where
387 * iam is in [0..num_threads)
388 * @sa link_complete */
389 void link_incomplete(const _Rb_tree_node_ptr& r, const int iam) const
390 {
391 size_type real_pos = rank.get_real_rank(&r-r_init, iam);
392 size_type l_s, r_s, p_s;
393 int mod_pos= original_to_complete(real_pos);
394 int zero= first_0_right(mod_pos);
395
396 // 1. Convert n to n', where n' will be its rank if the tree
397 // was complete
398 // 2. Calculate neighbours for n'
399 // 3. Convert the neighbours n1', n2' and n3' to their
400 // appropiate values n1, n2, n3. Note that it must be
401 // checked that this neighbours reallly exist.
402 calculate_shifts_pos_level(mod_pos, zero, l_s, r_s, p_s);
403 if (l_s > splitting_point)
404 {
405 _GLIBCXX_PARALLEL_ASSERT(r_s > splitting_point);
406 if (zero == 1)
407 {
408 r->_M_left = 0;
409 r->_M_right = 0;
410 }
411 else
412 {
413 r->_M_left= r_init[rank.get_shifted_rank(complete_to_original(l_s),iam)];
414 r->_M_right= r_init[rank.get_shifted_rank(complete_to_original(r_s),iam)];
415 }
416
417 }
418 else{
419 r->_M_left= r_init[rank.get_shifted_rank(l_s,iam)];
420 if (zero != 1)
421 {
422 r->_M_right= r_init[rank.get_shifted_rank(complete_to_original(r_s),iam)];
423 }
424 else
425 {
426 r->_M_right = 0;
427 }
428 }
429 r->_M_color = std::_S_black;
430 CALCULATE_PARENT;
431 }
432
433 /** @brief Link a node with its parent and children taking into
434 account that its rank (without gaps) is the same as that in
435 a complete tree
436 * @param r Pointer to the node
437 * @param iam Partition of the array in which the node is, where
438 * iam is in [0..@c num_threads)
439 * @sa link_incomplete
440 */
441 void link_complete(const _Rb_tree_node_ptr& r, const int iam) const
442 {
443 size_type real_pos = rank.get_real_rank(&r-r_init, iam);
444 size_type p_s;
445
446 // Test if it is a leaf on the last not necessarily full level
447 if ((real_pos & mask[0]) == 0)
448 {
449 if ((real_pos & 0x2) == 0)
450 p_s = real_pos + 1;
451 else
452 p_s = real_pos - 1;
453 r->_M_color = std::_S_red;
454 r->_M_left = 0;
455 r->_M_right = 0;
456 }
457 else
458 {
459 size_type l_s, r_s;
460 int zero = first_0_right(real_pos);
461 calculate_shifts_pos_level(real_pos, zero, l_s, r_s, p_s);
462 r->_M_color = std::_S_black;
463
464 r->_M_left = r_init[rank.get_shifted_rank(l_s,iam)];
465 if (r_s > splitting_point)
466 r_s = complete_to_original(r_s);
467 r->_M_right = r_init[rank.get_shifted_rank(r_s,iam)];
468 }
469 CALCULATE_PARENT;
470 }
471
472 #undef CALCULATE_PARENT
473
474 private:
475 /** @brief Change of "base": Convert the rank in the actual tree
476 into the corresponding rank if the tree was complete
477 * @param pos Rank in the actual incomplete tree
478 * @return Rank in the corresponding complete tree
479 * @sa complete_to_original */
480 int original_to_complete(const int pos) const
481 {
482 return (pos << 1) - splitting_point;
483 }
484
485 /** @brief Change of "base": Convert the rank if the tree was
486 complete into the corresponding rank in the actual tree
487 * @param pos Rank in the complete tree
488 * @return Rank in the actual incomplete tree
489 * @sa original_to_complete */
490 int complete_to_original(const int pos) const
491 {
492 return (pos + splitting_point) >> 1;
493 }
494
495
496 /** @brief Calculate the rank in the complete tree of the parent
497 and children of a node
498 * @param pos Rank in the complete tree of the node whose parent
499 * and children rank must be calculated
500 * @param level Tree level in which the node at pos is in
501 * (starting to count at leaves). @pre @c level > 1
502 * @param left_shift Rank in the complete tree of the left child
503 * of pos (out parameter)
504 * @param right_shift Rank in the complete tree of the right
505 * child of pos (out parameter)
506 * @param parent_shift Rank in the complete tree of the parent
507 * of pos (out parameter)
508 */
509 void calculate_shifts_pos_level(const size_type pos, const int level, size_type& left_shift, size_type& right_shift, size_type& parent_shift) const
510 {
511 int stride = 1 << (level -1);
512 left_shift = pos - stride;
513 right_shift = pos + stride;
514 if (((pos >> (level + 1)) & 0x1) == 0)
515 parent_shift = pos + 2*stride;
516 else
517 parent_shift = pos - 2*stride;
518 }
519
520 /** @brief Search for the first 0 bit (growing the weight)
521 * @param x Binary number (corresponding to a rank in the tree)
522 * whose first 0 bit must be calculated
523 * @return Position of the first 0 bit in @c x (starting to
524 * count with 1)
525 */
526 int first_0_right(const size_type x) const
527 {
528 if ((x & 0x2) == 0)
529 return 1;
530 else
531 return first_0_right_bs(x);
532 }
533
534 /** @brief Search for the first 0 bit (growing the weight) using
535 * binary search
536 *
537 * Binary search can be used instead of a naïve loop using the
538 * masks in mask array
539 * @param x Binary number (corresponding to a rank in the tree)
540 * whose first 0 bit must be calculated
541 * @param k_beg Position in which to start searching. By default is 2.
542 * @return Position of the first 0 bit in x (starting to count with 1) */
543 int first_0_right_bs(const size_type x, int k_beg=2) const
544 {
545 int k_end = sizeof(size_type)*8;
546 size_type not_x = x ^ mask[k_end-1];
547 while ((k_end-k_beg) > 1)
548 {
549 int k = k_beg + (k_end-k_beg)/2;
550 if ((not_x & mask[k-1]) != 0)
551 k_end = k;
552 else
553 k_beg = k;
554 }
555 return k_beg;
556 }
557 };
558
559 /***** Dealing with repetitions (EFFICIENCY ISSUE) *****/
560 /** @brief Helper class of nodes_initializer: mind the gaps of an
561 array of nodes.
562 *
563 * Get absolute positions in an array of nodes taking into account
564 * the gaps in it @sa ranker_no_gaps
565 */
566 class ranker_gaps
567 {
568 /** @brief Renaming of tree's size_type */
569 typedef typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::size_type size_type;
570
571 /** @brief Array containing the beginning ranks of all the
572 num_threads partitions just considering the valid nodes, not
573 the gaps */
574 size_type* beg_partition;
575
576 /** @brief Array containing the beginning ranks of all the
577 num_threads partitions considering the valid nodes and the
578 gaps */
579 const size_type* beg_shift_partition;
580
581 /** @brief Array containing the number of accumulated gaps at
582 the beginning of each partition */
583 const size_type* rank_shift;
584
585 /** @brief Number of partitions (and threads that work on it) */
586 const thread_index_t num_threads;
587
588 public:
589 /** @brief Constructor
590 * @param size_p Pointer to the array containing the beginning
591 * ranks of all the @c _num_threads partitions considering the
592 * valid nodes and the gaps
593 * @param shift_r Array containing the number of accumulated
594 * gaps at the beginning of each partition
595 * @param _num_threads Number of partitions (and threads that
596 * work on it) */
597 ranker_gaps(const size_type* size_p, const size_type* shift_r, const thread_index_t _num_threads) :
598 beg_shift_partition(size_p),
599 rank_shift(shift_r),
600 num_threads(_num_threads)
601 {
602 beg_partition = new size_type[num_threads+1];
603 beg_partition[0] = 0;
604 for (int i = 1; i <= num_threads; ++i)
605 {
606 beg_partition[i] = beg_partition[i-1] + (beg_shift_partition[i] - beg_shift_partition[i-1]) - (rank_shift[i] - rank_shift[i-1]);
607
608 }
609
610 // Ghost element, strictly larger than any index requested.
611 ++beg_partition[num_threads];
612 }
613
614 /** @brief Destructor
615 * Needs to be defined to deallocate the dynamic memory that has
616 * been allocated for beg_partition array
617 */
618 ~ranker_gaps()
619 {
620 delete[] beg_partition;
621 }
622
623 /** @brief Convert a rank in the array of nodes considering
624 valid nodes and gaps, to the corresponding considering only
625 the valid nodes
626 * @param pos Rank in the array of nodes considering valid nodes and gaps
627 * @param index Partition which the rank belongs to
628 * @return Rank in the array of nodes considering only the valid nodes
629 * @sa get_shifted_rank
630 */
631 size_type get_real_rank(const size_type pos, const int index) const
632 {
633 return pos - rank_shift[index];
634 }
635
636 /** @brief Inverse of get_real_rank: Convert a rank in the array
637 of nodes considering only valid nodes, to the corresponding
638 considering valid nodes and gaps
639 * @param pos Rank in the array of nodes considering only valid nodes
640 * @param index Partition which the rank is most likely to
641 * belong to (ie. the corresponding if there were no gaps)
642 * @pre 0 <= @c pos <= number_of_distinct_elements
643 * @return Rank in the array of nodes considering valid nodes and gaps
644 * @post 0 <= @c return <= number_of_elements
645 * @sa get_real_rank()
646 */
647 size_type get_shifted_rank(const size_type pos, const int index) const
648 {
649 // Heuristic.
650 if (beg_partition[index] <= pos and pos < beg_partition[index+1])
651 return pos + rank_shift[index];
652 else
653 // Called rarely, do not hinder inlining.
654 return get_shifted_rank_loop(pos,index);
655 }
656
657 /** @brief Helper method of get_shifted_rank: in case the given
658 index in get_shifted_rank is not correct, look for it and
659 then calculate the rank
660 * @param pos Rank in the array of nodes considering only valid nodes
661 * @param index Partition which the rank should have belong to
662 * if there were no gaps
663 * @return Rank in the array of nodes considering valid nodes and gaps
664 */
665 size_type get_shifted_rank_loop(const size_type pos, int index) const
666 {
667 while (pos >= beg_partition[index+1])
668 ++index;
669 while (pos < beg_partition[index])
670 --index;
671 _GLIBCXX_PARALLEL_ASSERT(0 <= index && index < num_threads);
672 return pos + rank_shift[index];
673 }
674 };
675
676 /** @brief Helper class of nodes_initializer: access an array of
677 * nodes with no gaps
678 *
679 * Get absolute positions in an array of nodes taking into account
680 * that there are no gaps in it. @sa ranker_gaps */
681 class ranker_no_gaps
682 {
683 /** @brief Renaming of tree's size_type */
684 typedef typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::size_type size_type;
685
686 public:
687 /** @brief Convert a rank in the array of nodes considering
688 * valid nodes and gaps, to the corresponding considering only
689 * the valid nodes
690 *
691 * As there are no gaps in this case, get_shifted_rank() and
692 * get_real_rank() are synonyms and make no change on pos
693 * @param pos Rank in the array of nodes considering valid nodes and gaps
694 * @param index Partition which the rank belongs to, unused here
695 * @return Rank in the array of nodes considering only the valid nodes */
696 size_type get_real_rank(const size_type pos, const int index) const
697 {
698 return pos;
699 }
700
701 /** @brief Inverse of get_real_rank: Convert a rank in the array
702 * of nodes considering only valid nodes, to the corresponding
703 * considering valid nodes and gaps
704 *
705 * As there are no gaps in this case, get_shifted_rank() and
706 * get_real_rank() are synonyms and make no change on pos
707 * @param pos Rank in the array of nodes considering only valid nodes
708 * @param index Partition which the rank belongs to, unused here
709 * @return Rank in the array of nodes considering valid nodes and gaps
710 */
711 size_type get_shifted_rank(const size_type pos, const int index) const
712 {
713 return pos;
714 }
715 };
716
717
718 /** @brief Helper comparator class: Invert a binary comparator
719 * @param _Comp Comparator to invert
720 * @param _Iterator Iterator to the elements to compare */
721 template<typename _Comp, typename _Iterator>
722 class gr_or_eq
723 {
724 /** @brief Renaming value_type of _Iterator */
725 typedef typename std::iterator_traits<_Iterator>::value_type value_type;
726
727 /** @brief Comparator to be inverted */
728 const _Comp comp;
729
730 public:
731 /** @brief Constructor
732 * @param c Comparator */
733 gr_or_eq(const _Comp& c) : comp(c) { }
734
735 /** @brief Operator()
736 * @param a First value to compare
737 * @param b Second value to compare */
738 bool operator()(const value_type& a, const value_type& b) const
739 {
740 if (not (comp(_KeyOfValue()(a), _KeyOfValue()(b))))
741 return true;
742 return false;
743 }
744 };
745
746 /** @brief Helper comparator class: Passed as a parameter of
747 list_partition to check that a sequence is sorted
748 * @param _InputIterator Iterator to the elements to compare
749 * @param _CompIsSorted Comparator to check for sortedness */
750 template<typename _InputIterator, typename _CompIsSorted>
751 class is_sorted_functor
752 {
753 /** @brief Element to compare with (first parameter of comp) */
754 _InputIterator prev;
755
756 /** @brief Comparator to check for sortedness */
757 const _CompIsSorted comp;
758
759 /** @brief Sum up the history of the operator() of this
760 * comparator class Its value is true if all calls to comp from
761 * this class have returned true. It is false otherwise */
762 bool sorted;
763
764 public:
765 /** @brief Constructor
766 *
767 * Sorted is set to true
768 * @param first Element to compare with the first time the
769 * operator() is called
770 * @param c Comparator to check for sortednes */
771 is_sorted_functor(const _InputIterator first, const _CompIsSorted c)
772 : prev(first), comp(c), sorted(true) { }
773
774 /** @brief Operator() with only one explicit parameter. Updates
775 the class member @c prev and sorted.
776 * @param it Iterator to the element which must be compared to
777 * the element pointed by the the class member @c prev */
778 void operator()(const _InputIterator it)
779 {
780 if (sorted and it != prev and comp(_KeyOfValue()(*it),_KeyOfValue()(*prev)))
781 sorted = false;
782 prev = it;
783 }
784
785 /** @brief Query method for sorted
786 * @return Current value of sorted */
787 bool is_sorted() const
788 {
789 return sorted;
790 }
791 };
792
793 /** @brief Helper functor: sort the input based upon elements
794 instead of keys
795 * @param KeyComparator Comparator for the key of values */
796 template<typename KeyComparator>
797 class ValueCompare
798 : public std::binary_function<value_type, value_type, bool>
799 {
800 /** @brief Comparator for the key of values */
801 const KeyComparator comp;
802
803 public:
804 /** @brief Constructor
805 * @param c Comparator for the key of values */
806 ValueCompare(const KeyComparator& c): comp(c) { }
807
808 /** @brief Operator(): Analogous to comp but for values and not keys
809 * @param v1 First value to compare
810 * @param v2 Second value to compare
811 * @return Result of the comparison */
812 bool operator()(const value_type& v1, const value_type& v2) const
813 { return comp(_KeyOfValue()(v1),_KeyOfValue()(v2)); }
814 };
815
816 /** @brief Helper comparator: compare a key with the key in a node
817 * @param _Comparator Comparator for keys */
818 template<typename _Comparator>
819 struct compare_node_key
820 {
821 /** @brief Comparator for keys */
822 const _Comparator& c;
823
824 /** @brief Constructor
825 * @param _c Comparator for keys */
826 compare_node_key(const _Comparator& _c) : c(_c) { }
827
828 /** @brief Operator() with the first parameter being a node
829 * @param r Node whose key is to be compared
830 * @param k Key to be compared
831 * @return Result of the comparison */
832 bool operator()(const _Rb_tree_node_ptr r, const key_type& k) const
833 { return c(base_type::_S_key(r),k); }
834
835 /** @brief Operator() with the second parameter being a node
836 * @param k Key to be compared
837 * @param r Node whose key is to be compared
838 * @return Result of the comparison */
839 bool operator()(const key_type& k, const _Rb_tree_node_ptr r) const
840 { return c(k, base_type::_S_key(r)); }
841 };
842
843 /** @brief Helper comparator: compare a key with the key of a value pointed by an iterator
844 * @param _Comparator Comparator for keys */
845 template<typename _Iterator, typename _Comparator>
846 struct compare_value_key
847 {
848 /** @brief Comparator for keys */
849 const _Comparator& c;
850
851 /** @brief Constructor
852 * @param _c Comparator for keys */
853 compare_value_key(const _Comparator& _c) : c(_c){ }
854
855 /** @brief Operator() with the first parameter being an iterator
856 * @param v Iterator to the value whose key is to be compared
857 * @param k Key to be compared
858 * @return Result of the comparison */
859 bool operator()(const _Iterator& v, const key_type& k) const
860 { return c(_KeyOfValue()(*v),k); }
861
862 /** @brief Operator() with the second parameter being an iterator
863 * @param k Key to be compared
864 * @param v Iterator to the value whose key is to be compared
865 * @return Result of the comparison */
866 bool operator()(const key_type& k, const _Iterator& v) const
867 { return c(k, _KeyOfValue()(*v)); }
868 };
869
870 /** @brief Helper class of _Rb_tree to avoid some symmetric code
871 in tree operations */
872 struct LeftRight
873 {
874 /** @brief Obtain the conceptual left child of a node
875 * @param parent Node whose child must be obtained
876 * @return Reference to the child node */
877 static _Rb_tree_node_base*& left(_Rb_tree_node_base* parent)
878 { return parent->_M_left; }
879
880 /** @brief Obtain the conceptual right child of a node
881 * @param parent Node whose child must be obtained
882 * @return Reference to the child node */
883 static _Rb_tree_node_base*& right(_Rb_tree_node_base* parent)
884 { return parent->_M_right; }
885 };
886
887 /** @brief Helper class of _Rb_tree to avoid some symmetric code
888 in tree operations: inverse the symmetry
889 * @param S Symmetry to inverse
890 * @sa LeftRight */
891 template<typename S>
892 struct Opposite
893 {
894 /** @brief Obtain the conceptual left child of a node, inversing
895 the symmetry
896 * @param parent Node whose child must be obtained
897 * @return Reference to the child node */
898 static _Rb_tree_node_base*& left(_Rb_tree_node_base* parent)
899 { return S::right(parent);}
900
901 /** @brief Obtain the conceptual right child of a node,
902 inversing the symmetry
903 * @param parent Node whose child must be obtained
904 * @return Reference to the child node */
905 static _Rb_tree_node_base*& right(_Rb_tree_node_base* parent)
906 { return S::left(parent);}
907 };
908
909 /** @brief Inverse symmetry of LeftRight */
910 typedef Opposite<LeftRight> RightLeft;
911
912 /** @brief Helper comparator to compare value pointers, so that
913 the value is taken
914 * @param Comparator Comparator for values
915 * @param _ValuePtr Pointer to values */
916 template<typename Comparator, typename _ValuePtr>
917 class PtrComparator : public std::binary_function<_ValuePtr, _ValuePtr, bool>
918 {
919 /** @brief Comparator for values */
920 Comparator comp;
921
922 public:
923 /** @brief Constructor
924 * @param comp Comparator for values */
925 PtrComparator(Comparator comp) : comp(comp) { }
926
927 /** @brief Operator(): compare the values instead of the pointers
928 * @param v1 Pointer to the first element to compare
929 * @param v2 Pointer to the second element to compare */
930 bool operator()(const _ValuePtr& v1, const _ValuePtr& v2) const
931 { return comp(*v1,*v2); }
932 };
933
934 /** @brief Iterator whose elements are pointers
935 * @param value_type Type pointed by the pointers */
936 template<typename _ValueTp>
937 class PtrIterator
938 {
939 public:
940 /** @brief The iterator category is random access iterator */
941 typedef typename std::random_access_iterator_tag iterator_category;
942 typedef _ValueTp value_type;
943 typedef size_t difference_type;
944 typedef value_type* ValuePtr;
945 typedef ValuePtr& reference;
946 typedef value_type** pointer;
947
948 /** @brief Element accessed by the iterator */
949 value_type** ptr;
950
951 /** @brief Trivial constructor */
952 PtrIterator() { }
953
954 /** @brief Constructor from an element */
955 PtrIterator(const ValuePtr& __i) : ptr(&__i) { }
956
957 /** @brief Constructor from a pointer */
958 PtrIterator(const pointer& __i) : ptr(__i) { }
959
960 /** @brief Copy constructor */
961 PtrIterator(const PtrIterator<value_type>& __i) : ptr(__i.ptr) { }
962
963 reference
964 operator*() const
965 { return **ptr; }
966
967 ValuePtr
968 operator->() const
969 { return *ptr; }
970
971 /** @brief Bidirectional iterator requirement */
972 PtrIterator&
973 operator++()
974 {
975 ++ptr;
976 return *this;
977 }
978
979 /** @brief Bidirectional iterator requirement */
980 PtrIterator
981 operator++(int)
982 { return PtrIterator(ptr++); }
983
984 /** @brief Bidirectional iterator requirement */
985 PtrIterator&
986 operator--()
987 {
988 --ptr;
989 return *this;
990 }
991
992 /** @brief Bidirectional iterator requirement */
993 PtrIterator
994 operator--(int)
995 { return PtrIterator(ptr--); }
996
997 /** @brief Random access iterator requirement */
998 reference
999 operator[](const difference_type& __n) const
1000 { return *ptr[__n]; }
1001
1002 /** @brief Random access iterator requirement */
1003 PtrIterator&
1004 operator+=(const difference_type& __n)
1005 {
1006 ptr += __n;
1007 return *this;
1008 }
1009
1010 /** @brief Random access iterator requirement */
1011 PtrIterator
1012 operator+(const difference_type& __n) const
1013 { return PtrIterator(ptr + __n); }
1014
1015 /** @brief Random access iterator requirement */
1016 PtrIterator&
1017 operator-=(const difference_type& __n)
1018 {
1019 ptr -= __n;
1020 return *this;
1021 }
1022
1023 /** @brief Random access iterator requirement */
1024 PtrIterator
1025 operator-(const difference_type& __n) const
1026 { return PtrIterator(ptr - __n); }
1027
1028 /** @brief Random access iterator requirement */
1029 difference_type
1030 operator-(const PtrIterator<value_type>& iter) const
1031 { return ptr - iter.ptr; }
1032
1033 /** @brief Random access iterator requirement */
1034 difference_type
1035 operator+(const PtrIterator<value_type>& iter) const
1036 { return ptr + iter.ptr; }
1037
1038 /** @brief Allow assignment of an element ValuePtr to the iterator */
1039 PtrIterator<value_type>& operator=(const ValuePtr sptr)
1040 {
1041 ptr = &sptr;
1042 return *this;
1043 }
1044
1045 PtrIterator<value_type>& operator=(const PtrIterator<value_type>& piter)
1046 {
1047 ptr = piter.ptr;
1048 return *this;
1049 }
1050
1051 bool operator==(const PtrIterator<value_type>& piter)
1052 { return ptr == piter.ptr; }
1053
1054 bool operator!=(const PtrIterator<value_type>& piter)
1055 { return ptr != piter.ptr; }
1056
1057 };
1058
1059
1060 /** @brief Bulk insertion helper: synchronization and construction
1061 of the tree bottom up */
1062 struct concat_problem
1063 {
1064 /** @brief Root of a tree.
1065 *
1066 * Input: Middle node to concatenate two subtrees. Out: Root of
1067 * the resulting concatenated tree. */
1068 _Rb_tree_node_ptr t;
1069
1070 /** @brief Black height of @c t */
1071 int black_h;
1072
1073 /** @brief Synchronization variable.
1074 *
1075 * \li READY_YES: the root of the tree can be concatenated with
1076 * the result of the children concatenation problems (both of
1077 * them have finished).
1078 * \li READY_NOT: at least one of the children
1079 * concatenation_problem have not finished */
1080 int is_ready;
1081
1082 /** @brief Parent concatenation problem to solve when @c
1083 is_ready = READY_YES */
1084 concat_problem* par_problem;
1085
1086 /** @brief Left concatenation problem */
1087 concat_problem* left_problem;
1088
1089 /** @brief Right concatenation problem */
1090 concat_problem* right_problem;
1091
1092 /** @brief Value NO for the synchronization variable. */
1093 static const int READY_NO = 0;
1094
1095 /** @brief Value YES for the synchronization variable. */
1096 static const int READY_YES = 1;
1097
1098 /** @brief Trivial constructor.
1099 *
1100 * Initialize the synchronization variable to not ready. */
1101 concat_problem(): is_ready(READY_NO) { }
1102
1103 /** @brief Constructor.
1104 *
1105 * Initialize the synchronization variable to not ready.
1106 * @param _t Root of a tree.
1107 * @param _black_h Black height of @c _t
1108 * @param _par_problem Parent concatenation problem to solve
1109 * when @c is_ready = READY_YES
1110 */
1111 concat_problem(const _Rb_tree_node_ptr _t, const int _black_h, concat_problem* _par_problem):
1112 t(_t),
1113 black_h(_black_h),
1114 is_ready(READY_NO),
1115 par_problem(_par_problem)
1116 {
1117 // The root of an insertion problem must be black.
1118 if (t != NULL and t->_M_color == std::_S_red)
1119 {
1120 t->_M_color = std::_S_black;
1121 ++black_h;
1122 }
1123 }
1124 };
1125
1126
1127 /** @brief Bulk insertion helper: insertion of a sequence of
1128 elements in a subtree
1129 @invariant t, pos_beg and pos_end will not change after initialization
1130 */
1131 struct insertion_problem
1132 {
1133 /** @brief Renaming of _Rb_tree @c size_type */
1134 typedef typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::size_type size_type;
1135
1136 /** @brief Root of the tree where the elements are to be inserted */
1137 _Rb_tree_node_ptr t;
1138
1139 /** @brief Position of the first node in the array of nodes to
1140 be inserted into @c t */
1141 size_type pos_beg;
1142
1143 /** @brief Positition of the first node in the array of nodes
1144 that won't be inserted into @c t */
1145 size_type pos_end;
1146
1147 /** @brief Partition in the array of nodes of @c pos_beg and @c
1148 pos_end (must be the same for both, and so gaps are
1149 avoided) */
1150 int array_partition;
1151
1152 /** @brief Concatenation problem to solve once the insertion
1153 problem is finished */
1154 concat_problem* conc;
1155
1156 /** @brief Trivial constructor. */
1157 insertion_problem()
1158 { }
1159
1160 /** @brief Constructor.
1161 * @param b Position of the first node in the array of nodes to
1162 * be inserted into @c _conc->t
1163 * @param e Position of the first node in the array of nodes
1164 * that won't be inserted into @c _conc->t
1165 * @param array_p Partition in the array of nodes of @c b and @c e
1166 * @param _conc Concatenation problem to solve once the
1167 * insertion problem is finished
1168 */
1169 insertion_problem(const size_type b, const size_type e, const int array_p, concat_problem* _conc)
1170 : t(_conc->t), pos_beg(b), pos_end(e), array_partition(array_p), conc(_conc)
1171 {
1172 _GLIBCXX_PARALLEL_ASSERT(pos_beg <= pos_end);
1173
1174 //The root of an insertion problem must be black!!
1175 _GLIBCXX_PARALLEL_ASSERT(t == NULL or t->_M_color != std::_S_red);
1176 }
1177 };
1178
1179
1180 /** @brief Main bulk construction and insertion helper method
1181 * @param __first First element in a sequence to be added into the tree
1182 * @param __last End of the sequence of elements to be added into the tree
1183 * @param is_construction If true, the tree was empty and so, this
1184 * is constructed. Otherwise, the elements are added to an
1185 * existing tree.
1186 * @param strictly_less_or_less_equal Comparator to deal
1187 * transparently with repetitions with respect to the uniqueness
1188 * of the wrapping container
1189 * The input sequence is preprocessed so that the bulk
1190 * construction or insertion can be performed
1191 * efficiently. Essentially, the sequence is checked for
1192 * sortedness and iterators to the middle of the structure are
1193 * saved so that afterwards the sequence can be processed
1194 * effectively in parallel. */
1195 template<typename _InputIterator, typename StrictlyLessOrLessEqual>
1196 void
1197 _M_bulk_insertion_construction(const _InputIterator __first, const _InputIterator __last, const bool is_construction, StrictlyLessOrLessEqual strictly_less_or_less_equal)
1198 {
1199 Timing<_timing_tag> t;
1200
1201 t.tic();
1202
1203 thread_index_t num_threads = get_max_threads();
1204 size_type n;
1205 size_type beg_partition[num_threads+1];
1206 _InputIterator access[num_threads+1];
1207 beg_partition[0] = 0;
1208 bool is_sorted= is_sorted_distance_accessors(__first, __last, access, beg_partition,n, num_threads, std::__iterator_category(__first));
1209
1210 t.tic("is_sorted");
1211
1212 if (not is_sorted)
1213 {
1214 _M_not_sorted_bulk_insertion_construction(access, beg_partition, n, num_threads, is_construction, strictly_less_or_less_equal);
1215 }
1216 else
1217 {
1218 // The vector must be moved... all ranges must have at least
1219 // one element, or make just sequential???
1220 if (static_cast<size_type>(num_threads) > n)
1221 {
1222 int j = 1;
1223 for (int i = 1; i <= num_threads; ++i)
1224 {
1225 if (beg_partition[j-1] != beg_partition[i])
1226 {
1227 beg_partition[j] = beg_partition[i];
1228 access[j] = access[i];
1229 ++j;
1230 }
1231 }
1232 num_threads = static_cast<thread_index_t>(n);
1233 }
1234
1235 if (is_construction)
1236 _M_sorted_bulk_construction(access, beg_partition, n, num_threads, strictly_less_or_less_equal);
1237 else
1238 _M_sorted_bulk_insertion(access, beg_partition, n, num_threads, strictly_less_or_less_equal);
1239 }
1240
1241 t.tic("main work");
1242
1243 t.print();
1244 }
1245
1246 /** @brief Bulk construction and insertion helper method on an
1247 * input sequence which is not sorted
1248 *
1249 * The elements are copied, according to the copy policy, in order
1250 * to be sorted. Then the
1251 * _M_not_sorted_bulk_insertion_construction() method is called
1252 * appropiately
1253 * @param access Array of iterators of size @c num_threads +
1254 * 1. Each position contains the first element in each subsequence
1255 * to be added into the tree.
1256 * @param beg_partition Array of positions of size @c num_threads
1257 * + 1. Each position contains the rank of the first element in
1258 * each subsequence to be added into the tree.
1259 * @param n Size of the sequence to be inserted
1260 * @param num_threads Number of threads and corresponding
1261 * subsequences in which the insertion work is going to be shared
1262 * @param is_construction If true, the tree was empty and so, this
1263 * is constructed. Otherwise, the elements are added to an
1264 * existing tree.
1265 * @param strictly_less_or_less_equal Comparator to deal transparently with repetitions with respect to the uniqueness of the wrapping container */
1266 template<typename _InputIterator, typename StrictlyLessOrLessEqual>
1267 void
1268 _M_not_sorted_bulk_insertion_construction(_InputIterator* access,
1269 size_type* beg_partition,
1270 const size_type n,
1271 const thread_index_t num_threads,
1272 const bool is_construction,
1273 StrictlyLessOrLessEqual strictly_less_or_less_equal)
1274 {
1275 // Copy entire elements. In the case of a map, we would be
1276 // copying the pair. Therefore, the copy should be reconsidered
1277 // when objects are big. Essentially two cases:
1278 // - The key is small: make that the pair, is a pointer to data
1279 // instead of a copy to it
1280 // - The key is big: we simply have a pointer to the iterator
1281 #if _GLIBCXX_TREE_FULL_COPY
1282 nc_value_type* v = static_cast<nc_value_type*> (::operator new(sizeof(nc_value_type)*(n+1)));
1283
1284 uninitialized_copy_from_accessors(access, beg_partition, v, num_threads);
1285
1286 _M_not_sorted_bulk_insertion_construction<nc_value_type, nc_value_type*, ValueCompare<_Compare> >
1287 (beg_partition, v, ValueCompare<_Compare>(base_type::_M_impl._M_key_compare), n, num_threads, is_construction, strictly_less_or_less_equal);
1288 #else
1289 // For sorting, we cannot use the new PtrIterator because we
1290 // want the pointers to be exchanged and not the elements.
1291 typedef PtrComparator<ValueCompare<_Compare>, nc_value_type*> this_ptr_comparator;
1292 nc_value_type** v = static_cast<nc_value_type**> (::operator new(sizeof(nc_value_type*)*(n+1)));
1293
1294 uninitialized_ptr_copy_from_accessors(access, beg_partition, v, num_threads);
1295
1296 _M_not_sorted_bulk_insertion_construction<nc_value_type*, PtrIterator<nc_value_type>, this_ptr_comparator>
1297 (beg_partition, v, this_ptr_comparator(ValueCompare<_Compare>(base_type::_M_impl._M_key_compare)), n, num_threads, is_construction, strictly_less_or_less_equal);
1298 #endif
1299 }
1300
1301 /** @brief Bulk construction and insertion helper method on an
1302 * input sequence which is not sorted
1303 *
1304 * The elements are sorted and its accessors calculated. Then,
1305 * _M_sorted_bulk_construction() or _M_sorted_bulk_insertion() is
1306 * called.
1307 * @param beg_partition Array of positions of size @c num_threads
1308 * + 1. Each position contains the rank of the first element in
1309 * each subsequence to be added into the tree.
1310 * @param v Array of elements to be sorted (copy of the original sequence).
1311 * @param comp Comparator to be used for sorting the elements
1312 * @param n Size of the sequence to be inserted
1313 * @param num_threads Number of threads and corresponding
1314 * subsequences in which the insertion work is going to be shared
1315 * @param is_construction If true, _M_sorted_bulk_construction()
1316 * is called. Otherwise, _M_sorted_bulk_insertion() is called.
1317 * @param strictly_less_or_less_equal Comparator to deal
1318 * transparently with repetitions with respect to the uniqueness
1319 * of the wrapping container
1320 */
1321 template<typename ElementsToSort, typename IteratorSortedElements, typename Comparator, typename StrictlyLessOrLessEqual>
1322 void
1323 _M_not_sorted_bulk_insertion_construction(size_type* beg_partition, ElementsToSort* v, Comparator comp, const size_type n, thread_index_t num_threads, const bool is_construction, StrictlyLessOrLessEqual strictly_less_or_less_equal)
1324 {
1325 // The accessors have been calculated for the non sorted.
1326 Timing<_timing_tag> t;
1327
1328 t.tic();
1329
1330 num_threads = static_cast<thread_index_t>(std::min<size_type>(num_threads, n));
1331
1332 std::stable_sort(v, v+n, comp);
1333
1334 t.tic("sort");
1335
1336 IteratorSortedElements sorted_access[num_threads+1];
1337 range_accessors(IteratorSortedElements(v), IteratorSortedElements(v+n), sorted_access, beg_partition, n, num_threads, std::__iterator_category(v));
1338
1339 t.tic("range_accessors");
1340
1341 // Partial template specialization not available.
1342 if (is_construction)
1343 _M_sorted_bulk_construction(sorted_access, beg_partition, n, num_threads, strictly_less_or_less_equal);
1344 else
1345 _M_sorted_bulk_insertion(sorted_access, beg_partition, n, num_threads, strictly_less_or_less_equal);
1346 delete v;
1347
1348 t.tic("actual construction or insertion");
1349
1350 t.print();
1351 }
1352
1353 /** @brief Construct a tree sequentially using the parallel routine
1354 * @param r_array Array of nodes from which to take the nodes to
1355 * build the tree
1356 * @param pos_beg Position of the first node in the array of nodes
1357 * to be part of the tree
1358 * @param pos_end Position of the first node in the array of nodes
1359 * that will not be part of the tree
1360 * @param black_h Black height of the resulting tree (out)
1361 */
1362 static _Rb_tree_node_ptr
1363 simple_tree_construct(_Rb_tree_node_ptr* r_array, const size_type pos_beg, const size_type pos_end, int& black_h)
1364 {
1365 if (pos_beg == pos_end)
1366 {
1367 black_h = 0;
1368 return NULL;
1369 }
1370 if (pos_beg+1 == pos_end)
1371 {
1372 // It is needed, not only for efficiency but because the
1373 // last level in our tree construction is red.
1374 make_leaf(r_array[pos_beg], black_h);
1375 return r_array[pos_beg];
1376 }
1377
1378 // Dummy b_p
1379 size_type b_p[2];
1380 b_p[0] = 0;
1381 b_p[1] = pos_end - pos_beg;
1382 _Rb_tree_node_ptr* r= r_array + pos_beg;
1383 size_type length = pos_end - pos_beg;
1384
1385 ranker_no_gaps rank;
1386 nodes_initializer<ranker_no_gaps> nodes_init(r, length, 1, rank);
1387
1388 black_h = nodes_init.get_height();
1389
1390 size_type split = nodes_init.get_shifted_splitting_point();
1391 for (size_type i = 0; i < split; ++i)
1392 nodes_init.link_complete(r[i],0);
1393
1394 for (size_type i = split; i < length; ++i)
1395 nodes_init.link_incomplete(r[i],0);
1396
1397 _Rb_tree_node_ptr t = nodes_init.get_root();
1398 _GLIBCXX_PARALLEL_ASSERT(rb_verify_tree(t));
1399 _GLIBCXX_PARALLEL_ASSERT(t->_M_color == std::_S_black);
1400 return t;
1401 }
1402
1403
1404 /** @brief Allocation of an array of nodes and initilization of
1405 their value fields from an input sequence. Done in parallel.
1406 * @param access Array of iterators of size @c num_threads +
1407 * 1. Each position contains the first value in the subsequence to
1408 * be copied into the corresponding tree node.
1409 * @param beg_partition Array of positions of size @c num_threads
1410 * + 1. Each position contains the rank of the first element in
1411 * the subsequence from which to copy the data to initialize the
1412 * nodes.
1413 * @param n Size of the sequence and the array of nodes to be allocated.
1414 * @param num_threads Number of threads and corresponding
1415 * subsequences in which the allocation and initialization work is
1416 * going to be shared
1417 */
1418 template<typename _Iterator>
1419 _Rb_tree_node_ptr* _M_unsorted_bulk_allocation_and_initialization(const _Iterator* access, const size_type* beg_partition, const size_type n, const thread_index_t num_threads)
1420 {
1421 _Rb_tree_node_ptr* r = static_cast<_Rb_tree_node_ptr*> (::operator new (sizeof(_Rb_tree_node_ptr)*(n+1)));
1422
1423 // Allocate and initialize the nodes (don't check for uniqueness
1424 // because the sequence is not necessarily sorted.
1425 #pragma omp parallel num_threads(num_threads)
1426 {
1427 #if USE_PAPI
1428 PAPI_register_thread();
1429 #endif
1430
1431 int iam = omp_get_thread_num();
1432 _Iterator it = access[iam];
1433 size_type i = beg_partition[iam];
1434 while (it!= access[iam+1])
1435 {
1436 r[i] = base_type::_M_create_node(*it);
1437 ++i;
1438 ++it;
1439 }
1440 }
1441 return r;
1442 }
1443
1444
1445 /** @brief Allocation of an array of nodes and initilization of
1446 * their value fields from an input sequence. Done in
1447 * parallel. Besides, the sequence is checked for uniqueness while
1448 * copying the elements, and if there are repetitions, gaps within
1449 * the partitions are created.
1450 *
1451 * An extra ghost node pointer is reserved in the array to ease
1452 * comparisons later while linking the nodes
1453 * @pre The sequence is sorted.
1454 * @param access Array of iterators of size @c num_threads +
1455 * 1. Each position contains the first value in the subsequence to
1456 * be copied into the corresponding tree node.
1457 * @param beg_partition Array of positions of size @c num_threads
1458 * + 1. Each position contains the rank of the first element in
1459 * the subsequence from which to copy the data to initialize the
1460 * nodes.
1461 * @param rank_shift Array of size @c num_threads + 1 containing
1462 * the number of accumulated gaps at the beginning of each
1463 * partition
1464 * @param n Size of the sequence and the array of nodes (-1) to be
1465 * allocated.
1466 * @param num_threads Number of threads and corresponding
1467 * subsequences in which the allocation and initialization work is
1468 * going to be shared
1469 * @param strictly_less_or_less_equal Comparator to deal
1470 * transparently with repetitions with respect to the uniqueness
1471 * of the wrapping container
1472 */
1473 template<typename _Iterator, typename StrictlyLessOrLessEqual>
1474 _Rb_tree_node_ptr* _M_sorted_bulk_allocation_and_initialization(_Iterator* access, size_type* beg_partition, size_type* rank_shift, const size_type n, thread_index_t& num_threads, StrictlyLessOrLessEqual strictly_less_or_less_equal)
1475 {
1476 // Ghost node at the end to avoid extra comparisons in nodes_initializer.
1477 _Rb_tree_node_ptr* r = static_cast<_Rb_tree_node_ptr*> (::operator new (sizeof(_Rb_tree_node_ptr)*(n+1)));
1478 r[n] = NULL;
1479
1480 // Dealing with repetitions (EFFICIENCY ISSUE).
1481 _Iterator access_copy[num_threads+1];
1482 for (int i = 0; i <= num_threads; ++i)
1483 access_copy[i] = access[i];
1484 // Allocate and initialize the nodes
1485 #pragma omp parallel num_threads(num_threads)
1486 {
1487 #if USE_PAPI
1488 PAPI_register_thread();
1489 #endif
1490 thread_index_t iam = omp_get_thread_num();
1491 _Iterator prev = access[iam];
1492 size_type i = beg_partition[iam];
1493 _Iterator it = prev;
1494 if (iam != 0)
1495 {
1496 --prev;
1497 // Dealing with repetitions (CORRECTNESS ISSUE).
1498 while (it!= access_copy[iam+1] and not strictly_less_or_less_equal(_KeyOfValue()(*prev), _KeyOfValue()(*it)))
1499 {
1500 _GLIBCXX_PARALLEL_ASSERT(not base_type::_M_impl._M_key_compare(_KeyOfValue()(*it),_KeyOfValue()(*prev)));
1501 ++it;
1502 }
1503 access[iam] = it;
1504 if (it != access_copy[iam+1]){
1505 r[i] = base_type::_M_create_node(*it);
1506 ++i;
1507 prev=it;
1508 ++it;
1509 }
1510 //}
1511 }
1512 else
1513 {
1514 r[i] = base_type::_M_create_node(*prev);
1515 ++i;
1516 ++it;
1517 }
1518 while (it!= access_copy[iam+1])
1519 {
1520 /***** Dealing with repetitions (CORRECTNESS ISSUE) *****/
1521 if (strictly_less_or_less_equal(_KeyOfValue()(*prev),_KeyOfValue()(*it)))
1522 {
1523 r[i] = base_type::_M_create_node(*it);
1524 ++i;
1525 prev=it;
1526 }
1527 else{
1528 _GLIBCXX_PARALLEL_ASSERT(not base_type::_M_impl._M_key_compare(_KeyOfValue()(*it),_KeyOfValue()(*prev)));
1529 }
1530 ++it;
1531 }
1532 /***** Dealing with repetitions (EFFICIENCY ISSUE) *****/
1533 rank_shift[iam+1] = beg_partition[iam+1] - i;
1534 }
1535 /***** Dealing with repetitions (EFFICIENCY ISSUE) *****/
1536 rank_shift[0] = 0;
1537 /* Guarantee that there are no empty intervals.
1538 - If an empty interval is found, is joined with the previous one
1539 (the rank_shift of the previous is augmented with all the new
1540 repetitions)
1541 */
1542 thread_index_t i = 1;
1543 while (i <= num_threads and rank_shift[i] != (beg_partition[i] - beg_partition[i-1]))
1544 {
1545 rank_shift[i] += rank_shift[i-1];
1546 ++i;
1547 }
1548 if (i <= num_threads)
1549 {
1550 thread_index_t j = i - 1;
1551 while (true)
1552 {
1553 do
1554 {
1555 rank_shift[j] += rank_shift[i];
1556 ++i;
1557 } while (i <= num_threads and rank_shift[i] == (beg_partition[i] - beg_partition[i-1]));
1558
1559 beg_partition[j] = beg_partition[i-1];
1560 access[j] = access[i-1];
1561 if (i > num_threads) break;
1562 ++j;
1563
1564 // Initialize with the previous.
1565 rank_shift[j] = rank_shift[j-1];
1566 }
1567 num_threads = j;
1568 }
1569 return r;
1570
1571 }
1572
1573 /** @brief Allocation of an array of nodes and initilization of
1574 * their value fields from an input sequence.
1575 *
1576 * The allocation and initialization is done in parallel. Besides,
1577 * the sequence is checked for uniqueness while copying the
1578 * elements. However, in contrast to
1579 * _M_sorted_bulk_allocation_and_initialization(), if there are
1580 * repetitions, no gaps within the partitions are created. To do
1581 * so efficiently, some extra memory is needed to compute a prefix
1582 * sum.
1583 * @pre The sequence is sorted.
1584 * @param access Array of iterators of size @c num_threads +
1585 * 1. Each position contains the first value in the subsequence to
1586 * be copied into the corresponding tree node.
1587 * @param beg_partition Array of positions of size @c num_threads
1588 * + 1. Each position contains the rank of the first element in
1589 * the subsequence from which to copy the data to initialize the
1590 * nodes.
1591 * @param n Size of the sequence and the array of nodes (-1) to be
1592 * allocated.
1593 * @param num_threads Number of threads and corresponding
1594 * subsequences in which the allocation and initialization work is
1595 * going to be shared
1596 * @param strictly_less_or_less_equal Comparator to deal
1597 * transparently with repetitions with respect to the uniqueness
1598 * of the wrapping container
1599 */
1600 template<typename _Iterator, typename StrictlyLessOrLessEqual>
1601 _Rb_tree_node_ptr* _M_sorted_no_gapped_bulk_allocation_and_initialization(_Iterator* access, size_type* beg_partition, size_type& n, const thread_index_t num_threads, StrictlyLessOrLessEqual strictly_less_or_less_equal)
1602 {
1603 size_type* sums = static_cast<size_type*> (::operator new (sizeof(size_type)*n));
1604 // Allocate and initialize the nodes
1605 /* try
1606 {*/
1607 #pragma omp parallel num_threads(num_threads)
1608 {
1609 #if USE_PAPI
1610 PAPI_register_thread();
1611 #endif
1612 int iam = omp_get_thread_num();
1613 _Iterator prev = access[iam];
1614 size_type i = beg_partition[iam];
1615 _Iterator it = prev;
1616 if (iam !=0)
1617 {
1618 --prev;
1619
1620 // First iteration here, to update accessor in case was
1621 // equal to the last element of the previous range
1622
1623 // Dealing with repetitions (CORRECTNESS ISSUE).
1624 if (strictly_less_or_less_equal(_KeyOfValue()(*prev),_KeyOfValue()(*it)))
1625 {
1626 sums[i] = 0;
1627 prev=it;
1628 }
1629 else
1630 {
1631 sums[i] = 1;
1632 }
1633 ++i;
1634 ++it;
1635 }
1636 else
1637 {
1638 sums[i] = 0;
1639 ++i;
1640 ++it;
1641 }
1642 while (it!= access[iam+1])
1643 {
1644 // Dealing with repetitions (CORRECTNESS ISSUE).
1645 if (strictly_less_or_less_equal(_KeyOfValue()(*prev),_KeyOfValue()(*it)))
1646 {
1647 sums[i] = 0;
1648 prev=it;
1649 }
1650 else
1651 sums[i] = 1;
1652 ++i;
1653 ++it;
1654 }
1655 }
1656 // Should be done in parallel.
1657 partial_sum(sums,sums + n, sums);
1658
1659 n -= sums[n-1];
1660 _Rb_tree_node_ptr* r = static_cast<_Rb_tree_node_ptr*> (::operator new (sizeof(_Rb_tree_node_ptr)*(n+1)));
1661 r[n]=0;
1662
1663 #pragma omp parallel num_threads(num_threads)
1664 {
1665 #if USE_PAPI
1666 PAPI_register_thread();
1667 #endif
1668 int iam = omp_get_thread_num();
1669 _Iterator it = access[iam];
1670 size_type i = beg_partition[iam];
1671 size_type j = i;
1672 size_type before = 0;
1673 if (iam > 0)
1674 {
1675 before = sums[i-1];
1676 j -= sums[i-1];
1677 }
1678 beg_partition[iam] = j;
1679 while (it!= access[iam+1])
1680 {
1681 while (it!= access[iam+1] and sums[i]!=before)
1682 {
1683 before = sums[i];
1684 ++i;
1685 ++it;
1686 }
1687 if (it!= access[iam+1])
1688 {
1689 r[j] = base_type::_M_create_node(*it);
1690 ++j;
1691 ++i;
1692 ++it;
1693 }
1694 }
1695
1696 }
1697 beg_partition[num_threads] = n;
1698
1699 // Update beginning of partitions.
1700 ::operator delete(sums);
1701 return r;
1702 }
1703
1704 /** @brief Main bulk construction method: perform the actual
1705 initialization, allocation and finally node linking once the
1706 input sequence has already been preprocessed.
1707 * @param access Array of iterators of size @c num_threads +
1708 * 1. Each position contains the first value in the subsequence to
1709 * be copied into the corresponding tree node.
1710 * @param beg_partition Array of positions of size @c num_threads
1711 * + 1. Each position contains the rank of the first element in
1712 * the subsequence from which to copy the data to initialize the
1713 * nodes.
1714 * @param n Size of the sequence and the array of nodes (-1) to be
1715 * allocated.
1716 * @param num_threads Number of threads and corresponding
1717 * subsequences in which the work is going to be shared
1718 * @param strictly_less_or_less_equal Comparator to deal
1719 * transparently with repetitions with respect to the uniqueness
1720 * of the wrapping container
1721 */
1722 template<typename _Iterator, typename StrictlyLessOrLessEqual>
1723 void
1724 _M_sorted_bulk_construction(_Iterator* access, size_type* beg_partition, const size_type n, thread_index_t num_threads, StrictlyLessOrLessEqual strictly_less_or_less_equal)
1725 {
1726 Timing<_timing_tag> t;
1727
1728 // Dealing with repetitions (EFFICIENCY ISSUE).
1729 size_type rank_shift[num_threads+1];
1730
1731 t.tic();
1732
1733 _Rb_tree_node_ptr* r = _M_sorted_bulk_allocation_and_initialization(access, beg_partition, rank_shift, n, num_threads, strictly_less_or_less_equal);
1734
1735 t.tic("bulk allocation and initialization");
1736
1737 // Link the tree appropiately.
1738 // Dealing with repetitions (EFFICIENCY ISSUE).
1739 ranker_gaps rank(beg_partition, rank_shift, num_threads);
1740 nodes_initializer<ranker_gaps> nodes_init(r, n - rank_shift[num_threads], num_threads, rank);
1741 size_type split = nodes_init.get_shifted_splitting_point();
1742
1743 #pragma omp parallel num_threads(num_threads)
1744 {
1745 #if USE_PAPI
1746 PAPI_register_thread();
1747 #endif
1748 int iam = omp_get_thread_num();
1749 size_type beg = beg_partition[iam];
1750 // Dealing with repetitions (EFFICIENCY ISSUE).
1751 size_type end = beg_partition[iam+1] - (rank_shift[iam+1] - rank_shift[iam]);
1752 if (split >= end)
1753 {
1754 for (size_type i = beg; i < end; ++i)
1755 {
1756 nodes_init.link_complete(r[i],iam);
1757 }
1758 }
1759 else
1760 {
1761 if (split <= beg)
1762 {
1763 for (size_type i = beg; i < end; ++i)
1764 nodes_init.link_incomplete(r[i],iam);
1765 }
1766 else
1767 {
1768 for (size_type i = beg; i < split; ++i)
1769 nodes_init.link_complete(r[i],iam);
1770 for (size_type i = split; i < end; ++i)
1771 nodes_init.link_incomplete(r[i],iam);
1772 }
1773 }
1774 }
1775 // If the execution reachs this point, there has been no
1776 // exception, and so the structure can be initialized.
1777
1778 // Join the tree laid on the array of ptrs with the header node.
1779 // Dealing with repetitions (EFFICIENCY ISSUE).
1780 base_type::_M_impl._M_node_count = n - rank_shift[num_threads];
1781 base_type::_M_impl._M_header._M_left = r[0];
1782 thread_index_t with_element = num_threads;
1783 while ((beg_partition[with_element] - beg_partition[with_element-1]) == (rank_shift[with_element] - rank_shift[with_element-1]))
1784 {
1785 --with_element;
1786 }
1787 base_type::_M_impl._M_header._M_right = r[beg_partition[with_element] - (rank_shift[with_element] - rank_shift[with_element-1]) - 1];
1788 base_type::_M_impl._M_header._M_parent = nodes_init.get_root();
1789 nodes_init.get_root()->_M_parent= &base_type::_M_impl._M_header;
1790
1791 t.tic("linking nodes");
1792 ::operator delete(r);
1793
1794 t.tic("delete array of pointers");
1795 t.print();
1796 }
1797
1798
1799 /** @brief Main bulk insertion method: perform the actual
1800 initialization, allocation and finally insertion once the
1801 input sequence has already been preprocessed.
1802 * @param access Array of iterators of size @c num_threads +
1803 * 1. Each position contains the first value in the subsequence to
1804 * be copied into the corresponding tree node.
1805 * @param beg_partition Array of positions of size @c num_threads
1806 * + 1. Each position contains the rank of the first element in
1807 * the subsequence from which to copy the data to initialize the
1808 * nodes.
1809 * @param k Size of the sequence to be inserted (including the
1810 * possible repeated elements among the sequence itself and
1811 * against those elements already in the tree)
1812 * @param num_threads Number of threads and corresponding
1813 * subsequences in which the work is going to be shared
1814 * @param strictly_less_or_less_equal Comparator to deal
1815 * transparently with repetitions with respect to the uniqueness
1816 * of the wrapping container
1817 */
1818 template<typename _Iterator, typename StrictlyLessOrLessEqual>
1819 void
1820 _M_sorted_bulk_insertion(_Iterator* access, size_type* beg_partition, size_type k, thread_index_t num_threads, StrictlyLessOrLessEqual strictly_less_or_less_equal)
1821 {
1822 _GLIBCXX_PARALLEL_ASSERT((size_type)num_threads <= k);
1823 Timing<_timing_tag> t;
1824
1825 t.tic();
1826
1827 // num_thr-1 problems in the upper part of the tree
1828 // num_thr problems to further parallelize
1829 std::vector<size_type> existing(num_threads,0);
1830 #if _GLIBCXX_TREE_INITIAL_SPLITTING
1831 /***** Dealing with repetitions (EFFICIENCY ISSUE) *****/
1832 size_type rank_shift[num_threads+1];
1833
1834 // Need to create them dynamically because they are so erased
1835 concat_problem* conc[2*num_threads-1];
1836 #endif
1837 _Rb_tree_node_ptr* r;
1838 /***** Dealing with repetitions (EFFICIENCY ISSUE) *****/
1839 if (not strictly_less_or_less_equal(base_type::_S_key(base_type::_M_root()),base_type::_S_key(base_type::_M_root()) ))
1840 {
1841 // Unique container
1842 // Set 1 and 2 could be done in parallel ...
1843 // 1. Construct the nodes with their corresponding data
1844 #if _GLIBCXX_TREE_INITIAL_SPLITTING
1845 r = _M_sorted_bulk_allocation_and_initialization(access, beg_partition, rank_shift, k, num_threads, strictly_less_or_less_equal);
1846 t.tic("bulk allocation and initialization");
1847 #else
1848 r = _M_sorted_no_gapped_bulk_allocation_and_initialization(access, beg_partition, k, num_threads, strictly_less_or_less_equal);
1849 #endif
1850 }
1851 else
1852 {
1853 // Not unique container.
1854 r = _M_unsorted_bulk_allocation_and_initialization(access, beg_partition, k, num_threads);
1855 #if _GLIBCXX_TREE_INITIAL_SPLITTING
1856 // Trivial initialization of rank_shift.
1857 for (int i=0; i <= num_threads; ++i)
1858 rank_shift[i] = 0;
1859 #endif
1860 }
1861 #if _GLIBCXX_TREE_INITIAL_SPLITTING
1862 // Calculate position of last element to be inserted: must be
1863 // done now, or otherwise becomes messy.
1864
1865 /***** Dealing with
1866 repetitions (EFFICIENCY ISSUE) *****/
1867 size_type last = beg_partition[num_threads] - (rank_shift[num_threads] - rank_shift[num_threads - 1]);
1868
1869 t.tic("last element to be inserted");
1870
1871 //2. Split the tree according to access in num_threads parts
1872 //Initialize upper concat_problems
1873 //Allocate them dinamically because they are afterwards so erased
1874 for (int i=0; i < (2*num_threads-1); ++i)
1875 {
1876 conc[i] = new concat_problem ();
1877 }
1878 concat_problem* root_problem = _M_bulk_insertion_initialize_upper_problems(conc, 0, num_threads, NULL);
1879
1880 // The first position of access and the last are ignored, so we
1881 // have exactly num_threads subtrees.
1882 bool before = omp_get_nested();
1883 omp_set_nested(true);
1884 _M_bulk_insertion_split_tree_by_pivot(static_cast<_Rb_tree_node_ptr>(base_type::_M_root()), r, access, beg_partition, rank_shift, 0, num_threads-1, conc, num_threads, strictly_less_or_less_equal);
1885 omp_set_nested(before);
1886
1887 // Construct upper tree with the first elements of ranges if
1888 // they are NULL We cannot do this by default because they could
1889 // be repeated and would not be checked.
1890 size_type r_s = 0;
1891 for (int pos = 1; pos < num_threads; ++pos)
1892 {
1893 _GLIBCXX_PARALLEL_ASSERT(conc[(pos-1)*2]->t == NULL or conc[pos*2-1]->t == NULL or strictly_less_or_less_equal(base_type::_S_key(base_type::_S_maximum(conc[(pos-1)*2]->t)), base_type::_S_key(conc[pos*2-1]->t)));
1894 _GLIBCXX_PARALLEL_ASSERT(conc[pos*2]->t == NULL or conc[pos*2-1]->t == NULL or strictly_less_or_less_equal( base_type::_S_key(conc[pos*2-1]->t), base_type::_S_key(base_type::_S_minimum(conc[pos*2]->t))));
1895 /***** Dealing with repetitions (CORRECTNESS ISSUE) *****/
1896
1897 // The first element of the range is the root.
1898 if (conc[pos*2-1]->t == NULL or (not(strictly_less_or_less_equal(base_type::_S_key(static_cast<_Rb_tree_node_ptr>(conc[pos*2-1]->t)), _KeyOfValue()(*access[pos])))))
1899 {
1900 // There was not a candidate element
1901 // or
1902 // Exists an initialized position in the array which
1903 // corresponds to conc[pos*2-1]->t */
1904 if (conc[pos*2-1]->t == NULL)
1905 {
1906 size_t np = beg_partition[pos];
1907 _GLIBCXX_PARALLEL_ASSERT(conc[(pos-1)*2]->t == NULL or strictly_less_or_less_equal(base_type::_S_key(base_type::_S_maximum(conc[(pos-1)*2]->t)), base_type::_S_key(r[np])));
1908 _GLIBCXX_PARALLEL_ASSERT(conc[pos*2]->t == NULL or strictly_less_or_less_equal( base_type::_S_key(r[np]), base_type::_S_key(base_type::_S_minimum(conc[pos*2]->t))));
1909 conc[pos*2-1]->t = r[np];
1910 r[np]->_M_color = std::_S_black;
1911 ++base_type::_M_impl._M_node_count;
1912 }
1913 else
1914 {
1915 base_type::_M_destroy_node(r[beg_partition[pos]]);
1916 }
1917 ++(access[pos]);
1918 ++(beg_partition[pos]);
1919 ++r_s;
1920 }
1921 _GLIBCXX_PARALLEL_ASSERT(conc[(pos-1)*2]->t == NULL or conc[(pos-1)*2]->t->_M_color == std::_S_black);
1922 /***** Dealing with repetitions (EFFICIENCY ISSUE) *****/
1923 rank_shift[pos] += r_s;
1924 }
1925 /***** Dealing with repetitions (EFFICIENCY ISSUE) *****/
1926 rank_shift[num_threads] += r_s;
1927 #else
1928 concat_problem root_problem_on_stack(static_cast<_Rb_tree_node_ptr>(base_type::_M_root()), black_height(static_cast<_Rb_tree_node_ptr>(base_type::_M_root())), NULL);
1929 concat_problem * root_problem = &root_problem_on_stack;
1930 size_type last = k;
1931 #endif
1932
1933 t.tic("sorted_no_gapped...");
1934
1935 // 3. Split the range according to tree and create
1936 // 3. insertion/concatenation problems to be solved in parallel
1937 #if _GLIBCXX_TREE_DYNAMIC_BALANCING
1938 size_type min_problem = (k/num_threads) / (log2(k/num_threads + 1)+1);
1939 #else
1940 size_type min_problem = base_type::size() + k;
1941 #endif
1942
1943 RestrictedBoundedConcurrentQueue<insertion_problem>* ins_problems[num_threads];
1944
1945 #pragma omp parallel num_threads(num_threads)
1946 {
1947 int num_thread = omp_get_thread_num();
1948 ins_problems[num_thread] = new RestrictedBoundedConcurrentQueue<insertion_problem>(2*(log2(base_type::size())+1));
1949 #if _GLIBCXX_TREE_INITIAL_SPLITTING
1950 /***** Dealing with repetitions (EFFICIENCY ISSUE) *****/
1951 size_type end_k_thread = beg_partition[num_thread+1] - (rank_shift[num_thread+1] - rank_shift[num_thread]);
1952 ins_problems[num_thread]->push_front(insertion_problem(beg_partition[num_thread], end_k_thread, num_thread, conc[num_thread*2]));
1953 #else
1954 // size_type end_k_thread = beg_partition[num_thread+1];
1955 #endif
1956 insertion_problem ip_to_solve;
1957 bool change;
1958
1959 #if _GLIBCXX_TREE_INITIAL_SPLITTING
1960 #pragma omp barrier
1961 #else
1962 #pragma omp single
1963 ins_problems[num_thread]->push_front(insertion_problem(0, k, num_thread, root_problem));
1964 #endif
1965
1966 do
1967 {
1968 // First do own work.
1969 while (ins_problems[num_thread]->pop_front(ip_to_solve))
1970 {
1971 _GLIBCXX_PARALLEL_ASSERT(ip_to_solve.pos_beg <= ip_to_solve.pos_end);
1972 _M_bulk_insertion_split_sequence(r, ins_problems[num_thread], ip_to_solve, existing[num_thread], min_problem, strictly_less_or_less_equal);
1973
1974 }
1975 yield();
1976 change = false;
1977
1978 //Then, try to steal from others (and become own).
1979 for (int i=1; i<num_threads; ++i)
1980 {
1981 if (ins_problems[(num_thread+i)%num_threads]->pop_back(ip_to_solve))
1982 {
1983 change = true;
1984 _M_bulk_insertion_split_sequence(r, ins_problems[num_thread], ip_to_solve, existing[num_thread], min_problem, strictly_less_or_less_equal);
1985 break;
1986 }
1987 }
1988 } while (change);
1989 }
1990
1991 t.tic("merging");
1992
1993 // Update root and sizes.
1994 base_type::_M_root() = root_problem->t;
1995 root_problem->t->_M_parent = &(base_type::_M_impl._M_header);
1996 /***** Dealing with repetitions (EFFICIENCY ISSUE) *****/
1997
1998 // Add the k elements that wanted to be inserted, minus the ones
1999 // that were repeated.
2000 #if _GLIBCXX_TREE_INITIAL_SPLITTING
2001 base_type::_M_impl._M_node_count += (k - (rank_shift[num_threads]));
2002 #else
2003 base_type::_M_impl._M_node_count += k;
2004 #endif
2005 // Also then, take out the ones that were already existing in the tree.
2006 for (int i = 0; i< num_threads; ++i)
2007 {
2008 base_type::_M_impl._M_node_count -= existing[i];
2009 }
2010 // Update leftmost and rightmost.
2011 /***** Dealing with repetitions (EFFICIENCY ISSUE) *****/
2012 if (not strictly_less_or_less_equal(base_type::_S_key(base_type::_M_root()), base_type::_S_key(base_type::_M_root()))){
2013 // Unique container.
2014 if (base_type::_M_impl._M_key_compare(_KeyOfValue()(*(access[0])), base_type::_S_key(base_type::_M_leftmost())))
2015 base_type::_M_leftmost() = r[0];
2016 if (base_type::_M_impl._M_key_compare(base_type::_S_key(base_type::_M_rightmost()), _KeyOfValue()(*(--access[num_threads]))))
2017 base_type::_M_rightmost() = r[last - 1];
2018 }
2019 else{
2020 if (strictly_less_or_less_equal(_KeyOfValue()(*(access[0])), base_type::_S_key(base_type::_M_leftmost())))
2021 base_type::_M_leftmost() = base_type::_S_minimum(base_type::_M_root());
2022 if (strictly_less_or_less_equal(base_type::_S_key(base_type::_M_rightmost()), _KeyOfValue()(*(--access[num_threads]))))
2023 base_type::_M_rightmost() = base_type::_S_maximum(base_type::_M_root());
2024 }
2025
2026
2027
2028
2029 #if _GLIBCXX_TREE_INITIAL_SPLITTING
2030 // Delete root problem
2031 delete root_problem;
2032 #endif
2033
2034 // Delete queues
2035 for (int pos = 0; pos < num_threads; ++pos)
2036 {
2037 delete ins_problems[pos];
2038 }
2039
2040 // Delete array of pointers
2041 ::operator delete(r);
2042
2043 t.tic();
2044 t.print();
2045 }
2046
2047
2048 /** @brief Divide a tree according to the splitter elements of a
2049 * given sequence.
2050 *
2051 * The tree of the intial recursive call is divided in exactly
2052 * num_threads partitions, some of which may be empty. Besides,
2053 * some nodes may be extracted from it to afterwards concatenate
2054 * the subtrees resulting from inserting the elements into it.
2055 * This is done sequentially. It could be done in parallel but the
2056 * performance is much worse.
2057 * @param t Root of the tree to be splitted
2058 * @param r Array of nodes to be inserted into the tree (here only
2059 * used to look up its elements)
2060 * @param access Array of iterators of size @c num_threads +
2061 * 1. Each position contains the first value in the subsequence
2062 * that has been copied into the corresponding tree node.
2063 * @param beg_partition Array of positions of size @c num_threads
2064 * + 1. Each position contains the rank of the first element in
2065 * the array of nodes to be inserted.
2066 * @param rank_shift Array of size @c num_threads + 1 containing
2067 * the number of accumulated gaps at the beginning of each
2068 * partition
2069 * @param pos_beg First position in the access array to be
2070 * considered to split @c t
2071 * @param pos_end Last position (included) in the access array to
2072 * be considered to split @c t
2073 * @param conc Array of concatenation problems to be initialized
2074 * @param num_threads Number of threads and corresponding
2075 * subsequences in which the original sequence has been
2076 * partitioned
2077 * @param strictly_less_or_less_equal Comparator to deal
2078 * transparently with repetitions with respect to the uniqueness
2079 * of the wrapping container
2080 */
2081 template<typename _Iterator, typename StrictlyLessOrLessEqual>
2082 void
2083 _M_bulk_insertion_split_tree_by_pivot(_Rb_tree_node_ptr t, _Rb_tree_node_ptr* r, _Iterator* access, size_type* beg_partition, size_type* rank_shift, const size_type pos_beg, const size_type pos_end, concat_problem** conc, const thread_index_t num_threads, StrictlyLessOrLessEqual strictly_less_or_less_equal)
2084 {
2085 if (pos_beg == pos_end)
2086 {
2087 //Elements are in [pos_beg, pos_end]
2088 conc[pos_beg*2]->t = t;
2089 conc[pos_beg*2]->black_h = black_height(t);
2090 force_black_root (conc[pos_beg*2]->t, conc[pos_beg*2]->black_h);
2091 return;
2092 }
2093 if (t == 0)
2094 {
2095 for (size_type i = pos_beg; i < pos_end; ++i)
2096 {
2097 conc[i*2]->t = NULL;
2098 conc[i*2]->black_h = 0;
2099 conc[i*2+1]->t = NULL;
2100 }
2101 conc[pos_end*2]->t = NULL;
2102 conc[pos_end*2]->black_h = 0;
2103 return;
2104 }
2105
2106 // Return the last pos, in which key >= (pos-1).
2107 // Search in the range [pos_beg, pos_end]
2108 size_type pos = std::upper_bound(access + pos_beg, access + pos_end + 1, base_type::_S_key(t), compare_value_key<_Iterator, _Compare>(base_type::_M_impl._M_key_compare)) - access;
2109 if (pos != pos_beg)
2110 {
2111 --pos;
2112 }
2113 _GLIBCXX_PARALLEL_ASSERT(pos == 0 or not base_type::_M_impl._M_key_compare(base_type::_S_key(t), _KeyOfValue()(*access[pos])));
2114
2115
2116 _Rb_tree_node_ptr ll, lr;
2117 int black_h_ll, black_h_lr;
2118 _Rb_tree_node_ptr rl, rr;
2119 int black_h_rl, black_h_rr;
2120
2121 if (pos != pos_beg)
2122 {
2123 _Rb_tree_node_ptr prev = r[beg_partition[pos] - 1 - (rank_shift[pos] - rank_shift[pos - 1])];
2124
2125 _GLIBCXX_PARALLEL_ASSERT(strictly_less_or_less_equal(base_type::_S_key(prev), _KeyOfValue()(*access[pos])));
2126
2127 split(static_cast<_Rb_tree_node_ptr>(t->_M_left),
2128 static_cast<const key_type&>(_KeyOfValue()(*access[pos])),
2129 static_cast<const key_type&>(base_type::_S_key(prev)),
2130 conc[pos*2-1]->t, ll, lr, black_h_ll, black_h_lr,
2131 strictly_less_or_less_equal);
2132
2133 _M_bulk_insertion_split_tree_by_pivot(ll, r, access, beg_partition, rank_shift, pos_beg, pos-1, conc,num_threads, strictly_less_or_less_equal);
2134 }
2135 else
2136 {
2137 lr = static_cast<_Rb_tree_node_ptr>(t->_M_left);
2138 black_h_lr = black_height (lr);
2139 force_black_root (lr, black_h_lr);
2140 }
2141
2142 if (pos != pos_end)
2143 {
2144 _Rb_tree_node_ptr prev = r[beg_partition[pos+1] - 1 - (rank_shift[pos+1] - rank_shift[pos])];
2145
2146 _GLIBCXX_PARALLEL_ASSERT(not base_type::_M_impl._M_key_compare(_KeyOfValue()(*access[pos+1]), base_type::_S_key(prev)));
2147 _GLIBCXX_PARALLEL_ASSERT(strictly_less_or_less_equal(base_type::_S_key(prev), _KeyOfValue()(*access[pos+1])));
2148
2149 split(static_cast<_Rb_tree_node_ptr>(t->_M_right),
2150 static_cast<const key_type&>(_KeyOfValue()(*access[pos+1])),
2151 static_cast<const key_type&>(base_type::_S_key(prev)),
2152 conc[pos*2+1]->t, rl, rr, black_h_rl, black_h_rr,
2153 strictly_less_or_less_equal);
2154
2155 _M_bulk_insertion_split_tree_by_pivot(rr, r, access, beg_partition, rank_shift, pos+1, pos_end, conc,num_threads, strictly_less_or_less_equal);
2156 }
2157 else
2158 {
2159 rl = static_cast<_Rb_tree_node_ptr>(t->_M_right);
2160 black_h_rl = black_height (rl);
2161 force_black_root (rl, black_h_rl);
2162 }
2163
2164 // When key(t) is equal to key(access[pos]) and no other key in
2165 // the left tree satisfies the criteria to be conc[pos*2-1]->t,
2166 // key(t) must be assigned to it to avoid repetitions.
2167 // Therefore, we do not have a root parameter for the
2168 // concatenate function and a new concatenate function must be
2169 // provided.
2170 if (pos != pos_beg and conc[pos*2-1]->t == NULL and not strictly_less_or_less_equal(_KeyOfValue()(*access[pos]), base_type::_S_key(t)))
2171 {
2172 conc[pos*2-1]->t = t;
2173 t = NULL;
2174 }
2175 concatenate(t, lr, rl, black_h_lr, black_h_rl, conc[pos*2]->t, conc[pos*2]->black_h);
2176 }
2177
2178 /** @brief Divide the insertion problem until a leaf is reached or
2179 * the problem is small.
2180 *
2181 * During the recursion, the right subproblem is queued, so that
2182 * it can be handled by any thread. The left subproblem is
2183 * divided recursively, and finally, solved right away
2184 * sequentially.
2185 * @param r Array of nodes containing the nodes to added into the tree
2186 * @param ins_problems Pointer to a queue of insertion
2187 * problems. The calling thread owns this queue, i.e. it is the
2188 * only one to push elements, but other threads could pop elements
2189 * from it in other methods.
2190 * @param ip Current insertion problem to be solved
2191 * @param existing Number of existing elements found when solving
2192 * the insertion problem (out)
2193 * @param min_problem Threshold size on the size of the insertion
2194 * problem in which to stop recursion
2195 * @param strictly_less_or_less_equal Comparator to deal
2196 * transparently with repetitions with respect to the uniqueness
2197 * of the wrapping container
2198 */
2199 template<typename StrictlyLessOrLessEqual>
2200 void
2201 _M_bulk_insertion_split_sequence(_Rb_tree_node_ptr* r, RestrictedBoundedConcurrentQueue<insertion_problem>* ins_problems, insertion_problem& ip, size_type& existing, const size_type min_problem, StrictlyLessOrLessEqual strictly_less_or_less_equal)
2202 {
2203 _GLIBCXX_PARALLEL_ASSERT(ip.t == ip.conc->t);
2204 if (ip.t == NULL or (ip.pos_end- ip.pos_beg) <= min_problem)
2205 {
2206 // SOLVE PROBLEM SEQUENTIALLY
2207 // Start solving the problem.
2208 _GLIBCXX_PARALLEL_ASSERT(ip.pos_beg <= ip.pos_end);
2209 _M_bulk_insertion_merge_concatenate(r, ip, existing, strictly_less_or_less_equal);
2210 return;
2211 }
2212
2213 size_type pos_beg_right;
2214 size_type pos_end_left = divide(r, ip.pos_beg, ip.pos_end, base_type::_S_key(ip.t), pos_beg_right, existing, strictly_less_or_less_equal);
2215
2216 int black_h_l, black_h_r;
2217 if (ip.t->_M_color == std::_S_black)
2218 {
2219 black_h_l = black_h_r = ip.conc->black_h - 1;
2220 }
2221 else
2222 {
2223 black_h_l = black_h_r = ip.conc->black_h;
2224 }
2225
2226 // Right problem into the queue.
2227 ip.conc->right_problem = new concat_problem(static_cast<_Rb_tree_node_ptr>(ip.t->_M_right), black_h_r, ip.conc);
2228 ip.conc->left_problem = new concat_problem(static_cast<_Rb_tree_node_ptr>(ip.t->_M_left), black_h_l, ip.conc);
2229
2230 ins_problems->push_front(insertion_problem(pos_beg_right, ip.pos_end, ip.array_partition, ip.conc->right_problem));
2231
2232 // Solve left problem.
2233 insertion_problem ip_left(ip.pos_beg, pos_end_left, ip.array_partition, ip.conc->left_problem);
2234 _M_bulk_insertion_split_sequence(r, ins_problems, ip_left, existing, min_problem, strictly_less_or_less_equal);
2235 }
2236
2237
2238 /** @brief Insert a sequence of elements into a tree using a
2239 * divide-and-conquer scheme.
2240 *
2241 * The problem is solved recursively and sequentially dividing the
2242 * sequence to be inserted according to the root of the tree. This
2243 * is done until a leaf is reached or the proportion of elements
2244 * to be inserted is small. Finally, the two resulting trees are
2245 * concatenated.
2246 * @param r_array Array of nodes containing the nodes to be added
2247 * into the tree (among others)
2248 * @param t Root of the tree
2249 * @param pos_beg Position of the first node in the array of
2250 * nodes to be inserted into the tree
2251 * @param pos_end Position of the first node in the array of
2252 * nodes that will not be inserted into the tree
2253 * @param existing Number of existing elements found while
2254 * inserting the range [@c pos_beg, @c pos_end) (out)
2255 * @param black_h Height of the tree @c t and of the resulting
2256 * tree after the recursive calls (in and out)
2257 * @param strictly_less_or_less_equal Comparator to deal
2258 * transparently with repetitions with respect to the uniqueness
2259 * of the wrapping container
2260 * @return Resulting tree after the elements have been inserted
2261 */
2262 template<typename StrictlyLessOrLessEqual>
2263 _Rb_tree_node_ptr _M_bulk_insertion_merge(_Rb_tree_node_ptr* r_array, _Rb_tree_node_ptr t, const size_type pos_beg, const size_type pos_end, size_type& existing, int& black_h, StrictlyLessOrLessEqual strictly_less_or_less_equal)
2264 {
2265 #ifndef NDEBUG
2266 int count;
2267 #endif
2268 _GLIBCXX_PARALLEL_ASSERT(pos_beg<=pos_end);
2269
2270 // Leaf: a tree with the range must be constructed. Returns its
2271 // height in black nodes and its root (in ip.t) If there is
2272 // nothing to insert, we still need the height for balancing.
2273 if (t == NULL)
2274 {
2275 if (pos_end == pos_beg) return NULL;
2276 t = simple_tree_construct(r_array,pos_beg, pos_end, black_h);
2277 _GLIBCXX_PARALLEL_ASSERT(rb_verify_tree(t,count));
2278 return t;
2279 }
2280 if (pos_end == pos_beg)
2281 return t;
2282 if ((pos_end - pos_beg) <= (size_type)(black_h))
2283 {
2284 // Exponential size tree with respect the number of elements
2285 // to be inserted.
2286 for (size_type p = pos_beg; p < pos_end; ++p)
2287 {
2288 t = _M_insert_local(t, r_array[p], existing, black_h, strictly_less_or_less_equal);
2289 }
2290 _GLIBCXX_PARALLEL_ASSERT(rb_verify_tree(t,count));
2291 return t;
2292 }
2293
2294 size_type pos_beg_right;
2295 size_type pos_end_left = divide(r_array, pos_beg, pos_end, base_type::_S_key(t), pos_beg_right, existing, strictly_less_or_less_equal);
2296
2297
2298 int black_h_l, black_h_r;
2299 if (t->_M_color == std::_S_black)
2300 {
2301 black_h_l = black_h_r = black_h - 1;
2302 }
2303 else
2304 {
2305 black_h_l = black_h_r = black_h;
2306 }
2307 force_black_root(t->_M_left, black_h_l);
2308 _Rb_tree_node_ptr l = _M_bulk_insertion_merge(r_array, static_cast<_Rb_tree_node_ptr>(t->_M_left), pos_beg, pos_end_left, existing, black_h_l, strictly_less_or_less_equal);
2309 force_black_root(t->_M_right, black_h_r);
2310 _Rb_tree_node_ptr r = _M_bulk_insertion_merge(r_array, static_cast<_Rb_tree_node_ptr>(t->_M_right), pos_beg_right, pos_end, existing, black_h_r, strictly_less_or_less_equal);
2311
2312 concatenate(t, l, r, black_h_l, black_h_r, t, black_h);
2313
2314 return t;
2315 }
2316
2317 /** @brief Solve a given insertion problem and all the parent
2318 * concatenation problem that are ready to be solved.
2319 *
2320 * First, solve an insertion problem.
2321
2322 * Then, check if it is possible to solve the parent
2323 * concatenation problem. If this is the case, solve it and go
2324 * up recursively, as far as possible. Quit otherwise.
2325 *
2326 * @param r Array of nodes containing the nodes to be added into
2327 * the tree (among others)
2328 * @param ip Insertion problem to solve initially.
2329 * @param existing Number of existing elements found while
2330 * inserting the range defined by the insertion problem (out)
2331 * @param strictly_less_or_less_equal Comparator to deal
2332 * transparently with repetitions with respect to the uniqueness
2333 * of the wrapping container
2334 */
2335 template<typename StrictlyLessOrLessEqual>
2336 void _M_bulk_insertion_merge_concatenate(_Rb_tree_node_ptr* r, insertion_problem& ip, size_type& existing, StrictlyLessOrLessEqual strictly_less_or_less_equal)
2337 {
2338 concat_problem* conc = ip.conc;
2339 _GLIBCXX_PARALLEL_ASSERT(ip.pos_beg <= ip.pos_end);
2340
2341 conc->t = _M_bulk_insertion_merge(r, ip.t, ip.pos_beg, ip.pos_end, existing, conc->black_h, strictly_less_or_less_equal);
2342 _GLIBCXX_PARALLEL_ASSERT(conc->t == NULL or conc->t->_M_color == std::_S_black);
2343
2344 bool is_ready = true;
2345 while (conc->par_problem != NULL and is_ready)
2346 {
2347 // Pre: exists left and right problem, so there is not a deadlock
2348 if (compare_and_swap(&conc->par_problem->is_ready, concat_problem::READY_NO, concat_problem::READY_YES))
2349 is_ready = false;
2350
2351 if (is_ready)
2352 {
2353 conc = conc->par_problem;
2354 _GLIBCXX_PARALLEL_ASSERT(conc->left_problem!=NULL and conc->right_problem!=NULL);
2355 _GLIBCXX_PARALLEL_ASSERT (conc->left_problem->black_h >=0 and conc->right_problem->black_h>=0);
2356 // Finished working with the problems.
2357 concatenate(conc->t, conc->left_problem->t, conc->right_problem->t, conc->left_problem->black_h, conc->right_problem->black_h, conc->t, conc->black_h);
2358
2359 delete conc->left_problem;
2360 delete conc->right_problem;
2361 }
2362 }
2363 }
2364
2365 // Begin of sorting, searching and related comparison-based helper methods.
2366
2367 /** @brief Check whether a random-access sequence is sorted, and
2368 * calculate its size.
2369 *
2370 * @param __first Begin iterator of sequence.
2371 * @param __last End iterator of sequence.
2372 * @param dist Size of the sequence (out)
2373 * @return sequence is sorted. */
2374 template<typename _RandomAccessIterator>
2375 bool
2376 is_sorted_distance(const _RandomAccessIterator __first, const _RandomAccessIterator __last, size_type& dist, std::random_access_iterator_tag) const
2377 {
2378 gr_or_eq<_Compare, _RandomAccessIterator> geq(base_type::_M_impl._M_key_compare);
2379 dist = __last - __first;
2380
2381 // In parallel.
2382 return equal(__first + 1, __last, __first, geq);
2383 }
2384
2385 /** @brief Check whether an input sequence is sorted, and
2386 * calculate its size.
2387 *
2388 * The list partitioning tool is used so that all the work is
2389 * done in only one traversal.
2390 * @param __first Begin iterator of sequence.
2391 * @param __last End iterator of sequence.
2392 * @param dist Size of the sequence (out)
2393 * @return sequence is sorted. */
2394 template<typename _InputIterator>
2395 bool
2396 is_sorted_distance(const _InputIterator __first, const _InputIterator __last, size_type& dist, std::input_iterator_tag) const
2397 {
2398 dist = 1;
2399 bool is_sorted = true;
2400 _InputIterator it = __first;
2401 _InputIterator prev = it++;
2402 while (it != __last)
2403 {
2404 ++dist;
2405 if (base_type::_M_impl._M_key_compare(_KeyOfValue()(*it),_KeyOfValue()(*prev)))
2406 {
2407 is_sorted = false;
2408 ++it;
2409 break;
2410 }
2411 prev = it;
2412 ++it;
2413 }
2414 while (it != __last)
2415 {
2416 ++dist;
2417 ++it;
2418 }
2419 return is_sorted;
2420 }
2421
2422 /** @brief Check whether a random-access sequence is sorted,
2423 * calculate its size, and obtain intermediate accessors to the
2424 * sequence to ease parallelization.
2425 *
2426 * @param __first Begin iterator of sequence.
2427 * @param __last End iterator of sequence.
2428 * @param access Array of size @c num_pieces + 1 that defines @c
2429 * num_pieces subsequences of the original sequence (out). Each
2430 * position @c i will contain an iterator to the first element in
2431 * the subsequence @c i.
2432 * @param beg_partition Array of size @c num_pieces + 1 that
2433 * defines @c num_pieces subsequences of the original sequence
2434 * (out). Each position @c i will contain the rank of the first
2435 * element in the subsequence @c i.
2436 * @param dist Size of the sequence (out)
2437 * @param num_pieces Number of pieces to generate.
2438 * @return Sequence is sorted. */
2439 template<typename _RandomAccessIterator>
2440 bool
2441 is_sorted_distance_accessors(const _RandomAccessIterator __first, const _RandomAccessIterator __last, _RandomAccessIterator* access, size_type* beg_partition, size_type& dist, thread_index_t& num_pieces, std::random_access_iterator_tag) const
2442 {
2443 bool is_sorted = is_sorted_distance(__first, __last, dist,std::__iterator_category(__first));
2444 if (dist < (unsigned int) num_pieces)
2445 num_pieces = dist;
2446
2447 // Do it opposite way to use accessors in equal function???
2448 range_accessors(__first,__last, access, beg_partition, dist, num_pieces, std::__iterator_category(__first));
2449 return is_sorted;
2450 }
2451
2452 /** @brief Check whether an input sequence is sorted, calculate
2453 * its size, and obtain intermediate accessors to the sequence to
2454 * ease parallelization.
2455 *
2456 * The list partitioning tool is used so that all the work is
2457 * done in only one traversal.
2458 * @param __first Begin iterator of sequence.
2459 * @param __last End iterator of sequence.
2460 * @param access Array of size @c num_pieces + 1 that defines @c
2461 * num_pieces subsequences of the original sequence (out). Each
2462 * position @c i will contain an iterator to the first element in
2463 * the subsequence @c i.
2464 * @param beg_partition Array of size @c num_pieces + 1 that
2465 * defines @c num_pieces subsequences of the original sequence
2466 * (out). Each position @c i will contain the rank of the first
2467 * element in the subsequence @c i.
2468 * @param dist Size of the sequence (out)
2469 * @param num_pieces Number of pieces to generate.
2470 * @return Sequence is sorted. */
2471 template<typename _InputIterator>
2472 bool
2473 is_sorted_distance_accessors(const _InputIterator __first, const _InputIterator __last, _InputIterator* access, size_type* beg_partition, size_type& dist, thread_index_t& num_pieces, std::input_iterator_tag) const
2474 {
2475 is_sorted_functor<_InputIterator, _Compare> sorted(__first, base_type::_M_impl._M_key_compare);
2476 dist = list_partition(__first, __last, access, (beg_partition+1), num_pieces, sorted, 0);
2477
2478 // Calculate the rank of the begining each partition from the
2479 // sequence sizes (what is stored at this point in beg_partition
2480 // array).
2481 beg_partition[0] = 0;
2482 for (int i = 0; i < num_pieces; ++i)
2483 {
2484 beg_partition[i+1] += beg_partition[i];
2485 }
2486
2487 return sorted.is_sorted();
2488 }
2489
2490 /** @brief Make a full copy of the elements of a sequence
2491 *
2492 * The unitialized_copy method from the stl is called in parallel
2493 * using the access array to point to the beginning of each
2494 * partition
2495 * @param access Array of size @c num_threads + 1 that defines @c
2496 * num_threads subsequences. Each position @c i contains an
2497 * iterator to the first element in the subsequence @c i.
2498 * @param beg_partition Array of size @c num_threads + 1 that
2499 * defines @c num_threads subsequences. Each position @c i
2500 * contains the rank of the first element in the subsequence @c
2501 * i.
2502 * @param out Begin iterator of output sequence.
2503 * @param num_threads Number of threads to use. */
2504 template<typename _InputIterator, typename _OutputIterator>
2505 static void
2506 uninitialized_copy_from_accessors(_InputIterator* access, size_type* beg_partition, _OutputIterator out, const thread_index_t num_threads)
2507 {
2508 #pragma omp parallel num_threads(num_threads)
2509 {
2510 int iam = omp_get_thread_num();
2511 uninitialized_copy(access[iam], access[iam+1], out+beg_partition[iam]);
2512 }
2513 }
2514
2515 /** @brief Make a copy of the pointers of the elements of a sequence
2516 * @param access Array of size @c num_threads + 1 that defines @c
2517 * num_threads subsequences. Each position @c i contains an
2518 * iterator to the first element in the subsequence @c i.
2519 * @param beg_partition Array of size @c num_threads + 1 that
2520 * defines @c num_threads subsequences. Each position @c i
2521 * contains the rank of the first element in the subsequence @c
2522 * i.
2523 * @param out Begin iterator of output sequence.
2524 * @param num_threads Number of threads to use. */
2525 template<typename _InputIterator, typename _OutputIterator>
2526 static void
2527 uninitialized_ptr_copy_from_accessors(_InputIterator* access, size_type* beg_partition, _OutputIterator out, const thread_index_t num_threads)
2528 {
2529 #pragma omp parallel num_threads(num_threads)
2530 {
2531 int iam = omp_get_thread_num();
2532 _OutputIterator itout = out + beg_partition[iam];
2533 for (_InputIterator it = access[iam]; it != access[iam+1]; ++it)
2534 {
2535 *itout = &(*it);
2536 ++itout;
2537 }
2538 }
2539 }
2540
2541 /** @brief Split a sorted node array in two parts according to a key.
2542 *
2543 * For unique containers, if the splitting key is in the array of
2544 * nodes, the corresponding node is erased.
2545 * @param r Array of nodes containing the nodes to split (among others)
2546 * @param pos_beg Position of the first node in the array of
2547 * nodes to be considered
2548 * @param pos_end Position of the first node in the array of
2549 * nodes to be not considered
2550 * @param key Splitting key
2551 * @param pos_beg_right Position of the first node in the
2552 * resulting right partition (out)
2553 * @param existing Number of existing elements before dividing
2554 * (in) and after (out). Specificically, the counter is
2555 * incremented by one for unique containers if the splitting key
2556 * was already in the array of nodes.
2557 * @param strictly_less_or_less_equal Comparator to deal
2558 * transparently with repetitions with respect to the uniqueness
2559 * of the wrapping container
2560 * @return Position of the last node (not included) in the
2561 * resulting left partition (out)
2562 */
2563 template<typename StrictlyLessOrLessEqual>
2564 size_type
2565 divide(_Rb_tree_node_ptr* r, const size_type pos_beg, const size_type pos_end, const key_type& key, size_type& pos_beg_right, size_type& existing, StrictlyLessOrLessEqual strictly_less_or_less_equal)
2566 {
2567 pos_beg_right = std::lower_bound(r + pos_beg, r + pos_end, key, compare_node_key<_Compare>(base_type::_M_impl._M_key_compare)) - r;
2568
2569 //Check if the element exists.
2570 size_type pos_end_left = pos_beg_right;
2571
2572 // If r[pos_beg_right] is equal to key, must be erased
2573 /***** Dealing with repetitions (CORRECTNESS ISSUE) *****/
2574 _GLIBCXX_PARALLEL_ASSERT((pos_beg_right == pos_end) or not base_type::_M_impl._M_key_compare(base_type::_S_key(r[pos_beg_right]),key));
2575 _GLIBCXX_PARALLEL_ASSERT((pos_beg_right + 1 >= pos_end) or strictly_less_or_less_equal(key, base_type::_S_key(r[pos_beg_right + 1])));
2576 if (pos_beg_right != pos_end and not strictly_less_or_less_equal(key, base_type::_S_key(r[pos_beg_right])))
2577 {
2578 _M_destroy_node(r[pos_beg_right]);
2579 r[pos_beg_right] = NULL;
2580 ++pos_beg_right;
2581 ++existing;
2582 }
2583 _GLIBCXX_PARALLEL_ASSERT(pos_end_left <= pos_beg_right and pos_beg_right <= pos_end and pos_end_left >= pos_beg);
2584 return pos_end_left;
2585 }
2586
2587
2588 /** @brief Parallelization helper method: Given a random-access
2589 sequence of known size, divide it into pieces of almost the
2590 same size.
2591 * @param __first Begin iterator of sequence.
2592 * @param __last End iterator of sequence.
2593 * @param access Array of size @c num_pieces + 1 that defines @c
2594 * num_pieces subsequences. Each position @c i contains an
2595 * iterator to the first element in the subsequence @c i.
2596 * @param beg_partition Array of size @c num_pieces + 1 that
2597 * defines @c num_pieces subsequences. Each position @c i
2598 * contains the rank of the first element in the subsequence @c
2599 * i.
2600 * @param n Sequence size
2601 * @param num_pieces Number of pieces. */
2602 template<typename _RandomAccessIterator>
2603 static void
2604 range_accessors(const _RandomAccessIterator __first, const _RandomAccessIterator __last, _RandomAccessIterator* access, size_type* beg_partition, const size_type n, const thread_index_t num_pieces, std::random_access_iterator_tag)
2605 {
2606 access[0] = __first;
2607 for (int i=1; i< num_pieces; ++i)
2608 {
2609 access[i] = access[i-1] + (__last-__first)/num_pieces;
2610 beg_partition[i]= beg_partition[i-1]+ (__last-__first)/num_pieces;
2611 }
2612 beg_partition[num_pieces] = __last - access[num_pieces-1] + beg_partition[num_pieces-1];
2613 access[num_pieces]= __last;
2614 }
2615
2616 /** @brief Parallelization helper method: Given an input-access
2617 sequence of known size, divide it into pieces of almost the
2618 same size.
2619 * @param __first Begin iterator of sequence.
2620 * @param __last End iterator of sequence.
2621 * @param access Array of size @c num_pieces + 1 that defines @c
2622 * num_pieces subsequences. Each position @c i contains an
2623 * iterator to the first element in the subsequence @c i.
2624 * @param beg_partition Array of size @c num_pieces + 1 that
2625 * defines @c num_pieces subsequences. Each position @c i
2626 * contains the rank of the first element in the subsequence @c
2627 * i.
2628 * @param n Sequence size
2629 * @param num_pieces Number of pieces. */
2630 template<typename _InputIterator>
2631 static void
2632 range_accessors(const _InputIterator __first, const _InputIterator __last, _InputIterator* access, size_type* beg_partition, const size_type n, const thread_index_t num_pieces, std::input_iterator_tag)
2633 {
2634 access[0] = __first;
2635 _InputIterator it= __first;
2636 for (int i=1; i< num_pieces; ++i)
2637 {
2638 for (int j=0; j< n/num_pieces; ++j)
2639 ++it;
2640 access[i] = it;
2641 beg_partition[i]= n/num_pieces + beg_partition[i-1];
2642 }
2643 access[num_pieces] = __last;
2644 beg_partition[num_pieces] = n - (num_pieces-1)*(n/num_pieces) + beg_partition[num_pieces-1];
2645 }
2646
2647 /** @brief Initialize an array of concatenation problems for bulk
2648 insertion. They are linked as a tree with (end - beg) leaves.
2649 * @param conc Array of concatenation problems pointers to initialize.
2650 * @param beg Rank of the first leave to initialize
2651 * @param end Rank of the last (not included) leave to initialize
2652 * @param parent Pointer to the parent concatenation problem.
2653 */
2654 static concat_problem*
2655 _M_bulk_insertion_initialize_upper_problems(concat_problem** conc, const int beg, const int end, concat_problem* parent)
2656 {
2657 if (beg + 1 == end)
2658 {
2659 conc[2*beg]->par_problem = parent;
2660 return conc[2*beg];
2661 }
2662
2663 int size = end - beg;
2664 int mid = beg + size/2;
2665 conc[2*mid-1]->par_problem = parent;
2666 conc[2*mid-1]->left_problem = _M_bulk_insertion_initialize_upper_problems(conc, beg, mid, conc[2*mid-1]);
2667 conc[2*mid-1]->right_problem = _M_bulk_insertion_initialize_upper_problems(conc, mid, end, conc[2*mid-1]);
2668 return conc[2*mid-1];
2669 }
2670
2671
2672 /** @brief Determine black height of a node recursively.
2673 * @param t Node.
2674 * @return Black height of the node. */
2675 static int
2676 black_height(const _Rb_tree_node_ptr t)
2677 {
2678 if (t == NULL) return 0;
2679 int bh = black_height (static_cast<const _Rb_tree_node_ptr> (t->_M_left));
2680 if (t->_M_color == std::_S_black)
2681 ++bh;
2682 return bh;
2683 }
2684
2685 /** @brief Color a leaf black
2686 * @param t Leaf pointer.
2687 * @param black_h Black height of @c t (out) */
2688 static void
2689 make_black_leaf(const _Rb_tree_node_ptr t, int& black_h)
2690 {
2691 black_h = 0;
2692 if (t != NULL)
2693 {
2694 _GLIBCXX_PARALLEL_ASSERT(t->_M_left == NULL and t->_M_right == NULL);
2695 black_h = 1;
2696 t->_M_color = std::_S_black;
2697 }
2698 }
2699
2700 /** @brief Color a node black.
2701 * @param t Node to color black.
2702 * @param black_h Black height of @c t (out) */
2703 static void
2704 make_leaf(const _Rb_tree_node_ptr t, int& black_h)
2705 {
2706 _GLIBCXX_PARALLEL_ASSERT(t != NULL);
2707 black_h = 1;
2708 t->_M_color = std::_S_black;
2709 t->_M_left = NULL;
2710 t->_M_right = NULL;
2711 }
2712
2713 /** @brief Construct a tree from a root, a left subtree and a
2714 right subtree.
2715 * @param root Root of constructed tree.
2716 * @param l Root of left subtree.
2717 * @param r Root of right subtree.
2718 * @pre @c l, @c r are black.
2719 */
2720 template<typename S>
2721 static _Rb_tree_node_ptr
2722 plant(const _Rb_tree_node_ptr root, const _Rb_tree_node_ptr l, const _Rb_tree_node_ptr r)
2723 {
2724 S::left(root) = l;
2725 S::right(root) = r;
2726 if (l != NULL)
2727 l->_M_parent = root;
2728 if (r != NULL)
2729 r->_M_parent = root;
2730 root->_M_color = std::_S_red;
2731 return root;
2732 }
2733
2734 /** @brief Concatenate two red-black subtrees using and an
2735 intermediate node, which might be NULL
2736 * @param root Intermediate node.
2737 * @param l Left subtree.
2738 * @param r Right subtree.
2739 * @param black_h_l Black height of left subtree.
2740 * @param black_h_r Black height of right subtree.
2741 * @param t Tree resulting of the concatenation
2742 * @param black_h Black height of the resulting tree
2743 * @pre Left tree is higher than left tree
2744 * @post @c t is correct red-black tree with height @c black_h.
2745 */
2746 void
2747 concatenate(_Rb_tree_node_ptr root, _Rb_tree_node_ptr l, _Rb_tree_node_ptr r, int black_h_l, int black_h_r, _Rb_tree_node_ptr& t, int& black_h) const
2748 {
2749 #ifndef NDEBUG
2750 int count = 0, count1 = 0, count2 = 0;
2751 #endif
2752 _GLIBCXX_PARALLEL_ASSERT(rb_verify_tree(l, count1));
2753 _GLIBCXX_PARALLEL_ASSERT(rb_verify_tree(r, count2));
2754
2755 _GLIBCXX_PARALLEL_ASSERT(l != NULL ? l->_M_color != std::_S_red and black_h_l > 0 : black_h_l == 0);
2756 _GLIBCXX_PARALLEL_ASSERT(r != NULL ? r->_M_color != std::_S_red and black_h_r > 0 : black_h_r == 0);
2757
2758 if (black_h_l > black_h_r)
2759 if (root != NULL)
2760 concatenate<LeftRight>(root, l, r, black_h_l, black_h_r, t, black_h);
2761 else
2762 {
2763 if (r == NULL)
2764 {
2765 t = l;
2766 black_h = black_h_l;
2767 }
2768 else
2769 {
2770 // XXX SHOULD BE the same as extract_min but slower.
2771 /*
2772 root = static_cast<_Rb_tree_node_ptr>(_Rb_tree_node_base::_S_minimum(r));
2773 split(r, _S_key(_Rb_tree_increment(root)), _S_key(root), root, t, r, black_h, black_h_r);
2774 */
2775 extract_min(r, root, r, black_h_r);
2776 _GLIBCXX_PARALLEL_ASSERT(root != NULL);
2777 concatenate<LeftRight>(root, l, r, black_h_l, black_h_r, t, black_h);
2778 }
2779 }
2780 else
2781 if (root != NULL)
2782 concatenate<RightLeft>(root, r, l, black_h_r, black_h_l, t, black_h);
2783 else
2784 {
2785 if (l == NULL)
2786 {
2787 t = r;
2788 black_h = black_h_r;
2789 }
2790 else
2791 {
2792 // XXX SHOULD BE the same as extract_max but slower
2793 /*
2794 root = static_cast<_Rb_tree_node_ptr>(_Rb_tree_node_base::_S_maximum(l));
2795 split(l, _S_key(root), _S_key(_Rb_tree_decrement(root)), root, l, t, black_h_l, black_h);
2796 */
2797 extract_max(l, root, l, black_h_l);
2798 _GLIBCXX_PARALLEL_ASSERT(root != NULL);
2799 concatenate<RightLeft>(root, r, l, black_h_r, black_h_l, t, black_h);
2800 }
2801 }
2802 #ifndef NDEBUG
2803 if (root!=NULL) ++count1;
2804 _GLIBCXX_PARALLEL_ASSERT(t == NULL or t->_M_color == std::_S_black);
2805 bool b = rb_verify_tree(t, count);
2806 if (not b){
2807 _GLIBCXX_PARALLEL_ASSERT(false);
2808 }
2809 _GLIBCXX_PARALLEL_ASSERT(count1+count2 == count);
2810 #endif
2811 }
2812
2813 /** @brief Concatenate two red-black subtrees using and a not NULL
2814 * intermediate node.
2815 *
2816 * @c S is the symmetry parameter.
2817 * @param rt Intermediate node.
2818 * @param l Left subtree.
2819 * @param r Right subtree.
2820 * @param black_h_l Black height of left subtree.
2821 * @param black_h_r Black height of right subtree.
2822 * @param t Tree resulting of the concatenation
2823 * @param black_h Black height of the resulting tree
2824 * @pre Left tree is higher than right tree. @c rt != NULL
2825 * @post @c t is correct red-black tree with height @c black_h.
2826 */
2827 template<typename S>
2828 static void
2829 concatenate(const _Rb_tree_node_ptr rt, _Rb_tree_node_ptr l, _Rb_tree_node_ptr r, int black_h_l, int black_h_r, _Rb_tree_node_ptr& t, int& black_h)
2830 {
2831 _Rb_tree_node_base* root = l;
2832 _Rb_tree_node_ptr parent = NULL;
2833 black_h = black_h_l;
2834 _GLIBCXX_PARALLEL_ASSERT(black_h_l >= black_h_r);
2835 while (black_h_l != black_h_r)
2836 {
2837 if (l->_M_color == std::_S_black)
2838 --black_h_l;
2839 parent = l;
2840 l = static_cast<_Rb_tree_node_ptr>(S::right(l));
2841 _GLIBCXX_PARALLEL_ASSERT((black_h_l == 0 and (l == NULL or l->_M_color == std::_S_red)) or (black_h_l != 0 and l != NULL));
2842 _GLIBCXX_PARALLEL_ASSERT((black_h_r == 0 and (r == NULL or r->_M_color == std::_S_red)) or (black_h_r != 0 and r != NULL));
2843 }
2844 if (l != NULL and l->_M_color == std::_S_red)
2845 {
2846 //the root needs to be black
2847 parent = l;
2848 l = static_cast<_Rb_tree_node_ptr>(S::right(l));
2849 }
2850 _GLIBCXX_PARALLEL_ASSERT(l != NULL ? l->_M_color == std::_S_black : true);
2851 _GLIBCXX_PARALLEL_ASSERT(r != NULL ? r->_M_color == std::_S_black : true);
2852 t = plant<S>(rt, l, r);
2853 t->_M_parent = parent;
2854 if (parent != NULL)
2855 {
2856 S::right(parent) = t;
2857 black_h += _Rb_tree_rebalance(t, root);
2858 t = static_cast<_Rb_tree_node_ptr> (root);
2859 }
2860 else
2861 {
2862 ++black_h;
2863 t->_M_color = std::_S_black;
2864 }
2865 _GLIBCXX_PARALLEL_ASSERT(t->_M_color == std::_S_black);
2866 }
2867
2868 /** @brief Split a tree according to key in three parts: a left
2869 * child, a right child and an intermediate node.
2870 *
2871 * Trees are concatenated once the recursive call returns. That
2872 * is, from bottom to top (ie. smaller to larger), so the cost
2873 * bounds for split hold.
2874 * @param t Root of the tree to split.
2875 * @param key Key to split according to.
2876 * @param prev_k Key to split the intermediate node
2877 * @param root Out parameter. If a node exists whose key is
2878 * smaller or equal than @c key, but strictly larger than @c
2879 * prev_k, this is returned. Otherwise, it is null.
2880 * @param l Root of left subtree returned, nodes less than @c key.
2881 * @param r Root of right subtree returned, nodes greater or
2882 * equal than @c key.
2883 * @param black_h_l Black height of the left subtree.
2884 * @param black_h_r Black height of the right subtree.
2885 * @param strictly_less_or_less_equal Comparator to deal
2886 * transparently with repetitions with respect to the uniqueness
2887 * of the wrapping container
2888 * @return Black height of t */
2889 template<typename StrictlyLessOrEqual>
2890 int
2891 split(_Rb_tree_node_ptr t, const key_type& key, const key_type& prev_k, _Rb_tree_node_ptr& root, _Rb_tree_node_ptr& l, _Rb_tree_node_ptr& r, int& black_h_l, int& black_h_r, StrictlyLessOrEqual strictly_less_or_less_equal) const
2892 {
2893 if (t != NULL)
2894 {
2895 // Must be initialized, in case we never go left!!!
2896 root = NULL;
2897 int h = split_not_null(t, key, prev_k, root, l, r, black_h_l, black_h_r, strictly_less_or_less_equal);
2898 #ifndef NDEBUG
2899 _GLIBCXX_PARALLEL_ASSERT(l == NULL or base_type::_M_impl._M_key_compare(base_type::_S_key(base_type::_S_maximum(l)),key));
2900 _GLIBCXX_PARALLEL_ASSERT(r == NULL or not base_type::_M_impl._M_key_compare(base_type::_S_key(base_type::_S_minimum(r)),key));
2901 int count1, count2;
2902 _GLIBCXX_PARALLEL_ASSERT(rb_verify_tree(l, count1));
2903 _GLIBCXX_PARALLEL_ASSERT(rb_verify_tree(r, count2));
2904 _GLIBCXX_PARALLEL_ASSERT(root == NULL or base_type::_M_impl._M_key_compare(prev_k, base_type::_S_key(root)) and not base_type::_M_impl._M_key_compare(key, base_type::_S_key(root)));
2905 _GLIBCXX_PARALLEL_ASSERT(root != NULL or l==NULL or not base_type::_M_impl._M_key_compare(prev_k, base_type::_S_key(base_type::_S_maximum(l))));
2906 #endif
2907 return h;
2908 }
2909
2910 r = NULL;
2911 root = NULL;
2912 l = NULL;
2913 black_h_r = 0;
2914 black_h_l = 0;
2915 return 0;
2916 }
2917
2918 /** @brief Split a tree according to key in three parts: a left
2919 * child, a right child and an intermediate node.
2920 *
2921 * @param t Root of the tree to split.
2922 * @param key Key to split according to.
2923 * @param prev_k Key to split the intermediate node
2924 * @param root Out parameter. If a node exists whose key is
2925 * smaller or equal than @c key, but strictly larger than @c
2926 * prev_k, this is returned. Otherwise, it is null.
2927 * @param l Root of left subtree returned, nodes less than @c key.
2928 * @param r Root of right subtree returned, nodes greater or
2929 * equal than @c key.
2930 * @param black_h_l Black height of the left subtree.
2931 * @param black_h_r Black height of the right subtree.
2932 * @param strictly_less_or_equal Comparator to deal transparently
2933 * with repetitions with respect to the uniqueness of the
2934 * wrapping container
2935 * @pre t != NULL
2936 * @return Black height of t */
2937 template<typename StrictlyLessOrEqual>
2938 int
2939 split_not_null(const _Rb_tree_node_ptr t, const key_type& key, const key_type& prev_k, _Rb_tree_node_ptr& root, _Rb_tree_node_ptr& l, _Rb_tree_node_ptr& r, int& black_h_l, int& black_h_r, StrictlyLessOrEqual strictly_less_or_equal) const
2940 {
2941 _GLIBCXX_PARALLEL_ASSERT (t != NULL);
2942 int black_h, b_h;
2943 int black_node = 0;
2944 if (t->_M_color == std::_S_black)
2945 ++black_node;
2946 if (strictly_less_or_equal(key, base_type::_S_key(t)))
2947 {
2948 if (t->_M_left != NULL )
2949 {
2950 // t->M_right is at most one node
2951 // go to the left
2952 b_h = black_h = split_not_null( static_cast<_Rb_tree_node_ptr>(t->_M_left), key, prev_k, root, l, r, black_h_l, black_h_r, strictly_less_or_equal);
2953 // Moin root and right subtree to already existing right
2954 // half, leave left subtree.
2955 force_black_root(t->_M_right, b_h);
2956 concatenate(t, r, static_cast<_Rb_tree_node_ptr>(t->_M_right), black_h_r, b_h, r, black_h_r);
2957 }
2958 else
2959 {
2960 // t->M_right is at most one node
2961 r = t;
2962 black_h_r = black_node;
2963 force_black_root(r, black_h_r);
2964
2965 black_h = 0;
2966 l = NULL;
2967 black_h_l = 0;
2968 }
2969 _GLIBCXX_PARALLEL_ASSERT(l == NULL or base_type::_M_impl._M_key_compare(base_type::_S_key(base_type::_S_maximum(l)),key));
2970 _GLIBCXX_PARALLEL_ASSERT(r == NULL or not base_type::_M_impl._M_key_compare(base_type::_S_key(base_type::_S_minimum(r)),key));
2971 }
2972 else
2973 {
2974 if (t->_M_right != NULL )
2975 {
2976 // Go to the right.
2977 if (strictly_less_or_equal(prev_k, base_type::_S_key(t)))
2978 root = t;
2979 b_h = black_h = split_not_null(static_cast<_Rb_tree_node_ptr>(t->_M_right), key, prev_k, root, l, r, black_h_l, black_h_r, strictly_less_or_equal);
2980 // Join root and left subtree to already existing left
2981 // half, leave right subtree.
2982 force_black_root(t->_M_left, b_h);
2983 if (root != t)
2984 {
2985 // There was another point where we went right.
2986 concatenate(t, static_cast<_Rb_tree_node_ptr>(t->_M_left), l, b_h, black_h_l, l, black_h_l);
2987 }
2988 else
2989 {
2990 l = static_cast<_Rb_tree_node_ptr>(t->_M_left);
2991 black_h_l = b_h;
2992 }
2993 _GLIBCXX_PARALLEL_ASSERT(l == NULL or base_type::_M_impl._M_key_compare(base_type::_S_key(base_type::_S_maximum(l)),key));
2994 _GLIBCXX_PARALLEL_ASSERT(r == NULL or not base_type::_M_impl._M_key_compare(base_type::_S_key(base_type::_S_minimum(r)),key));
2995 }
2996 else
2997 {
2998 if (strictly_less_or_equal(prev_k, base_type::_S_key(t)))
2999 {
3000 root = t;
3001 l= static_cast<_Rb_tree_node_ptr>(t->_M_left);
3002 make_black_leaf(l, black_h_l);
3003 _GLIBCXX_PARALLEL_ASSERT(l == NULL or base_type::_M_impl._M_key_compare(base_type::_S_key(base_type::_S_maximum(l)),key));
3004 }
3005 else
3006 {
3007 l= t;
3008 black_h_l = black_node;
3009 force_black_root(l, black_h_l);
3010 _GLIBCXX_PARALLEL_ASSERT(l == NULL or base_type::_M_impl._M_key_compare(base_type::_S_key(base_type::_S_maximum(l)),key));
3011 }
3012
3013 r = NULL;
3014 black_h = 0;
3015 black_h_r = 0;
3016 }
3017 }
3018 return black_h + black_node;
3019 }
3020
3021 /** @brief Color the root black and update the black height accordingly.
3022 *
3023 * @param t Root of the tree.
3024 * @param black_h Black height of the tree @c t (out) */
3025 static void force_black_root(_Rb_tree_node_base* t, int& black_h)
3026 {
3027 if (t != NULL and t->_M_color == std::_S_red)
3028 {
3029 t->_M_color = std::_S_black;
3030 ++ black_h;
3031 }
3032 }
3033
3034 /** @brief Split the tree in two parts: the minimum element from a
3035 tree (i.e. leftmost) and the rest (right subtree)
3036 * @param t Root of the tree
3037 * @param root Minimum element (out)
3038 * @param r Right subtree: @c t - {@c root}
3039 * @param black_h_r Black height of the right subtree.
3040 * @return Black height of the original tree */
3041 int
3042 extract_min(const _Rb_tree_node_ptr t, _Rb_tree_node_ptr& root, _Rb_tree_node_ptr& r, int& black_h_r) const
3043 {
3044 _GLIBCXX_PARALLEL_ASSERT (t != NULL);
3045 int black_h, b_h;
3046 int black_node = 0;
3047 if (t->_M_color == std::_S_black)
3048 ++black_node;
3049
3050 if (t->_M_left != NULL )
3051 {
3052 // t->M_right is at most one node
3053 // go to the left
3054 b_h = black_h = extract_min( static_cast<_Rb_tree_node_ptr>(t->_M_left), root, r, black_h_r);
3055
3056 // Join root and right subtree to already existing right
3057 // half, leave left subtree
3058 force_black_root(t->_M_right, b_h);
3059 concatenate(t, r, static_cast<_Rb_tree_node_ptr>(t->_M_right), black_h_r, b_h, r, black_h_r);
3060 }
3061 else
3062 {
3063 // t->M_right is at most one node
3064 root = t;
3065 if (t->_M_right == NULL)
3066 {
3067 r = NULL;
3068 black_h_r = 0;
3069 }
3070 else
3071 {
3072 r = static_cast<_Rb_tree_node_ptr>(t->_M_right);
3073 black_h_r = 1;
3074 r->_M_color = std::_S_black;
3075 }
3076 black_h = 0;
3077 }
3078 return black_h + black_node;
3079 }
3080
3081
3082 /** @brief Split the tree in two parts: the greatest element from
3083 a tree (i.e. rightmost) and the rest (left subtree)
3084 * @param t Root of the tree
3085 * @param root Maximum element (out)
3086 * @param l Left subtree: @c t - {@c root}
3087 * @param black_h_l Black height of the left subtree.
3088 * @return Black height of the original tree */
3089 int
3090 extract_max(const _Rb_tree_node_ptr t, _Rb_tree_node_ptr& root, _Rb_tree_node_ptr& l, int& black_h_l) const
3091 {
3092 _GLIBCXX_PARALLEL_ASSERT (t != NULL);
3093 int black_h, b_h;
3094 int black_node = 0;
3095 if (t->_M_color == std::_S_black)
3096 ++black_node;
3097
3098 if (t->_M_right != NULL )
3099 {
3100 b_h = black_h = extract_max(static_cast<_Rb_tree_node_ptr>(t->_M_right), root, l, black_h_l);
3101
3102 // Join root and left subtree to already existing left half,
3103 // leave right subtree.
3104 force_black_root(t->_M_left, b_h);
3105
3106 concatenate(t, static_cast<_Rb_tree_node_ptr>(t->_M_left), l, b_h, black_h_l, l, black_h_l);
3107 }
3108 else
3109 {
3110 root = t;
3111 if (t->_M_left == NULL)
3112 {
3113 l = NULL;
3114 black_h_l = 0;
3115 }
3116 else
3117 {
3118 l = static_cast<_Rb_tree_node_ptr>(t->_M_left);
3119 black_h_l = 1;
3120 l->_M_color = std::_S_black;
3121 }
3122 black_h = 0;
3123 }
3124 return black_h + black_node;
3125 }
3126
3127 /** @brief Split tree according to key in two parts: a left tree
3128 * and a right subtree
3129 *
3130 * Trees are concatenated once the recursive call returns. That
3131 * is, from bottom to top (ie. smaller to larger), so the cost
3132 * bounds for split hold.
3133 * @param t Root of the tree to split.
3134 * @param key Key to split according to.
3135 * @param l Root of left subtree returned, nodes less than @c key.
3136 * @param r Root of right subtree returned, nodes greater than @c key.
3137 * @param black_h_l Black height of the left subtree.
3138 * @param black_h_r Black height of the right subtree.
3139 * @return Black height of the original tree */
3140 int
3141 split(const _Rb_tree_node_ptr t, const key_type& key, _Rb_tree_node_ptr& l, _Rb_tree_node_ptr& r, int& black_h_l, int& black_h_r) const
3142 {
3143 if (t != NULL)
3144 {
3145 int black_h, b_h;
3146 int black_node = 0;
3147 if (t->_M_color == std::_S_black)
3148 ++black_node;
3149 if (not (base_type::_M_impl._M_key_compare(base_type::_S_key(t), key)))
3150 {
3151 // Go to the left.
3152 b_h = black_h = split( static_cast<_Rb_tree_node_ptr>(t->_M_left), key, l, r, black_h_l, black_h_r);
3153
3154 // Join root and right subtree to already existing right
3155 // half, leave left subtree.
3156 force_black_root(t->_M_right, b_h);
3157 concatenate(t, r, static_cast<_Rb_tree_node_ptr>(t->_M_right), black_h_r, b_h, r, black_h_r);
3158 }
3159 else
3160 {
3161 // Go to the right.
3162 b_h = black_h = split(static_cast<_Rb_tree_node_ptr>(t->_M_right), key, l, r, black_h_l, black_h_r);
3163
3164 // Join root and left subtree to already existing left
3165 // half, leave right subtree.
3166 force_black_root(t->_M_left, b_h);
3167 concatenate(t, static_cast<_Rb_tree_node_ptr>(t->_M_left), l, b_h, black_h_l, l, black_h_l);
3168 }
3169 return black_h + black_node;
3170 }
3171 else
3172 {
3173 r = NULL;
3174 l = NULL;
3175 black_h_r = 0;
3176 black_h_l = 0;
3177 return 0;
3178 }
3179 }
3180
3181 /** @brief Insert an existing node in tree and rebalance it, if
3182 * appropriate.
3183 *
3184 * The keyword "local" is used because no attributes of the
3185 * red-black tree are changed, so this insertion is not yet seen
3186 * by the global data structure.
3187 * @param t Root of tree to insert into.
3188 * @param new_t Existing node to insert.
3189 * @param existing Number of existing elements before insertion
3190 * (in) and after (out). Specifically, the counter is incremented
3191 * by one for unique containers if the key of new_t was already
3192 * in the tree.
3193 * @param black_h Black height of the resulting tree (out)
3194 * @param strictly_less_or_less_equal Comparator to deal
3195 * transparently with repetitions with respect to the uniqueness
3196 * of the wrapping container
3197 * @return Resulting tree after insertion */
3198 template<typename StrictlyLessOrLessEqual>
3199 _Rb_tree_node_ptr
3200 _M_insert_local(_Rb_tree_node_base* t, const _Rb_tree_node_ptr new_t, size_type& existing, int& black_h, StrictlyLessOrLessEqual strictly_less_or_less_equal)
3201 {
3202 _GLIBCXX_PARALLEL_ASSERT(t != NULL);
3203 if (_M_insert_local_top_down(t, new_t, NULL, NULL, true, strictly_less_or_less_equal))
3204 {
3205 t->_M_parent = NULL;
3206 black_h += _Rb_tree_rebalance(new_t, t);
3207 _GLIBCXX_PARALLEL_ASSERT(t->_M_color == std::_S_black);
3208 return static_cast<_Rb_tree_node_ptr>(t);
3209 }
3210 else
3211 {
3212 base_type::_M_destroy_node(new_t);
3213 ++existing;
3214 force_black_root(t, black_h);
3215 return static_cast<_Rb_tree_node_ptr>(t);
3216 }
3217 }
3218
3219 /***** Dealing with repetitions (CORRECTNESS ISSUE) *****/
3220 /** @brief Insert an existing node in tree, do no rebalancing.
3221 * @param t Root of tree to insert into.
3222 * @param new_t Existing node to insert.
3223 * @param eq_t Node candidate to be equal than new_t, only
3224 * relevant for unique containers
3225 * @param parent Parent node of @c t
3226 * @param is_left True if @c t is a left child of @c
3227 * parent. False otherwise.
3228 * @param strictly_less_or_less_equal Comparator to deal
3229 * transparently with repetitions with respect to the uniqueness
3230 * of the wrapping container
3231
3232 * @return Success of the insertion
3233 */
3234 template<typename StrictlyLessOrLessEqual>
3235 bool
3236 _M_insert_local_top_down(_Rb_tree_node_base* t, const _Rb_tree_node_ptr new_t, _Rb_tree_node_base* eq_t, _Rb_tree_node_base* parent, const bool is_left, StrictlyLessOrLessEqual strictly_less_or_less_equal) const
3237 {
3238 if (t != NULL)
3239 {
3240 if (strictly_less_or_less_equal(_S_key(new_t), _S_key(static_cast<_Rb_tree_node_ptr>(t))))
3241 {
3242 return _M_insert_local_top_down(t->_M_left, new_t, eq_t, t, true, strictly_less_or_less_equal);
3243 }
3244 else
3245 {
3246 return _M_insert_local_top_down(t->_M_right, new_t, t, t, false, strictly_less_or_less_equal);
3247 }
3248 }
3249
3250 _GLIBCXX_PARALLEL_ASSERT(parent != NULL);
3251
3252 // Base case.
3253 if (eq_t == NULL or strictly_less_or_less_equal(_S_key(static_cast<_Rb_tree_node_ptr>(eq_t)), _S_key(new_t)))
3254 {
3255 // The element to be inserted did not existed.
3256 if (is_left)
3257 {
3258 parent->_M_left = new_t;
3259 }
3260 else
3261 {
3262 parent->_M_right = new_t;
3263 }
3264
3265 new_t->_M_parent = parent;
3266 new_t->_M_left = NULL;
3267 new_t->_M_right = NULL;
3268 new_t->_M_color = std::_S_red;
3269
3270 return true;
3271 }
3272 else
3273 return false;
3274 }
3275
3276 /** @brief Rebalance a tree locally.
3277 *
3278 * Essentially, it is the same function as insert_erase from the
3279 * base class, but without the insertion and without using any
3280 * tree attributes.
3281 * @param __x Root of the current subtree to rebalance.
3282 * @param __root Root of tree where @c __x is in (rebalancing
3283 * stops when root is reached)
3284 * @return Increment in the black height after rebalancing
3285 */
3286 static int
3287 _Rb_tree_rebalance(_Rb_tree_node_base* __x, _Rb_tree_node_base*& __root)
3288 {
3289 _GLIBCXX_PARALLEL_ASSERT(__root->_M_color == std::_S_black);
3290 // Rebalance.
3291 while (__x != __root and __x->_M_parent != __root and
3292 __x->_M_parent->_M_color == std::_S_red)
3293 {
3294 _Rb_tree_node_base* const __xpp = __x->_M_parent->_M_parent;
3295
3296 if (__x->_M_parent == __xpp->_M_left)
3297 {
3298 _Rb_tree_node_base* const __y = __xpp->_M_right;
3299 if (__y && __y->_M_color == std::_S_red)
3300 {
3301 __x->_M_parent->_M_color = std::_S_black;
3302 __y->_M_color = std::_S_black;
3303 __xpp->_M_color = std::_S_red;
3304 __x = __xpp;
3305 }
3306 else
3307 {
3308 if (__x == __x->_M_parent->_M_right)
3309 {
3310 __x = __x->_M_parent;
3311 std::_Rb_tree_rotate_left(__x, __root);
3312 }
3313 __x->_M_parent->_M_color = std::_S_black;
3314 __xpp->_M_color = std::_S_red;
3315 std::_Rb_tree_rotate_right(__xpp, __root);
3316 }
3317 }
3318 else
3319 {
3320 _Rb_tree_node_base* const __y = __xpp->_M_left;
3321 if (__y && __y->_M_color == std::_S_red)
3322 {
3323 __x->_M_parent->_M_color = std::_S_black;
3324 __y->_M_color = std::_S_black;
3325 __xpp->_M_color = std::_S_red;
3326 __x = __xpp;
3327 }
3328 else
3329 {
3330 if (__x == __x->_M_parent->_M_left)
3331 {
3332 __x = __x->_M_parent;
3333 std::_Rb_tree_rotate_right(__x, __root);
3334 }
3335 __x->_M_parent->_M_color = std::_S_black;
3336 __xpp->_M_color = std::_S_red;
3337 std::_Rb_tree_rotate_left(__xpp, __root);
3338 }
3339 }
3340 }
3341 if (__root->_M_color == std::_S_red)
3342 {
3343 __root->_M_color = std::_S_black;
3344 _GLIBCXX_PARALLEL_ASSERT(rb_verify_tree(static_cast<typename base_type::_Const_Link_type>(__root)));
3345 return 1;
3346 }
3347 _GLIBCXX_PARALLEL_ASSERT(rb_verify_tree(static_cast<typename base_type::_Const_Link_type>(__root)));
3348 return 0;
3349 }
3350
3351 /** @brief Analogous to class method rb_verify() but only for a subtree.
3352 * @param __x Pointer to root of subtree to check.
3353 * @param count Returned number of nodes.
3354 * @return Tree correct.
3355 */
3356 bool
3357 rb_verify_tree(const typename base_type::_Const_Link_type __x, int& count) const
3358 {
3359 int bh;
3360 return rb_verify_tree_node(__x) and rb_verify_tree(__x, count, bh);
3361 }
3362
3363 /** @brief Verify that a subtree is binary search tree (verifies
3364 key relationships)
3365 * @param __x Pointer to root of subtree to check.
3366 * @return Tree correct.
3367 */
3368 bool
3369 rb_verify_tree_node(const typename base_type::_Const_Link_type __x) const
3370 {
3371 if (__x == NULL)
3372 return true;
3373 else
3374 {
3375 return rb_verify_node(__x) and
3376 rb_verify_tree_node(base_type::_S_left(__x)) and
3377 rb_verify_tree_node( base_type::_S_right(__x));
3378 }
3379 }
3380
3381 /** @brief Verify all the properties of a red-black tree except
3382 for the key ordering
3383 * @param __x Pointer to (subtree) root node.
3384 * @return Tree correct.
3385 */
3386 static bool
3387 rb_verify_tree(const typename base_type::_Const_Link_type __x)
3388 {
3389 int bh, count;
3390 return rb_verify_tree(__x, count, bh);
3391 }
3392
3393 /** @brief Verify all the properties of a red-black tree except
3394 for the key ordering
3395 * @param __x Pointer to (subtree) root node.
3396 * @param count Number of nodes of @c __x (out).
3397 * @param black_h Black height of @c __x (out).
3398 * @return Tree correct.
3399 */
3400 static bool
3401 rb_verify_tree(const typename base_type::_Const_Link_type __x, int& count, int& black_h)
3402 {
3403 if (__x == NULL)
3404 {
3405 count = 0;
3406 black_h = 0;
3407 return true;
3408 }
3409 typename base_type::_Const_Link_type __L = base_type::_S_left(__x);
3410 typename base_type::_Const_Link_type __R = base_type::_S_right(__x);
3411 int countL, countR = 0, bhL, bhR;
3412 bool ret = rb_verify_tree(__L, countL, bhL);
3413 ret = ret and rb_verify_tree(__R, countR, bhR);
3414 count = 1 + countL + countR;
3415 ret = ret and bhL == bhR;
3416 black_h = bhL + ((__x->_M_color == std::_S_red)? 0 : 1);
3417 return ret;
3418 }
3419
3420 /** @brief Verify red-black properties (including key based) for a node
3421 * @param __x Pointer to node.
3422 * @return Node correct.
3423 */
3424 bool
3425 rb_verify_node(const typename base_type::_Const_Link_type __x) const
3426 {
3427 typename base_type::_Const_Link_type __L = base_type::_S_left(__x);
3428 typename base_type::_Const_Link_type __R = base_type::_S_right(__x);
3429 if (__x->_M_color == std::_S_red)
3430 if ((__L && __L->_M_color == std::_S_red)
3431 || (__R && __R->_M_color == std::_S_red))
3432 {
3433 return false;
3434 }
3435 if (__L != NULL)
3436 {
3437 __L = static_cast<typename base_type::_Const_Link_type>(base_type::_S_maximum(__L));
3438 if (base_type::_M_impl._M_key_compare(base_type::_S_key(__x), base_type::_S_key(__L)))
3439 {
3440 return false;
3441 }
3442 }
3443
3444 if (__R != NULL)
3445 {
3446 __R = static_cast<typename base_type::_Const_Link_type>(base_type::_S_minimum(__R));
3447 if (base_type::_M_impl._M_key_compare(base_type::_S_key(__R), base_type::_S_key(__x)))
3448 {
3449 return false;
3450 }
3451 }
3452
3453 return true;
3454 }
3455
3456 /** @brief Print all the information of the root.
3457 * @param t Root of the tree.
3458 */
3459 static void
3460 print_root(_Rb_tree_node_base* t)
3461 {
3462 /*
3463 if (t != NULL)
3464 std::cout<< base_type::_S_key(t) << std::endl;
3465 else
3466 std::cout<< "NULL" << std::endl;
3467 */
3468 }
3469
3470 /** @brief Print all the information of the tree.
3471 * @param t Root of the tree.
3472 */
3473 static void
3474 print_tree(_Rb_tree_node_base* t)
3475 {
3476 /*
3477 if (t != NULL)
3478 {
3479 print_tree(t->_M_left);
3480 std::cout<< base_type::_S_key(t) << std::endl;
3481 print_tree(t->_M_right);
3482 }
3483 */
3484 }
3485
3486 /** @brief Print blanks.
3487 * @param b Number of blanks to print.
3488 * @return A string with @c b blanks */
3489 inline static std::string
3490 blanks(int b)
3491 {
3492 /*
3493 std::string s = "";
3494 for (int i=0; i < b; ++i)
3495 s += " ";
3496 return s;
3497 */
3498 }
3499
3500 /** @brief Print all the information of the tree.
3501 * @param t Root of the tree.
3502 * @param c Width of a printed key.
3503 */
3504 template<typename Pointer>
3505 static void
3506 draw_tree(Pointer t, const int c)
3507 {
3508 /*
3509 if (t == NULL)
3510 {
3511 std::cout << blanks(c) << "NULL" << std::endl;
3512 return;
3513 }
3514 draw_tree(static_cast<Pointer>(t->_M_right), c + 8);
3515 std::cout << blanks(c) << "" << base_type::_S_key(t) << " ";
3516 if (t->_M_color == std::_S_black)
3517 std::cout << "B" << std::endl;
3518 else
3519 std::cout << "R" << std::endl;
3520 draw_tree(static_cast<Pointer>(t->_M_left), c + 8);
3521 */
3522 }
3523
3524 public:
3525 /** @brief Verify that all the red-black tree properties hold for
3526 the stored tree, as well as the additional properties that the
3527 STL implementation imposes.
3528 */
3529 bool
3530 rb_verify()
3531 {
3532 if (base_type::_M_impl._M_node_count == 0 || base_type::begin() == base_type::end())
3533 {
3534 bool res = base_type::_M_impl._M_node_count == 0 && base_type::begin() == base_type::end()
3535 && base_type::_M_impl._M_header._M_left ==base_type::_M_end()
3536 && base_type::_M_impl._M_header._M_right == base_type::_M_end();
3537 _GLIBCXX_PARALLEL_ASSERT(res);
3538 return res;
3539 }
3540 size_type i=0;
3541 unsigned int __len = _Rb_tree_black_count(base_type::_M_leftmost(), base_type::_M_root());
3542 for (typename base_type::const_iterator __it =base_type::begin(); __it != base_type::end(); ++__it)
3543 {
3544 typename base_type::_Const_Link_type __x = static_cast<typename base_type::_Const_Link_type>(__it._M_node);
3545 if (not rb_verify_node(__x)) return false;
3546 if (!base_type::_S_left(__x)&& !base_type::_S_right(__x) && _Rb_tree_black_count(__x,base_type::_M_root()) != __len)
3547 {
3548 _GLIBCXX_PARALLEL_ASSERT(false);
3549 return false;
3550 }
3551 ++i;
3552 }
3553
3554 if (i != base_type::_M_impl._M_node_count)
3555 printf("%ld != %ld\n", i, base_type::_M_impl._M_node_count);
3556
3557 if (base_type::_M_leftmost() != std::_Rb_tree_node_base::_S_minimum(base_type::_M_root()))
3558 {
3559 _GLIBCXX_PARALLEL_ASSERT(false);
3560 return false;
3561 }
3562 if (base_type::_M_rightmost() != std::_Rb_tree_node_base::_S_maximum(base_type::_M_root()))
3563 {
3564 _GLIBCXX_PARALLEL_ASSERT(false);
3565 return false;
3566 }
3567 _GLIBCXX_PARALLEL_ASSERT(i == base_type::_M_impl._M_node_count);
3568 return true;
3569 }
3570 };
3571
3572 }
3573
3574 #endif