|
PPL
0.12.1
|
00001 /* CO_Tree class implementation. 00002 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 00003 Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com) 00004 00005 This file is part of the Parma Polyhedra Library (PPL). 00006 00007 The PPL is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License as published by the 00009 Free Software Foundation; either version 3 of the License, or (at your 00010 option) any later version. 00011 00012 The PPL is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00015 for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software Foundation, 00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. 00020 00021 For the most up-to-date information see the Parma Polyhedra Library 00022 site: http://bugseng.com/products/ppl/ . */ 00023 00024 #include "ppl-config.h" 00025 #include "CO_Tree.defs.hh" 00026 00027 namespace PPL = Parma_Polyhedra_Library; 00028 00029 PPL::dimension_type 00030 PPL::CO_Tree::external_memory_in_bytes() const { 00031 dimension_type memory_size = 0; 00032 if (reserved_size != 0) { 00033 // Add the size of data[] 00034 memory_size += (reserved_size + 1)*sizeof(data[0]); 00035 // Add the size of indexes[] 00036 memory_size += (reserved_size + 2)*sizeof(indexes[0]); 00037 for (const_iterator itr = begin(), itr_end = end(); itr != itr_end; ++itr) 00038 memory_size += PPL::external_memory_in_bytes(*itr); 00039 } 00040 return memory_size; 00041 } 00042 00043 PPL::CO_Tree::iterator 00044 PPL::CO_Tree::insert(iterator itr, dimension_type key1) { 00045 PPL_ASSERT(key1 != unused_index); 00046 00047 if (empty()) { 00048 insert_in_empty_tree(key1, Coefficient_zero()); 00049 return iterator(*this); 00050 } 00051 00052 if (itr == end()) 00053 return insert(key1); 00054 00055 iterator candidate1 = bisect_near(itr, key1); 00056 00057 if (key1 == candidate1.index()) 00058 return candidate1; 00059 00060 dimension_type candidate2_index = dfs_index(candidate1); 00061 00062 if (key1 < candidate1.index()) { 00063 --candidate2_index; 00064 while (indexes[candidate2_index] == unused_index) 00065 --candidate2_index; 00066 } else { 00067 ++candidate2_index; 00068 while (indexes[candidate2_index] == unused_index) 00069 ++candidate2_index; 00070 } 00071 00072 tree_iterator candidate1_node(candidate1, *this); 00073 00074 PPL_ASSERT(candidate2_index <= reserved_size + 1); 00075 00076 if (candidate2_index == 0 || candidate2_index > reserved_size) 00077 // Use candidate1 00078 return iterator(insert_precise(key1, Coefficient_zero(), 00079 candidate1_node)); 00080 00081 tree_iterator candidate2_node(*this, candidate2_index); 00082 00083 // Adjacent nodes in an in-order visit of a tree always have different 00084 // heights. This fact can be easily proven by induction on the tree's 00085 // height, using the definition of the in-order layout. 00086 PPL_ASSERT(candidate1_node.get_offset() != candidate2_node.get_offset()); 00087 00088 if (candidate1_node.get_offset() < candidate2_node.get_offset()) { 00089 PPL_ASSERT(candidate1_node.depth() > candidate2_node.depth()); 00090 // candidate1_node is deeper in the tree than candidate2_node, so use 00091 // candidate1_node. 00092 return iterator(insert_precise(key1, Coefficient_zero(), 00093 candidate1_node)); 00094 } else { 00095 PPL_ASSERT(candidate1_node.depth() < candidate2_node.depth()); 00096 // candidate2_node is deeper in the tree than candidate1_node, so use 00097 // candidate2_node. 00098 return iterator(insert_precise(key1, Coefficient_zero(), 00099 candidate2_node)); 00100 } 00101 } 00102 00103 PPL::CO_Tree::iterator 00104 PPL::CO_Tree::insert(iterator itr, dimension_type key1, 00105 data_type_const_reference data1) { 00106 PPL_ASSERT(key1 != unused_index); 00107 00108 if (empty()) { 00109 insert_in_empty_tree(key1, data1); 00110 return iterator(*this); 00111 } 00112 00113 if (itr == end()) 00114 return insert(key1, data1); 00115 00116 iterator candidate1 = bisect_near(itr, key1); 00117 00118 if (key1 == candidate1.index()) { 00119 *candidate1 = data1; 00120 return candidate1; 00121 } 00122 00123 dimension_type candidate2_index = dfs_index(candidate1); 00124 00125 if (key1 < candidate1.index()) { 00126 --candidate2_index; 00127 while (indexes[candidate2_index] == unused_index) 00128 --candidate2_index; 00129 } else { 00130 ++candidate2_index; 00131 while (indexes[candidate2_index] == unused_index) 00132 ++candidate2_index; 00133 } 00134 00135 tree_iterator candidate1_node(candidate1, *this); 00136 00137 if (candidate2_index == 0 || candidate2_index > reserved_size) 00138 // Use candidate1 00139 return iterator(insert_precise(key1, data1, candidate1_node)); 00140 00141 tree_iterator candidate2_node(*this, candidate2_index); 00142 00143 // Adjacent nodes in an in-order visit of a tree always have different 00144 // heights. This fact can be easily proven by induction on the tree's 00145 // height, using the definition of the in-order layout. 00146 PPL_ASSERT(candidate1_node.get_offset() != candidate2_node.get_offset()); 00147 00148 if (candidate1_node.get_offset() < candidate2_node.get_offset()) { 00149 PPL_ASSERT(candidate1_node.depth() > candidate2_node.depth()); 00150 // candidate1_node is deeper in the tree than candidate2_node, so 00151 // use candidate1_node. 00152 return iterator(insert_precise(key1, data1, candidate1_node)); 00153 } else { 00154 PPL_ASSERT(candidate1_node.depth() < candidate2_node.depth()); 00155 // candidate2_node is deeper in the tree than candidate1_node, so 00156 // use candidate2_node. 00157 return iterator(insert_precise(key1, data1, candidate2_node)); 00158 } 00159 } 00160 00161 void 00162 PPL::CO_Tree::erase_element_and_shift_left(dimension_type key) { 00163 iterator itr = erase(key); 00164 if (itr == end()) 00165 return; 00166 dimension_type i = dfs_index(itr); 00167 dimension_type* p = indexes + i; 00168 dimension_type* p_end = indexes + (reserved_size + 1); 00169 for ( ; p != p_end; ++p) 00170 if (*p != unused_index) 00171 --(*p); 00172 PPL_ASSERT(OK()); 00173 } 00174 00175 void 00176 PPL::CO_Tree::increase_keys_from(dimension_type key, dimension_type n) { 00177 if (empty()) 00178 return; 00179 dimension_type* p = indexes + reserved_size; 00180 while (*p == unused_index) 00181 --p; 00182 while (p != indexes && *p >= key) { 00183 *p += n; 00184 --p; 00185 while (*p == unused_index) 00186 --p; 00187 } 00188 PPL_ASSERT(OK()); 00189 } 00190 00191 PPL::dimension_type 00192 PPL::CO_Tree::bisect_in(dimension_type first, dimension_type last, 00193 dimension_type key) const { 00194 PPL_ASSERT(first != 0); 00195 PPL_ASSERT(last <= reserved_size); 00196 PPL_ASSERT(first <= last); 00197 PPL_ASSERT(indexes[first] != unused_index); 00198 PPL_ASSERT(indexes[last] != unused_index); 00199 00200 while (first < last) { 00201 dimension_type half = (first + last) / 2; 00202 dimension_type new_half = half; 00203 00204 while (indexes[new_half] == unused_index) 00205 ++new_half; 00206 00207 if (indexes[new_half] == key) 00208 return new_half; 00209 00210 if (indexes[new_half] > key) { 00211 00212 while (indexes[half] == unused_index) 00213 --half; 00214 00215 last = half; 00216 00217 } else { 00218 00219 ++new_half; 00220 while (indexes[new_half] == unused_index) 00221 ++new_half; 00222 00223 first = new_half; 00224 } 00225 } 00226 00227 // It is important that last is returned instead of first, because first 00228 // may have increased beyond last, even beyond the original value of last 00229 // at the beginning of this method. 00230 return last; 00231 } 00232 00233 PPL::dimension_type 00234 PPL::CO_Tree::bisect_near(dimension_type hint, dimension_type key) const { 00235 PPL_ASSERT(hint != 0); 00236 PPL_ASSERT(hint <= reserved_size); 00237 PPL_ASSERT(indexes[hint] != unused_index); 00238 00239 if (indexes[hint] == key) 00240 return hint; 00241 00242 dimension_type new_hint; 00243 dimension_type offset = 1; 00244 00245 if (indexes[hint] > key) { 00246 // The searched element is before `hint'. 00247 00248 while (true) { 00249 00250 if (hint <= offset) { 00251 // The searched element is in (0,hint). 00252 new_hint = hint; 00253 hint = 1; 00254 // The searched element is in [hint,new_hint). 00255 while (indexes[hint] == unused_index) 00256 ++hint; 00257 if (indexes[hint] >= key) 00258 return hint; 00259 // The searched element is in (hint,new_hint) and both indexes point 00260 // to valid elements. 00261 break; 00262 } else 00263 new_hint = hint - offset; 00264 00265 PPL_ASSERT(new_hint > 0); 00266 PPL_ASSERT(new_hint <= reserved_size); 00267 00268 // Find the element at `new_hint' (or the first after it). 00269 while (indexes[new_hint] == unused_index) 00270 ++new_hint; 00271 00272 PPL_ASSERT(new_hint <= hint); 00273 00274 if (indexes[new_hint] == key) 00275 return new_hint; 00276 else 00277 if (indexes[new_hint] < key) { 00278 // The searched element is in (new_hint,hint) 00279 using std::swap; 00280 swap(hint, new_hint); 00281 // The searched element is now in (hint,new_hint). 00282 break; 00283 } 00284 00285 hint = new_hint; 00286 offset *= 2; 00287 } 00288 00289 } else { 00290 // The searched element is after `hint'. 00291 while (true) { 00292 00293 if (hint + offset > reserved_size) { 00294 // The searched element is in (hint,reserved_size+1). 00295 new_hint = reserved_size; 00296 // The searched element is in (hint,new_hint]. 00297 while (indexes[new_hint] == unused_index) 00298 --new_hint; 00299 if (indexes[new_hint] <= key) 00300 return new_hint; 00301 // The searched element is in (hint,new_hint) and both indexes point 00302 // to valid elements. 00303 break; 00304 } else 00305 new_hint = hint + offset; 00306 00307 PPL_ASSERT(new_hint > 0); 00308 PPL_ASSERT(new_hint <= reserved_size); 00309 00310 // Find the element at `new_hint' (or the first after it). 00311 while (indexes[new_hint] == unused_index) 00312 --new_hint; 00313 00314 PPL_ASSERT(hint <= new_hint); 00315 00316 if (indexes[new_hint] == key) 00317 return new_hint; 00318 else 00319 if (indexes[new_hint] > key) 00320 // The searched element is in (hint,new_hint). 00321 break; 00322 00323 hint = new_hint; 00324 offset *= 2; 00325 } 00326 } 00327 // The searched element is in (hint,new_hint). 00328 PPL_ASSERT(hint > 0); 00329 PPL_ASSERT(hint < new_hint); 00330 PPL_ASSERT(new_hint <= reserved_size); 00331 PPL_ASSERT(indexes[hint] != unused_index); 00332 PPL_ASSERT(indexes[new_hint] != unused_index); 00333 00334 ++hint; 00335 while (indexes[hint] == unused_index) 00336 ++hint; 00337 00338 if (hint == new_hint) 00339 return hint; 00340 00341 --new_hint; 00342 while (indexes[new_hint] == unused_index) 00343 --new_hint; 00344 00345 PPL_ASSERT(hint <= new_hint); 00346 PPL_ASSERT(indexes[hint] != unused_index); 00347 PPL_ASSERT(indexes[new_hint] != unused_index); 00348 00349 return bisect_in(hint, new_hint, key); 00350 } 00351 00352 PPL::CO_Tree::tree_iterator 00353 PPL::CO_Tree::insert_precise(dimension_type key1, 00354 data_type_const_reference data1, 00355 tree_iterator itr) { 00356 PPL_ASSERT(key1 != unused_index); 00357 PPL_ASSERT(!empty()); 00358 00359 #ifndef NDEBUG 00360 tree_iterator itr2(*this); 00361 itr2.go_down_searching_key(key1); 00362 PPL_ASSERT(itr == itr2); 00363 #endif 00364 00365 if (itr.index() == key1) { 00366 *itr = data1; 00367 PPL_ASSERT(OK()); 00368 return itr; 00369 } 00370 00371 if (is_greater_than_ratio(size_ + 1, reserved_size, max_density_percent)) { 00372 00373 rebuild_bigger_tree(); 00374 00375 // itr was invalidated by the rebuild operation 00376 itr.get_root(); 00377 itr.go_down_searching_key(key1); 00378 00379 PPL_ASSERT(itr.index() != key1); 00380 } 00381 00382 PPL_ASSERT(!is_greater_than_ratio(size_ + 1, reserved_size, 00383 max_density_percent)); 00384 00385 size_++; 00386 00387 if (!itr.is_leaf()) { 00388 if (key1 < itr.index()) 00389 itr.get_left_child(); 00390 else 00391 itr.get_right_child(); 00392 PPL_ASSERT(itr.index() == unused_index); 00393 00394 itr.index() = key1; 00395 new (&(*itr)) data_type(data1); 00396 00397 } else { 00398 00399 itr = rebalance(itr, key1, data1); 00400 00401 itr.go_down_searching_key(key1); 00402 00403 PPL_ASSERT(itr.index() == key1); 00404 } 00405 PPL_ASSERT(OK()); 00406 00407 return itr; 00408 } 00409 00410 PPL::CO_Tree::iterator 00411 PPL::CO_Tree::erase(tree_iterator itr) { 00412 PPL_ASSERT(itr.index() != unused_index); 00413 00414 PPL_ASSERT(size_ != 0); 00415 00416 if (size_ == 1) { 00417 // Deleting the only element of this tree, now it is empty. 00418 clear(); 00419 return end(); 00420 } 00421 00422 if (is_less_than_ratio(size_ - 1, reserved_size, min_density_percent) 00423 && !is_greater_than_ratio(size_ - 1, reserved_size/2, 00424 max_density_percent)) { 00425 00426 const dimension_type key = itr.index(); 00427 00428 PPL_ASSERT(!is_greater_than_ratio(size_, reserved_size, 00429 max_density_percent)); 00430 00431 rebuild_smaller_tree(); 00432 itr.get_root(); 00433 itr.go_down_searching_key(key); 00434 00435 PPL_ASSERT(itr.index() == key); 00436 } 00437 00438 #ifndef NDEBUG 00439 if (size_ > 1) 00440 PPL_ASSERT(!is_less_than_ratio(size_ - 1, reserved_size, 00441 min_density_percent) 00442 || is_greater_than_ratio(size_ - 1, reserved_size/2, 00443 max_density_percent)); 00444 #endif 00445 00446 const dimension_type deleted_key = itr.index(); 00447 tree_iterator deleted_node = itr; 00448 (*itr).~data_type(); 00449 while (true) { 00450 dimension_type& current_key = itr.index(); 00451 data_type& current_data = *itr; 00452 if (itr.is_leaf()) 00453 break; 00454 itr.get_left_child(); 00455 if (itr.index() != unused_index) 00456 // The left child has a value. 00457 itr.follow_right_children_with_value(); 00458 else { 00459 // The left child has not a value, try the right child. 00460 itr.get_parent(); 00461 itr.get_right_child(); 00462 if (itr.index() != unused_index) 00463 // The right child has a value. 00464 itr.follow_left_children_with_value(); 00465 else { 00466 // The right child has not a value, too. 00467 itr.get_parent(); 00468 break; 00469 } 00470 } 00471 using std::swap; 00472 swap(current_key, itr.index()); 00473 move_data_element(current_data, *itr); 00474 } 00475 00476 PPL_ASSERT(itr.index() != unused_index); 00477 itr.index() = unused_index; 00478 --size_; 00479 00480 PPL_ASSERT(OK()); 00481 00482 itr = rebalance(itr, 0, Coefficient_zero()); 00483 00484 if (itr.get_offset() < deleted_node.get_offset()) 00485 // deleted_node is an ancestor of itr 00486 itr = deleted_node; 00487 00488 itr.go_down_searching_key(deleted_key); 00489 00490 iterator result(itr); 00491 00492 if (result.index() < deleted_key) 00493 ++result; 00494 00495 PPL_ASSERT(OK()); 00496 PPL_ASSERT(result == end() || result.index() > deleted_key); 00497 #ifndef NDEBUG 00498 if (!empty()) { 00499 iterator last = end(); 00500 --last; 00501 PPL_ASSERT((result == end()) == (last.index() < deleted_key)); 00502 } 00503 #endif 00504 00505 return result; 00506 } 00507 00508 void 00509 PPL::CO_Tree::init(dimension_type reserved_size1) { 00510 00511 if (reserved_size1 == 0) { 00512 indexes = NULL; 00513 data = NULL; 00514 size_ = 0; 00515 reserved_size = 0; 00516 max_depth = 0; 00517 } else { 00518 max_depth = integer_log2(reserved_size1) + 1; 00519 00520 size_ = 0; 00521 reserved_size = (static_cast<dimension_type>(1) << max_depth) - 1; 00522 indexes = new dimension_type[reserved_size + 2]; 00523 try { 00524 data = data_allocator.allocate(reserved_size + 1); 00525 } catch (...) { 00526 delete[] indexes; 00527 throw; 00528 } 00529 // Mark all pairs as unused. 00530 for (dimension_type i = 1; i <= reserved_size; ++i) 00531 indexes[i] = unused_index; 00532 00533 // These are used as markers by iterators. 00534 indexes[0] = 0; 00535 indexes[reserved_size + 1] = 0; 00536 } 00537 00538 refresh_cached_iterators(); 00539 00540 PPL_ASSERT(structure_OK()); 00541 } 00542 00543 void 00544 PPL::CO_Tree::destroy() { 00545 00546 if (reserved_size != 0) { 00547 for (dimension_type i = 1; i <= reserved_size; ++i) { 00548 if (indexes[i] != unused_index) 00549 data[i].~data_type(); 00550 } 00551 00552 delete[] indexes; 00553 data_allocator.deallocate(data, reserved_size + 1); 00554 } 00555 } 00556 00557 bool 00558 PPL::CO_Tree::structure_OK() const { 00559 00560 if (size_ > reserved_size) 00561 return false; 00562 00563 if (reserved_size == 0) { 00564 if (indexes != NULL) 00565 return false; 00566 if (data != NULL) 00567 return false; 00568 if (max_depth != 0) 00569 return false; 00570 00571 return true; 00572 } 00573 00574 if (reserved_size < 3) 00575 return false; 00576 00577 if (reserved_size != (static_cast<dimension_type>(1) << max_depth) - 1) 00578 return false; 00579 00580 if (data == NULL) 00581 return false; 00582 00583 if (indexes == NULL) 00584 return false; 00585 00586 if (max_depth == 0) 00587 return false; 00588 00589 if (size_ == 0) { 00590 00591 // This const_cast could be removed by adding a const_tree_iterator, 00592 // but it would add much code duplication without a real need. 00593 tree_iterator itr(*const_cast<CO_Tree*>(this)); 00594 if (itr.index() != unused_index) 00595 return false; 00596 00597 } else { 00598 // This const_cast could be removed by adding a const_tree_iterator, 00599 // but it would add much code duplication without a real need. 00600 tree_iterator itr(*const_cast<CO_Tree*>(this)); 00601 dimension_type real_size = count_used_in_subtree(itr); 00602 if (real_size != size_) 00603 // There are \p real_size elements in the tree that are reachable by the 00604 // root, but size is \p size. 00605 return false; 00606 } 00607 00608 if (size_ != 0) { 00609 const_iterator itr = begin(); 00610 const_iterator itr_end = end(); 00611 00612 if (itr != itr_end) { 00613 dimension_type last_index = itr.index(); 00614 for (++itr; itr != itr_end; ++itr) { 00615 if (last_index >= itr.index()) 00616 // Found index \p itr->first after index \p last_index. 00617 return false; 00618 last_index = itr.index(); 00619 } 00620 } 00621 } 00622 00623 if (const_iterator(cached_end) != const_iterator(*this, reserved_size + 1)) 00624 return false; 00625 if (cached_const_end != const_iterator(*this, reserved_size + 1)) 00626 return false; 00627 00628 return true; 00629 } 00630 00631 bool 00632 PPL::CO_Tree::OK() const { 00633 00634 if (!structure_OK()) 00635 return false; 00636 00637 { 00638 dimension_type real_size = 0; 00639 00640 for (const_iterator itr = begin(), itr_end = end(); itr != itr_end; ++itr) 00641 ++real_size; 00642 00643 if (real_size != size_) 00644 // There are \p real_size elements in the tree, but size is \p size. 00645 return false; 00646 } 00647 00648 if (reserved_size > 0) { 00649 if (is_greater_than_ratio(size_, reserved_size, max_density_percent) 00650 && reserved_size != 3) 00651 // Found too high density. 00652 return false; 00653 if (is_less_than_ratio(size_, reserved_size, min_density_percent) 00654 && !is_greater_than_ratio(size_, reserved_size/2, max_density_percent)) 00655 // Found too low density 00656 return false; 00657 } 00658 00659 return true; 00660 } 00661 00662 unsigned 00663 PPL::CO_Tree::integer_log2(dimension_type n) { 00664 PPL_ASSERT(n != 0); 00665 unsigned result = 0; 00666 while (n != 1) { 00667 n /= 2; 00668 ++result; 00669 } 00670 return result; 00671 } 00672 00673 void 00674 PPL::CO_Tree::dump_subtree(tree_iterator itr) { 00675 if (!itr.is_leaf()) { 00676 itr.get_left_child(); 00677 dump_subtree(itr); 00678 itr.get_parent(); 00679 } 00680 std::cout << "At depth: " << itr.depth(); 00681 if (itr.index() == unused_index) 00682 std::cout << " (no data)" << std::endl; 00683 else 00684 std::cout << " pair (" << itr.index() << "," << *itr << ")" << std::endl; 00685 if (!itr.is_leaf()) { 00686 itr.get_right_child(); 00687 dump_subtree(itr); 00688 itr.get_parent(); 00689 } 00690 } 00691 00692 void 00693 PPL::CO_Tree::rebuild_bigger_tree() { 00694 if (reserved_size == 0) { 00695 init(3); 00696 PPL_ASSERT(structure_OK()); 00697 return; 00698 } 00699 00700 dimension_type new_reserved_size = reserved_size*2 + 1; 00701 00702 dimension_type* new_indexes = new dimension_type[new_reserved_size + 2]; 00703 00704 data_type* new_data; 00705 00706 try { 00707 new_data = data_allocator.allocate(new_reserved_size + 1); 00708 } catch (...) { 00709 delete[] new_indexes; 00710 throw; 00711 } 00712 00713 new_indexes[1] = unused_index; 00714 00715 for (dimension_type i = 1, j = 2; i <= reserved_size; ++i, ++j) { 00716 new_indexes[j] = indexes[i]; 00717 if (indexes[i] != unused_index) 00718 move_data_element(new_data[j], data[i]); 00719 ++j; 00720 new_indexes[j] = unused_index; 00721 } 00722 00723 // These are used as markers by iterators. 00724 new_indexes[0] = 0; 00725 new_indexes[new_reserved_size + 1] = 0; 00726 00727 delete[] indexes; 00728 data_allocator.deallocate(data, reserved_size + 1); 00729 00730 indexes = new_indexes; 00731 data = new_data; 00732 reserved_size = new_reserved_size; 00733 ++max_depth; 00734 00735 refresh_cached_iterators(); 00736 00737 PPL_ASSERT(structure_OK()); 00738 } 00739 00740 PPL::CO_Tree::tree_iterator 00741 PPL::CO_Tree::rebalance(tree_iterator itr, dimension_type key, 00742 data_type_const_reference value) { 00743 // Trees with reserved size 3 need not to be rebalanced. 00744 // This check is needed because they can't be shrunk, so they may violate 00745 // the density thresholds, and this would prevent the following while from 00746 // working correctly. 00747 if (reserved_size == 3) { 00748 PPL_ASSERT(OK()); 00749 return tree_iterator(*this); 00750 } 00751 PPL_ASSERT(itr.index() == unused_index || itr.is_leaf()); 00752 height_t itr_depth_minus_1 = itr.depth() - 1; 00753 height_t height = max_depth - itr_depth_minus_1; 00754 dimension_type subtree_size; 00755 dimension_type subtree_reserved_size = (static_cast<dimension_type>(1) 00756 << height) - 1; 00757 const bool deleting = itr.index() == unused_index; 00758 PPL_ASSERT(deleting || key != unused_index); 00759 if (deleting) 00760 subtree_size = 0; 00761 else 00762 // The existing element and the element with index key we want to add. 00763 subtree_size = 2; 00764 00765 while (is_greater_than_ratio(subtree_size, subtree_reserved_size, 00766 max_density_percent 00767 + ((itr_depth_minus_1 00768 * (100 - max_density_percent)) 00769 / (max_depth - 1))) 00770 || is_less_than_ratio(subtree_size, subtree_reserved_size, 00771 min_density_percent 00772 - ((itr_depth_minus_1 00773 * (min_density_percent 00774 - min_leaf_density_percent)) 00775 / (max_depth - 1)))) { 00776 // The density in the tree is correct, so the while condition is always 00777 // false for the root. 00778 PPL_ASSERT(itr_depth_minus_1 != 0); 00779 bool is_right_brother = itr.is_right_child(); 00780 itr.get_parent(); 00781 if (is_right_brother) 00782 itr.get_left_child(); 00783 else 00784 itr.get_right_child(); 00785 subtree_size += count_used_in_subtree(itr); 00786 itr.get_parent(); 00787 PPL_ASSERT(itr.index() != unused_index); 00788 ++subtree_size; 00789 subtree_reserved_size = 2*subtree_reserved_size + 1; 00790 --itr_depth_minus_1; 00791 PPL_ASSERT(itr.depth() - 1 == itr_depth_minus_1); 00792 } 00793 00794 // Now the subtree rooted at itr has been chosen as the subtree to be 00795 // rebalanced. 00796 00797 // Step 1: compact elements of this subtree in the rightmost end, from right 00798 // to left. 00799 dimension_type last_index_in_subtree 00800 = itr.dfs_index() + itr.get_offset() - 1; 00801 00802 dimension_type first_unused 00803 = compact_elements_in_the_rightmost_end(last_index_in_subtree, 00804 subtree_size, key, value, 00805 !deleting); 00806 00807 // Step 2: redistribute the elements, from left to right. 00808 redistribute_elements_in_subtree(itr.dfs_index(), subtree_size, 00809 first_unused + 1, key, value, 00810 first_unused != last_index_in_subtree 00811 - subtree_size); 00812 00813 PPL_ASSERT(OK()); 00814 00815 return itr; 00816 } 00817 00818 PPL::dimension_type 00819 PPL::CO_Tree 00820 ::compact_elements_in_the_rightmost_end(dimension_type last_in_subtree, 00821 dimension_type subtree_size, 00822 dimension_type key, 00823 data_type_const_reference value, 00824 bool add_element) { 00825 00826 PPL_ASSERT(subtree_size != 0); 00827 00828 PPL_ASSERT(subtree_size != 1 || !add_element); 00829 00830 dimension_type* last_index_in_subtree = &(indexes[last_in_subtree]); 00831 data_type* last_data_in_subtree = &(data[last_in_subtree]); 00832 00833 dimension_type* first_unused_index = last_index_in_subtree; 00834 data_type* first_unused_data = last_data_in_subtree; 00835 00836 while (*last_index_in_subtree == unused_index) { 00837 --last_index_in_subtree; 00838 --last_data_in_subtree; 00839 } 00840 00841 // From now on, last_index_in_subtree and last_data_in_subtree point to the 00842 // rightmost node with a value in the subtree. first_unused_index and 00843 // first_unused_data point to the rightmost unused node in the subtree. 00844 00845 if (add_element) 00846 while (subtree_size != 0) { 00847 --subtree_size; 00848 if (last_index_in_subtree == indexes || key > *last_index_in_subtree) { 00849 if (last_index_in_subtree == indexes 00850 || last_index_in_subtree != first_unused_index) { 00851 PPL_ASSERT(first_unused_index != indexes); 00852 PPL_ASSERT(*first_unused_index == unused_index); 00853 *first_unused_index = key; 00854 new (first_unused_data) data_type(value); 00855 --first_unused_index; 00856 --first_unused_data; 00857 } 00858 break; 00859 } else { 00860 if (last_index_in_subtree != first_unused_index) { 00861 PPL_ASSERT(first_unused_index != indexes); 00862 PPL_ASSERT(last_index_in_subtree != indexes); 00863 PPL_ASSERT(*first_unused_index == unused_index); 00864 *first_unused_index = *last_index_in_subtree; 00865 *last_index_in_subtree = unused_index; 00866 move_data_element(*first_unused_data, *last_data_in_subtree); 00867 } 00868 --last_index_in_subtree; 00869 --last_data_in_subtree; 00870 while (*last_index_in_subtree == unused_index) { 00871 --last_index_in_subtree; 00872 --last_data_in_subtree; 00873 } 00874 --first_unused_index; 00875 --first_unused_data; 00876 } 00877 } 00878 while (subtree_size != 0) { 00879 if (last_index_in_subtree != first_unused_index) { 00880 PPL_ASSERT(first_unused_index != indexes); 00881 PPL_ASSERT(last_index_in_subtree != indexes); 00882 PPL_ASSERT(*first_unused_index == unused_index); 00883 *first_unused_index = *last_index_in_subtree; 00884 *last_index_in_subtree = unused_index; 00885 move_data_element(*first_unused_data, *last_data_in_subtree); 00886 } 00887 --last_index_in_subtree; 00888 --last_data_in_subtree; 00889 while (*last_index_in_subtree == unused_index) { 00890 --last_index_in_subtree; 00891 --last_data_in_subtree; 00892 } 00893 --first_unused_index; 00894 --first_unused_data; 00895 --subtree_size; 00896 } 00897 00898 ptrdiff_t distance = first_unused_index - indexes; 00899 PPL_ASSERT(distance >= 0); 00900 return static_cast<dimension_type>(distance); 00901 } 00902 00903 void 00904 PPL::CO_Tree::redistribute_elements_in_subtree( 00905 dimension_type root_index, 00906 dimension_type subtree_size, 00907 dimension_type last_used, 00908 dimension_type key, 00909 data_type_const_reference value, 00910 bool add_element) { 00911 00912 // This is static and with static allocation, to improve performance. 00913 // sizeof_to_bits(sizeof(dimension_type)) is the maximum k such that 00914 // 2^k-1 is a dimension_type, so it is the maximum tree height. 00915 // For each node level, the stack may contain up to two element (one for the 00916 // subtree rooted at the right son of a node of that level, and one for the 00917 // node itself). An additional element can be at the top of the tree. 00918 static std::pair<dimension_type,dimension_type> 00919 stack[2U * sizeof_to_bits(sizeof(dimension_type)) + 1U]; 00920 00921 std::pair<dimension_type,dimension_type>* stack_first_empty = stack; 00922 00923 // A pair (n, i) in the stack means to visit the subtree with root index i 00924 // and size n. 00925 00926 PPL_ASSERT(subtree_size != 0); 00927 00928 stack_first_empty->first = subtree_size; 00929 stack_first_empty->second = root_index; 00930 ++stack_first_empty; 00931 00932 while (stack_first_empty != stack) { 00933 00934 --stack_first_empty; 00935 00936 // Implement 00937 // 00938 // <CODE> 00939 // top_n = stack.top().first; 00940 // top_i = stack.top().second; 00941 // </CODE> 00942 const dimension_type top_n = stack_first_empty->first; 00943 const dimension_type top_i = stack_first_empty->second; 00944 00945 PPL_ASSERT(top_n != 0); 00946 if (top_n == 1) { 00947 if (add_element 00948 && (last_used > reserved_size || indexes[last_used] > key)) { 00949 PPL_ASSERT(last_used != top_i); 00950 PPL_ASSERT(indexes[top_i] == unused_index); 00951 add_element = false; 00952 indexes[top_i] = key; 00953 new (&(data[top_i])) data_type(value); 00954 } else { 00955 if (last_used != top_i) { 00956 PPL_ASSERT(indexes[top_i] == unused_index); 00957 indexes[top_i] = indexes[last_used]; 00958 indexes[last_used] = unused_index; 00959 move_data_element(data[top_i], data[last_used]); 00960 } 00961 ++last_used; 00962 } 00963 } else { 00964 PPL_ASSERT(stack_first_empty + 2 00965 < stack + sizeof(stack)/sizeof(stack[0])); 00966 00967 const dimension_type offset = (top_i & -top_i) / 2; 00968 const dimension_type half = (top_n + 1) / 2; 00969 00970 PPL_ASSERT(half > 0); 00971 00972 // Right subtree 00973 PPL_ASSERT(top_n - half > 0); 00974 stack_first_empty->first = top_n - half; 00975 stack_first_empty->second = top_i + offset; 00976 ++stack_first_empty; 00977 00978 // Root of the current subtree 00979 stack_first_empty->first = 1; 00980 stack_first_empty->second = top_i; 00981 ++stack_first_empty; 00982 00983 // Left subtree 00984 if (half - 1 != 0) { 00985 stack_first_empty->first = half - 1; 00986 stack_first_empty->second = top_i - offset; 00987 ++stack_first_empty; 00988 } 00989 } 00990 } 00991 00992 PPL_ASSERT(!add_element); 00993 } 00994 00995 void 00996 PPL::CO_Tree::move_data_from(CO_Tree& tree) { 00997 PPL_ASSERT(size_ == 0); 00998 if (tree.size_ == 0) 00999 return; 01000 01001 tree_iterator root(*this); 01002 01003 dimension_type source_index = 1; 01004 while (tree.indexes[source_index] == unused_index) 01005 ++source_index; 01006 01007 // This is static and with static allocation, to improve performance. 01008 // sizeof_to_bits(sizeof(dimension_type)) is the maximum k such that 2^k-1 is a 01009 // dimension_type, so it is the maximum tree height. 01010 // For each node level, the stack may contain up to 4 elements: two elements 01011 // with operation 0, one element with operation 2 and one element 01012 // with operation 3. An additional element with operation 1 can be at the 01013 // top of the tree. 01014 static std::pair<dimension_type, signed char> 01015 stack[5U * sizeof_to_bits(sizeof(dimension_type))]; 01016 01017 dimension_type stack_first_empty = 0; 01018 01019 // A pair (n, operation) in the stack means: 01020 // 01021 // * Go to the parent, if operation is 0. 01022 // * Go to the left child, then visit the current tree (with size n), if 01023 // operation is 1. 01024 // * Go to the right child, then visit the current tree (with size n), if 01025 // operation is 2. 01026 // * Visit the current tree (with size n), if operation is 3. 01027 01028 stack[0].first = tree.size_; 01029 stack[0].second = 3; 01030 ++stack_first_empty; 01031 01032 while (stack_first_empty != 0) { 01033 01034 // Implement 01035 // 01036 // <CODE> 01037 // top_n = stack.top().first; 01038 // top_operation = stack.top().second; 01039 // </CODE> 01040 const dimension_type top_n = stack[stack_first_empty - 1].first; 01041 const signed char top_operation = stack[stack_first_empty - 1].second; 01042 01043 switch (top_operation) { 01044 01045 case 0: 01046 root.get_parent(); 01047 --stack_first_empty; 01048 continue; 01049 01050 case 1: 01051 root.get_left_child(); 01052 break; 01053 01054 case 2: 01055 root.get_right_child(); 01056 break; 01057 01058 #ifndef NDEBUG 01059 case 3: 01060 break; 01061 01062 default: 01063 PPL_UNREACHABLE; 01064 break; 01065 #endif 01066 } 01067 01068 // We now visit the current tree 01069 01070 if (top_n == 0) { 01071 --stack_first_empty; 01072 } else { 01073 if (top_n == 1) { 01074 PPL_ASSERT(root.index() == unused_index); 01075 PPL_ASSERT(tree.indexes[source_index] != unused_index); 01076 root.index() = tree.indexes[source_index]; 01077 tree.indexes[source_index] = unused_index; 01078 move_data_element(*root, tree.data[source_index]); 01079 PPL_ASSERT(source_index <= tree.reserved_size); 01080 ++source_index; 01081 while (tree.indexes[source_index] == unused_index) 01082 ++source_index; 01083 --stack_first_empty; 01084 } else { 01085 PPL_ASSERT(stack_first_empty + 3 < sizeof(stack)/sizeof(stack[0])); 01086 01087 const dimension_type half = (top_n + 1) / 2; 01088 stack[stack_first_empty - 1].second = 0; 01089 stack[stack_first_empty ] = std::make_pair(top_n - half, 2); 01090 stack[stack_first_empty + 1] = std::make_pair(1, 3); 01091 stack[stack_first_empty + 2].second = 0; 01092 stack[stack_first_empty + 3] = std::make_pair(half - 1, 1); 01093 stack_first_empty += 4; 01094 } 01095 } 01096 } 01097 size_ = tree.size_; 01098 tree.size_ = 0; 01099 PPL_ASSERT(tree.structure_OK()); 01100 PPL_ASSERT(structure_OK()); 01101 } 01102 01103 void 01104 PPL::CO_Tree::copy_data_from(const CO_Tree& x) { 01105 PPL_ASSERT(size_ == 0); 01106 PPL_ASSERT(reserved_size == x.reserved_size); 01107 PPL_ASSERT(structure_OK()); 01108 01109 if (x.size_ == 0) { 01110 PPL_ASSERT(OK()); 01111 return; 01112 } 01113 01114 for (dimension_type i = x.reserved_size; i > 0; --i) 01115 if (x.indexes[i] != unused_index) { 01116 indexes[i] = x.indexes[i]; 01117 new (&(data[i])) data_type(x.data[i]); 01118 } else { 01119 PPL_ASSERT(indexes[i] == unused_index); 01120 } 01121 01122 size_ = x.size_; 01123 PPL_ASSERT(OK()); 01124 } 01125 01126 PPL::dimension_type 01127 PPL::CO_Tree::count_used_in_subtree(tree_iterator itr) { 01128 dimension_type n = 0; 01129 01130 const dimension_type k = itr.get_offset(); 01131 const dimension_type root_index = itr.dfs_index(); 01132 01133 // The complete subtree rooted at itr has 2*k - 1 nodes. 01134 01135 PPL_ASSERT(root_index > (k - 1)); 01136 01137 dimension_type* current_index = &(itr.tree.indexes[root_index - (k - 1)]); 01138 01139 for (dimension_type j = 2*k - 1; j > 0; --j, ++current_index) 01140 if (*current_index != unused_index) 01141 ++n; 01142 01143 return n; 01144 } 01145 01146 bool 01147 PPL::CO_Tree::const_iterator::OK() const { 01148 #if PPL_CO_TREE_EXTRA_DEBUG 01149 if (tree == 0) { 01150 if (current_index != 0) 01151 return false; 01152 if (current_data != 0) 01153 return false; 01154 } else 01155 if (tree->reserved_size == 0) { 01156 if (current_index != 1 + (dimension_type*)0 01157 || current_data != 1 + (data_type*)0) 01158 return false; 01159 } else { 01160 if (current_index <= &(tree->indexes[0])) 01161 return false; 01162 if (current_index > &(tree->indexes[tree->reserved_size + 1])) 01163 return false; 01164 if (current_data <= &(tree->data[0])) 01165 return false; 01166 if (current_data > &(tree->data[tree->reserved_size + 1])) 01167 return false; 01168 if (*current_index == unused_index) 01169 return false; 01170 if (current_index - tree->indexes != current_data - tree->data) 01171 return false; 01172 } 01173 #endif 01174 return true; 01175 } 01176 01177 bool 01178 PPL::CO_Tree::iterator::OK() const { 01179 #if PPL_CO_TREE_EXTRA_DEBUG 01180 if (tree == 0) { 01181 if (current_index != 0) 01182 return false; 01183 if (current_data != 0) 01184 return false; 01185 } else 01186 if (tree->reserved_size == 0) { 01187 if (current_index != 1 + (dimension_type*)0 01188 || current_data != 1 + (data_type*)0) 01189 return false; 01190 } else { 01191 if (current_index <= &(tree->indexes[0])) 01192 return false; 01193 if (current_index > &(tree->indexes[tree->reserved_size + 1])) 01194 return false; 01195 if (current_data <= &(tree->data[0])) 01196 return false; 01197 if (current_data > &(tree->data[tree->reserved_size + 1])) 01198 return false; 01199 if (*current_index == unused_index) 01200 return false; 01201 if (current_index - tree->indexes != current_data - tree->data) 01202 return false; 01203 } 01204 #endif 01205 return true; 01206 } 01207 01208 bool 01209 PPL::CO_Tree::tree_iterator::OK() const { 01210 if (i == 0 || i > tree.reserved_size) 01211 return false; 01212 01213 // This assumes two's complement encoding. 01214 dimension_type correct_offset = i & -i; 01215 01216 if (offset != correct_offset) 01217 return false; 01218 01219 return true; 01220 } 01221 01222 void 01223 PPL::CO_Tree::tree_iterator::go_down_searching_key(dimension_type key) { 01224 // *this points to a node, so the tree is not empty. 01225 PPL_ASSERT(!tree.empty()); 01226 PPL_ASSERT(key != unused_index); 01227 PPL_ASSERT(index() != unused_index); 01228 while (!is_leaf()) { 01229 if (key == index()) 01230 break; 01231 if (key < index()) { 01232 get_left_child(); 01233 if (index() == unused_index) { 01234 get_parent(); 01235 break; 01236 } 01237 } else { 01238 get_right_child(); 01239 if (index() == unused_index) { 01240 get_parent(); 01241 break; 01242 } 01243 } 01244 } 01245 }