Commit f110a23c48d74157b999715bf451118c920fa169

Authored by m-holger
1 parent 0d8b0882

Refactor `NNTree::remove`: simplify logic, replace `getArrayItem` and `getArrayN…

…Items` with subscript operators, introduce `std::cmp` utilities, and remove redundant debug traces.
libqpdf/NNTree.cc
@@ -422,8 +422,8 @@ NNTreeIterator::remove() @@ -422,8 +422,8 @@ NNTreeIterator::remove()
422 throw std::logic_error("attempt made to remove an invalid iterator"); 422 throw std::logic_error("attempt made to remove an invalid iterator");
423 } 423 }
424 auto items = node.getKey(impl.details.itemsKey()); 424 auto items = node.getKey(impl.details.itemsKey());
425 - int nitems = items.getArrayNItems();  
426 - if (item_number + 2 > nitems) { 425 + int nitems = static_cast<int>(items.size());
  426 + if (std::cmp_greater(item_number + 2, nitems)) {
427 impl.error(node, "found short items array while removing an item"); 427 impl.error(node, "found short items array while removing an item");
428 } 428 }
429 429
@@ -437,20 +437,17 @@ NNTreeIterator::remove() @@ -437,20 +437,17 @@ NNTreeIterator::remove()
437 if (item_number == 0 || item_number == nitems) { 437 if (item_number == 0 || item_number == nitems) {
438 // We removed either the first or last item of an items array that remains non-empty, so 438 // We removed either the first or last item of an items array that remains non-empty, so
439 // we have to adjust limits. 439 // we have to adjust limits.
440 - QTC::TC("qpdf", "NNTree remove reset limits");  
441 resetLimits(node, lastPathElement()); 440 resetLimits(node, lastPathElement());
442 } 441 }
443 442
444 if (item_number == nitems) { 443 if (item_number == nitems) {
445 // We removed the last item of a non-empty items array, so advance to the successor of 444 // We removed the last item of a non-empty items array, so advance to the successor of
446 // the previous item. 445 // the previous item.
447 - QTC::TC("qpdf", "NNTree erased last item");  
448 item_number -= 2; 446 item_number -= 2;
449 increment(false); 447 increment(false);
450 } else if (item_number < nitems) { 448 } else if (item_number < nitems) {
451 // We don't have to do anything since the removed item's successor now occupies its 449 // We don't have to do anything since the removed item's successor now occupies its
452 // former location. 450 // former location.
453 - QTC::TC("qpdf", "NNTree erased non-last item");  
454 updateIValue(); 451 updateIValue();
455 } else { 452 } else {
456 // We already checked to ensure this condition would not happen. 453 // We already checked to ensure this condition would not happen.
@@ -461,61 +458,51 @@ NNTreeIterator::remove() @@ -461,61 +458,51 @@ NNTreeIterator::remove()
461 458
462 if (path.empty()) { 459 if (path.empty()) {
463 // Special case: if this is the root node, we can leave it empty. 460 // Special case: if this is the root node, we can leave it empty.
464 - QTC::TC("qpdf", "NNTree erased all items on leaf/root");  
465 setItemNumber(impl.oh, -1); 461 setItemNumber(impl.oh, -1);
466 return; 462 return;
467 } 463 }
468 464
469 - QTC::TC("qpdf", "NNTree items is empty after remove");  
470 -  
471 // We removed the last item from this items array, so we need to remove this node from the 465 // We removed the last item from this items array, so we need to remove this node from the
472 // parent on up the tree. Then we need to position ourselves at the removed item's successor. 466 // parent on up the tree. Then we need to position ourselves at the removed item's successor.
473 - bool done = false;  
474 - while (!done) { 467 + while (true) {
475 auto element = lastPathElement(); 468 auto element = lastPathElement();
476 auto parent = element; 469 auto parent = element;
477 --parent; 470 --parent;
478 auto kids = element->node.getKey("/Kids"); 471 auto kids = element->node.getKey("/Kids");
479 kids.eraseItem(element->kid_number); 472 kids.eraseItem(element->kid_number);
480 - auto nkids = kids.getArrayNItems(); 473 + auto nkids = kids.size();
481 if (nkids > 0) { 474 if (nkids > 0) {
482 // The logic here is similar to the items case. 475 // The logic here is similar to the items case.
483 - if ((element->kid_number == 0) || (element->kid_number == nkids)) {  
484 - QTC::TC("qpdf", "NNTree erased first or last kid"); 476 + if (element->kid_number == 0 || std::cmp_equal(element->kid_number, nkids)) {
485 resetLimits(element->node, parent); 477 resetLimits(element->node, parent);
486 } 478 }
487 - if (element->kid_number == nkids) { 479 + if (std::cmp_equal(element->kid_number, nkids)) {
488 // Move to the successor of the last child of the previous kid. 480 // Move to the successor of the last child of the previous kid.
489 - setItemNumber(QPDFObjectHandle(), -1); 481 + setItemNumber({}, -1);
490 --element->kid_number; 482 --element->kid_number;
491 - deepen(kids.getArrayItem(element->kid_number), false, true); 483 + deepen(kids[element->kid_number], false, true);
492 if (valid()) { 484 if (valid()) {
493 increment(false); 485 increment(false);
494 - if (!valid()) {  
495 - QTC::TC("qpdf", "NNTree erased last item in tree");  
496 - } else {  
497 - QTC::TC("qpdf", "NNTree erased last kid");  
498 - } 486 + QTC::TC("qpdf", "NNTree erased last kid/item in tree", valid() ? 0 : 1);
499 } 487 }
500 } else { 488 } else {
501 // Next kid is in deleted kid's position 489 // Next kid is in deleted kid's position
502 - QTC::TC("qpdf", "NNTree erased non-last kid");  
503 deepen(kids.getArrayItem(element->kid_number), true, true); 490 deepen(kids.getArrayItem(element->kid_number), true, true);
504 } 491 }
505 - done = true;  
506 - } else if (parent == path.end()) { 492 + return;
  493 + }
  494 +
  495 + if (parent == path.end()) {
507 // We erased the very last item. Convert the root to an empty items array. 496 // We erased the very last item. Convert the root to an empty items array.
508 - QTC::TC("qpdf", "NNTree non-flat tree is empty after remove");  
509 element->node.removeKey("/Kids"); 497 element->node.removeKey("/Kids");
510 element->node.replaceKey(impl.details.itemsKey(), QPDFObjectHandle::newArray()); 498 element->node.replaceKey(impl.details.itemsKey(), QPDFObjectHandle::newArray());
511 path.clear(); 499 path.clear();
512 setItemNumber(impl.oh, -1); 500 setItemNumber(impl.oh, -1);
513 - done = true;  
514 - } else {  
515 - // Walk up the tree and continue  
516 - QTC::TC("qpdf", "NNTree remove walking up tree");  
517 - path.pop_back(); 501 + return;
518 } 502 }
  503 +
  504 + // Walk up the tree and continue
  505 + path.pop_back();
519 } 506 }
520 } 507 }
521 508
qpdf/qpdf.testcov
@@ -534,17 +534,7 @@ NNTree split second half kid 0 @@ -534,17 +534,7 @@ NNTree split second half kid 0
534 NNTree limits didn't change 0 534 NNTree limits didn't change 0
535 NNTree increment end() 0 535 NNTree increment end() 0
536 NNTree insertAfter inserts first 0 536 NNTree insertAfter inserts first 0
537 -NNTree remove reset limits 0  
538 -NNTree erased last item 0  
539 -NNTree erased non-last item 0  
540 -NNTree items is empty after remove 0  
541 -NNTree erased all items on leaf/root 0  
542 -NNTree erased first or last kid 0  
543 -NNTree erased last kid 0  
544 -NNTree erased non-last kid 0  
545 -NNTree non-flat tree is empty after remove 0  
546 -NNTree remove walking up tree 0  
547 -NNTree erased last item in tree 0 537 +NNTree erased last kid/item in tree 1
548 NNTree remove limits from root 0 538 NNTree remove limits from root 0
549 QPDFPageObjectHelper unresolved names 0 539 QPDFPageObjectHelper unresolved names 0
550 QPDFPageObjectHelper resolving unresolved 0 540 QPDFPageObjectHelper resolving unresolved 0