Commit 5d3d583b88e74ae2dcf9f489ca7fd801b2262f9f
1 parent
0be4d2fe
Refactor `NNTreeImpl::binarySearch`: replace function pointer with `bool` flag, …
…simplify iteration logic, update to use `Dictionary` API, and streamline error checks.
Showing
2 changed files
with
12 additions
and
25 deletions
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& key, Array const& 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& 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& 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); | ... | ... |