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,19 +593,19 @@ NNTreeImpl::binarySearch( | ||
| 593 | Array const& items, | 593 | Array const& items, |
| 594 | size_t num_items, | 594 | size_t num_items, |
| 595 | bool return_prev_if_not_found, | 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 | size_t max_idx = std::bit_ceil(num_items); | 598 | size_t max_idx = std::bit_ceil(num_items); |
| 599 | 599 | ||
| 600 | int step = static_cast<int>(max_idx / 2); | 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 | int idx = step; | 602 | int idx = step; |
| 603 | int found_idx = -1; | 603 | int found_idx = -1; |
| 604 | 604 | ||
| 605 | - while (checks > 0) { | 605 | + for (int i = 0; i < checks; ++i) { |
| 606 | int status = -1; | 606 | int status = -1; |
| 607 | if (std::cmp_less(idx, num_items)) { | 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 | if (status == 0) { | 609 | if (status == 0) { |
| 610 | return idx; | 610 | return idx; |
| 611 | } | 611 | } |
| @@ -613,21 +613,9 @@ NNTreeImpl::binarySearch( | @@ -613,21 +613,9 @@ NNTreeImpl::binarySearch( | ||
| 613 | found_idx = idx; | 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 | return return_prev_if_not_found ? found_idx : -1; | 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,10 +631,11 @@ NNTreeImpl::compareKeyItem(QPDFObjectHandle const& key, Array const& items, int | ||
| 643 | int | 631 | int |
| 644 | NNTreeImpl::compareKeyKid(QPDFObjectHandle const& key, Array const& kids, int idx) const | 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 | error(oh, "invalid kid at index " + std::to_string(idx)); | 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 | if (!(keyValid(limits[0]) && keyValid(limits[1]))) { | 639 | if (!(keyValid(limits[0]) && keyValid(limits[1]))) { |
| 651 | error(kids[idx], "node is missing /Limits"); | 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,8 +708,7 @@ NNTreeImpl::findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_fo | ||
| 719 | Array items = node[itemsKey()]; | 708 | Array items = node[itemsKey()]; |
| 720 | size_t nitems = items.size(); | 709 | size_t nitems = items.size(); |
| 721 | if (nitems > 1) { | 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 | if (idx >= 0) { | 712 | if (idx >= 0) { |
| 725 | result.setItemNumber(node, 2 * idx); | 713 | result.setItemNumber(node, 2 * idx); |
| 726 | if (!result.impl.keyValid(result.ivalue.first)) { | 714 | if (!result.impl.keyValid(result.ivalue.first)) { |
| @@ -738,7 +726,7 @@ NNTreeImpl::findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_fo | @@ -738,7 +726,7 @@ NNTreeImpl::findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_fo | ||
| 738 | if (nkids == 0) { | 726 | if (nkids == 0) { |
| 739 | error(node, "bad node during find"); | 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 | if (idx == -1) { | 730 | if (idx == -1) { |
| 743 | error(node, "unexpected -1 from binary search of kids; limits may by wrong"); | 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,8 +170,7 @@ class NNTreeImpl final | ||
| 170 | qpdf::Array const& items, | 170 | qpdf::Array const& items, |
| 171 | size_t num_items, | 171 | size_t num_items, |
| 172 | bool return_prev_if_not_found, | 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 | int compareKeyItem(QPDFObjectHandle const& key, qpdf::Array const& items, int idx) const; | 174 | int compareKeyItem(QPDFObjectHandle const& key, qpdf::Array const& items, int idx) const; |
| 176 | int compareKeyKid(QPDFObjectHandle const& key, qpdf::Array const& items, int idx) const; | 175 | int compareKeyKid(QPDFObjectHandle const& key, qpdf::Array const& items, int idx) const; |
| 177 | void warn(QPDFObjectHandle const& node, std::string const& msg); | 176 | void warn(QPDFObjectHandle const& node, std::string const& msg); |