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 422 throw std::logic_error("attempt made to remove an invalid iterator");
423 423 }
424 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 427 impl.error(node, "found short items array while removing an item");
428 428 }
429 429  
... ... @@ -437,20 +437,17 @@ NNTreeIterator::remove()
437 437 if (item_number == 0 || item_number == nitems) {
438 438 // We removed either the first or last item of an items array that remains non-empty, so
439 439 // we have to adjust limits.
440   - QTC::TC("qpdf", "NNTree remove reset limits");
441 440 resetLimits(node, lastPathElement());
442 441 }
443 442  
444 443 if (item_number == nitems) {
445 444 // We removed the last item of a non-empty items array, so advance to the successor of
446 445 // the previous item.
447   - QTC::TC("qpdf", "NNTree erased last item");
448 446 item_number -= 2;
449 447 increment(false);
450 448 } else if (item_number < nitems) {
451 449 // We don't have to do anything since the removed item's successor now occupies its
452 450 // former location.
453   - QTC::TC("qpdf", "NNTree erased non-last item");
454 451 updateIValue();
455 452 } else {
456 453 // We already checked to ensure this condition would not happen.
... ... @@ -461,61 +458,51 @@ NNTreeIterator::remove()
461 458  
462 459 if (path.empty()) {
463 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 461 setItemNumber(impl.oh, -1);
466 462 return;
467 463 }
468 464  
469   - QTC::TC("qpdf", "NNTree items is empty after remove");
470   -
471 465 // We removed the last item from this items array, so we need to remove this node from the
472 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 468 auto element = lastPathElement();
476 469 auto parent = element;
477 470 --parent;
478 471 auto kids = element->node.getKey("/Kids");
479 472 kids.eraseItem(element->kid_number);
480   - auto nkids = kids.getArrayNItems();
  473 + auto nkids = kids.size();
481 474 if (nkids > 0) {
482 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 477 resetLimits(element->node, parent);
486 478 }
487   - if (element->kid_number == nkids) {
  479 + if (std::cmp_equal(element->kid_number, nkids)) {
488 480 // Move to the successor of the last child of the previous kid.
489   - setItemNumber(QPDFObjectHandle(), -1);
  481 + setItemNumber({}, -1);
490 482 --element->kid_number;
491   - deepen(kids.getArrayItem(element->kid_number), false, true);
  483 + deepen(kids[element->kid_number], false, true);
492 484 if (valid()) {
493 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 488 } else {
501 489 // Next kid is in deleted kid's position
502   - QTC::TC("qpdf", "NNTree erased non-last kid");
503 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 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 497 element->node.removeKey("/Kids");
510 498 element->node.replaceKey(impl.details.itemsKey(), QPDFObjectHandle::newArray());
511 499 path.clear();
512 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 534 NNTree limits didn't change 0
535 535 NNTree increment end() 0
536 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 538 NNTree remove limits from root 0
549 539 QPDFPageObjectHelper unresolved names 0
550 540 QPDFPageObjectHelper resolving unresolved 0
... ...