| 544 | }; |
| 545 | |
| 546 | void CollectedItems::MergeItems(ItemOrdering &itemOrdering, |
| 547 | const GroupItemBase &toMerge, const OrderingHint &hint, |
| 548 | void *pComputedItemContext) |
| 549 | { |
| 550 | NewItems newItems; |
| 551 | |
| 552 | { |
| 553 | // First do expansion of nameless groupings, and caching of computed |
| 554 | // items, just as for the previously collected items. |
| 555 | CollectedItems newCollection{ {}, computedItems }; |
| 556 | CollectItems(newCollection, toMerge, hint, pComputedItemContext); |
| 557 | |
| 558 | // Try to merge each, resolving name collisions with items already in the |
| 559 | // tree, and collecting those with names that don't collide. |
| 560 | for (const auto &item : newCollection.items) |
| 561 | if (!MergeWithExistingItem(itemOrdering, item.visitNow)) |
| 562 | newItems.push_back({ item.visitNow, item.hint }); |
| 563 | } |
| 564 | |
| 565 | // Choose placements for items with NEW names. |
| 566 | |
| 567 | // First sort so that like named items are together, and for the same name, |
| 568 | // items with more specific ordering hints come earlier. |
| 569 | std::sort( newItems.begin(), newItems.end(), Comp ); |
| 570 | |
| 571 | // Outer loop over trial passes. |
| 572 | int iPass = -1; |
| 573 | bool force = false; |
| 574 | size_t oldSize = 0; |
| 575 | size_t endItemsCount = 0; |
| 576 | auto prevSize = newItems.size(); |
| 577 | while( !newItems.empty() ) |
| 578 | { |
| 579 | // If several items have the same hint, we try to preserve the sort by |
| 580 | // name (an internal identifier, not necessarily user visible), just to |
| 581 | // have some determinacy. That requires passing one or the other way |
| 582 | // over newItems. |
| 583 | bool descending = |
| 584 | ( iPass == OrderingHint::After || iPass == OrderingHint::Begin ); |
| 585 | |
| 586 | if ( descending ) |
| 587 | MergeItemsDescendingNamesPass(itemOrdering, |
| 588 | newItems, iPass, endItemsCount, force); |
| 589 | else |
| 590 | MergeItemsAscendingNamesPass(itemOrdering, |
| 591 | newItems, iPass, endItemsCount, force); |
| 592 | |
| 593 | auto newSize = newItems.size(); |
| 594 | ++iPass; |
| 595 | |
| 596 | if ( iPass == 0 ) |
| 597 | // Just tried insertion by preferences. Don't try it again. |
| 598 | oldSize = newSize; |
| 599 | else if ( iPass == OrderingHint::Unspecified ) { |
| 600 | if ( !force ) { |
| 601 | iPass = 0, oldSize = newSize; |
| 602 | // Are we really ready for the final pass? |
| 603 | bool progress = ( oldSize > newSize ); |
no test coverage detected