Commit f3a1139fd7deed394ff093e05a999176becaf63e

Authored by m-holger
1 parent f42de31c

Refactor `NNTreeImpl`: simplify `binarySearch` logic, use `size_t` for indices, …

…and improve `findInternal` readability.
libqpdf/NNTree.cc
  1 +#include <qpdf/assert_debug.h>
  2 +
1 3 #include <qpdf/NNTree.hh>
2 4  
  5 +#include <qpdf/QPDFObjectHandle_private.hh>
3 6 #include <qpdf/QPDF_private.hh>
4 7 #include <qpdf/QTC.hh>
5 8 #include <qpdf/QUtil.hh>
6 9  
  10 +#include <bit>
7 11 #include <exception>
  12 +#include <utility>
8 13  
9 14 static std::string
10 15 get_description(QPDFObjectHandle& node)
... ... @@ -718,59 +723,44 @@ int
718 723 NNTreeImpl::binarySearch(
719 724 QPDFObjectHandle key,
720 725 QPDFObjectHandle items,
721   - int num_items,
  726 + size_t num_items,
722 727 bool return_prev_if_not_found,
723 728 int (NNTreeImpl::*compare)(QPDFObjectHandle& key, QPDFObjectHandle& arr, int item))
724 729 {
725   - int max_idx = 1;
726   - while (max_idx < num_items) {
727   - max_idx <<= 1;
728   - }
  730 + size_t max_idx = std::bit_ceil(num_items);
729 731  
730   - int step = max_idx / 2;
731   - int checks = max_idx;
  732 + int step = static_cast<int>(max_idx / 2);
  733 + size_t checks = max_idx;
732 734 int idx = step;
733 735 int found_idx = -1;
734   - bool found = false;
735   - bool found_leq = false;
736   - int status = 0;
737 736  
738   - while ((!found) && (checks > 0)) {
739   - if (idx < num_items) {
  737 + while (checks > 0) {
  738 + int status = -1;
  739 + if (std::cmp_less(idx, num_items)) {
740 740 status = (this->*compare)(key, items, idx);
741   - if (status >= 0) {
742   - found_leq = true;
  741 + if (status == 0) {
  742 + return idx;
  743 + }
  744 + if (status > 0) {
743 745 found_idx = idx;
744 746 }
745   - } else {
746   - // consider item to be below anything after the top
747   - status = -1;
748 747 }
  748 + checks >>= 1;
  749 + if (checks > 0) {
  750 + step >>= 1;
  751 + if (step == 0) {
  752 + step = 1;
  753 + }
749 754  
750   - if (status == 0) {
751   - found = true;
752   - } else {
753   - checks >>= 1;
754   - if (checks > 0) {
755   - step >>= 1;
756   - if (step == 0) {
757   - step = 1;
758   - }
759   -
760   - if (status < 0) {
761   - idx -= step;
762   - } else {
763   - idx += step;
764   - }
  755 + if (status < 0) {
  756 + idx -= step;
  757 + } else {
  758 + idx += step;
765 759 }
766 760 }
767 761 }
768 762  
769   - if (found || (found_leq && return_prev_if_not_found)) {
770   - return found_idx;
771   - } else {
772   - return -1;
773   - }
  763 + return return_prev_if_not_found ? found_idx : -1;
774 764 }
775 765  
776 766 int
... ... @@ -826,28 +816,19 @@ NNTreeImpl::find(QPDFObjectHandle key, bool return_prev_if_not_found)
826 816 }
827 817  
828 818 NNTreeImpl::iterator
829   -NNTreeImpl::findInternal(QPDFObjectHandle key, bool return_prev_if_not_found)
  819 +NNTreeImpl::findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_found)
830 820 {
831 821 auto first_item = begin();
832 822 auto last_item = end();
833 823 if (first_item == end()) {
834   - // Empty
835 824 return end();
836   - } else if (
837   - first_item.valid() && details.keyValid(first_item->first) &&
  825 + }
  826 + if (first_item.valid() && details.keyValid(first_item->first) &&
838 827 details.compareKeys(key, first_item->first) < 0) {
839 828 // Before the first key
840 829 return end();
841   - } else if (
842   - last_item.valid() && details.keyValid(last_item->first) &&
843   - details.compareKeys(key, last_item->first) > 0) {
844   - // After the last key
845   - if (return_prev_if_not_found) {
846   - return last_item;
847   - } else {
848   - return end();
849   - }
850 830 }
  831 + qpdf_assert_debug(!last_item.valid());
851 832  
852 833 QPDFObjGen::set seen;
853 834 auto node = oh;
... ... @@ -855,36 +836,33 @@ NNTreeImpl::findInternal(QPDFObjectHandle key, bool return_prev_if_not_found)
855 836  
856 837 while (true) {
857 838 if (!seen.add(node)) {
858   - QTC::TC("qpdf", "NNTree loop in find");
859 839 error(node, "loop detected in find");
860 840 }
861 841  
862   - auto kids = node.getKey("/Kids");
863   - int nkids = kids.isArray() ? kids.getArrayNItems() : 0;
864 842 auto items = node.getKey(details.itemsKey());
865   - int nitems = items.isArray() ? items.getArrayNItems() : 0;
866   - if (nitems > 0) {
  843 + size_t nitems = items.size();
  844 + if (nitems > 1) {
867 845 int idx = binarySearch(
868 846 key, items, nitems / 2, return_prev_if_not_found, &NNTreeImpl::compareKeyItem);
869 847 if (idx >= 0) {
870 848 result.setItemNumber(node, 2 * idx);
871 849 }
872   - break;
873   - } else if (nkids > 0) {
  850 + return result;
  851 + }
  852 +
  853 + auto kids = node.getKey("/Kids");
  854 + size_t nkids = kids.isArray() ? kids.size() : 0;
  855 + if (nkids > 0) {
874 856 int idx = binarySearch(key, kids, nkids, true, &NNTreeImpl::compareKeyKid);
875 857 if (idx == -1) {
876   - QTC::TC("qpdf", "NNTree -1 in binary search");
877 858 error(node, "unexpected -1 from binary search of kids; limits may by wrong");
878 859 }
879 860 result.addPathElement(node, idx);
880   - node = kids.getArrayItem(idx);
  861 + node = kids[idx];
881 862 } else {
882   - QTC::TC("qpdf", "NNTree bad node during find");
883 863 error(node, "bad node during find");
884 864 }
885 865 }
886   -
887   - return result;
888 866 }
889 867  
890 868 NNTreeImpl::iterator
... ...
libqpdf/qpdf/NNTree.hh
... ... @@ -110,12 +110,12 @@ class NNTreeImpl
110 110  
111 111 private:
112 112 void repair();
113   - iterator findInternal(QPDFObjectHandle key, bool return_prev_if_not_found = false);
  113 + iterator findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_found = false);
114 114 int withinLimits(QPDFObjectHandle key, QPDFObjectHandle node);
115 115 int binarySearch(
116 116 QPDFObjectHandle key,
117 117 QPDFObjectHandle items,
118   - int num_items,
  118 + size_t num_items,
119 119 bool return_prev_if_not_found,
120 120 int (NNTreeImpl::*compare)(QPDFObjectHandle& key, QPDFObjectHandle& arr, int item));
121 121 int compareKeyItem(QPDFObjectHandle& key, QPDFObjectHandle& items, int idx);
... ...
qpdf/qpdf.testcov
... ... @@ -543,9 +543,6 @@ NNTree split second half kid 0
543 543 NNTree missing limits 0
544 544 NNTree item is wrong type 0
545 545 NNTree kid is invalid 0
546   -NNTree loop in find 0
547   -NNTree -1 in binary search 0
548   -NNTree bad node during find 0
549 546 NNTree node is not a dictionary 0
550 547 NNTree limits didn't change 0
551 548 NNTree increment end() 0
... ...