Commit 5d3d583b88e74ae2dcf9f489ca7fd801b2262f9f

Authored by m-holger
1 parent 0be4d2fe

Refactor `NNTreeImpl::binarySearch`: replace function pointer with `bool` flag, …

…simplify iteration logic, update to use `Dictionary` API, and streamline error checks.
libqpdf/NNTree.cc
... ... @@ -593,19 +593,19 @@ NNTreeImpl::binarySearch(
593 593 Array const& items,
594 594 size_t num_items,
595 595 bool return_prev_if_not_found,
596   - int (NNTreeImpl::*compare)(QPDFObjectHandle const& key, Array const& arr, int item) const) const
  596 + bool search_kids) const
597 597 {
598 598 size_t max_idx = std::bit_ceil(num_items);
599 599  
600 600 int step = static_cast<int>(max_idx / 2);
601   - size_t checks = max_idx;
  601 + int checks = static_cast<int>(std::bit_width(max_idx)); // AppImage gcc version returns size_t
602 602 int idx = step;
603 603 int found_idx = -1;
604 604  
605   - while (checks > 0) {
  605 + for (int i = 0; i < checks; ++i) {
606 606 int status = -1;
607 607 if (std::cmp_less(idx, num_items)) {
608   - status = (this->*compare)(key, items, idx);
  608 + status = search_kids ? compareKeyKid(key, items, idx) : compareKeyItem(key, items, idx);
609 609 if (status == 0) {
610 610 return idx;
611 611 }
... ... @@ -613,21 +613,9 @@ NNTreeImpl::binarySearch(
613 613 found_idx = idx;
614 614 }
615 615 }
616   - checks >>= 1;
617   - if (checks > 0) {
618   - step >>= 1;
619   - if (step == 0) {
620   - step = 1;
621   - }
622   -
623   - if (status < 0) {
624   - idx -= step;
625   - } else {
626   - idx += step;
627   - }
628   - }
  616 + step = std::max(step / 2, 1);
  617 + idx += status * step;
629 618 }
630   -
631 619 return return_prev_if_not_found ? found_idx : -1;
632 620 }
633 621  
... ... @@ -643,10 +631,11 @@ NNTreeImpl::compareKeyItem(QPDFObjectHandle const&amp; key, Array const&amp; items, int
643 631 int
644 632 NNTreeImpl::compareKeyKid(QPDFObjectHandle const& key, Array const& kids, int idx) const
645 633 {
646   - if (!kids[idx].isDictionary()) {
  634 + Dictionary kid = kids[idx];
  635 + if (!kid) {
647 636 error(oh, "invalid kid at index " + std::to_string(idx));
648 637 }
649   - Array limits = kids[idx].getKey("/Limits");
  638 + Array limits = kid["/Limits"];
650 639 if (!(keyValid(limits[0]) && keyValid(limits[1]))) {
651 640 error(kids[idx], "node is missing /Limits");
652 641 }
... ... @@ -719,8 +708,7 @@ NNTreeImpl::findInternal(QPDFObjectHandle const&amp; key, bool return_prev_if_not_fo
719 708 Array items = node[itemsKey()];
720 709 size_t nitems = items.size();
721 710 if (nitems > 1) {
722   - int idx = binarySearch(
723   - key, items, nitems / 2, return_prev_if_not_found, &NNTreeImpl::compareKeyItem);
  711 + int idx = binarySearch(key, items, nitems / 2, return_prev_if_not_found, false);
724 712 if (idx >= 0) {
725 713 result.setItemNumber(node, 2 * idx);
726 714 if (!result.impl.keyValid(result.ivalue.first)) {
... ... @@ -738,7 +726,7 @@ NNTreeImpl::findInternal(QPDFObjectHandle const&amp; key, bool return_prev_if_not_fo
738 726 if (nkids == 0) {
739 727 error(node, "bad node during find");
740 728 }
741   - int idx = binarySearch(key, kids, nkids, true, &NNTreeImpl::compareKeyKid);
  729 + int idx = binarySearch(key, kids, nkids, true, true);
742 730 if (idx == -1) {
743 731 error(node, "unexpected -1 from binary search of kids; limits may by wrong");
744 732 }
... ...
libqpdf/qpdf/NNTree.hh
... ... @@ -170,8 +170,7 @@ class NNTreeImpl final
170 170 qpdf::Array const& items,
171 171 size_t num_items,
172 172 bool return_prev_if_not_found,
173   - int (NNTreeImpl::*compare)(QPDFObjectHandle const& key, qpdf::Array const& arr, int item)
174   - const) const;
  173 + bool search_kids) const;
175 174 int compareKeyItem(QPDFObjectHandle const& key, qpdf::Array const& items, int idx) const;
176 175 int compareKeyKid(QPDFObjectHandle const& key, qpdf::Array const& items, int idx) const;
177 176 void warn(QPDFObjectHandle const& node, std::string const& msg);
... ...