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,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&amp; key, Array const&amp; items, int @@ -643,10 +631,11 @@ NNTreeImpl::compareKeyItem(QPDFObjectHandle const&amp; key, Array const&amp; 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&amp; key, bool return_prev_if_not_fo @@ -719,8 +708,7 @@ NNTreeImpl::findInternal(QPDFObjectHandle const&amp; 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&amp; key, bool return_prev_if_not_fo @@ -738,7 +726,7 @@ NNTreeImpl::findInternal(QPDFObjectHandle const&amp; 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);