From 2451f8085be6ced9ac8e5b2595e0b43bf50599d9 Mon Sep 17 00:00:00 2001 From: Pavel Tyunin Date: Thu, 25 Feb 2021 21:23:33 +0200 Subject: [PATCH] Fix search in wxSortedArrayString with custom compare function --- include/wx/arrstr.h | 3 ++ src/common/arrstr.cpp | 70 ++++++++++++++++------------------------- tests/arrays/arrays.cpp | 5 +++ 3 files changed, 35 insertions(+), 43 deletions(-) diff --git a/include/wx/arrstr.h b/include/wx/arrstr.h index e21dc78761..bed1098d74 100644 --- a/include/wx/arrstr.h +++ b/include/wx/arrstr.h @@ -398,6 +398,9 @@ private: // (if the old buffer is big enough, just return NULL). wxString *Grow(size_t nIncrement); + // Binary search in the sorted array + size_t BinarySearch(const wxString& str, bool equal = false) const; + size_t m_nSize, // current size of the array m_nCount; // current number of elements diff --git a/src/common/arrstr.cpp b/src/common/arrstr.cpp index dc569a80bf..3aac42f67d 100644 --- a/src/common/arrstr.cpp +++ b/src/common/arrstr.cpp @@ -377,6 +377,29 @@ void wxArrayString::Shrink() } } +// Binary search in the sorted array +size_t wxArrayString::BinarySearch(const wxString& str, bool equal) const +{ + size_t + lo = 0, + hi = m_nCount; + while (lo < hi) { + size_t i; + i = (lo + hi) / 2; + + int res; + res = m_compareFunction ? m_compareFunction(str, m_pItems[i]) : str.Cmp(m_pItems[i]); + if (res < 0) + hi = i; + else if (res > 0) + lo = i + 1; + else + return i; + } + wxASSERT_MSG(lo == hi, wxT("binary search broken")); + return equal ? wxNOT_FOUND : lo; +} + // searches the array for an item (forward or backwards) int wxArrayString::Index(const wxString& str, bool bCase, bool bFromEnd) const { @@ -384,25 +407,7 @@ int wxArrayString::Index(const wxString& str, bool bCase, bool bFromEnd) const // use binary search in the sorted array wxASSERT_MSG( bCase && !bFromEnd, wxT("search parameters ignored for auto sorted array") ); - - size_t - lo = 0, - hi = m_nCount; - while ( lo < hi ) { - size_t i; - i = (lo + hi)/2; - - int res; - res = str.compare(m_pItems[i]); - if ( res < 0 ) - hi = i; - else if ( res > 0 ) - lo = i + 1; - else - return i; - } - - return wxNOT_FOUND; + return BinarySearch(str, true); } else { // use linear search in unsorted array @@ -432,30 +437,9 @@ size_t wxArrayString::Add(const wxString& str, size_t nInsert) { if ( m_autoSort ) { // insert the string at the correct position to keep the array sorted - size_t - lo = 0, - hi = m_nCount; - while ( lo < hi ) { - size_t i; - i = (lo + hi)/2; - - int res; - res = m_compareFunction ? m_compareFunction(str, m_pItems[i]) : str.Cmp(m_pItems[i]); - if ( res < 0 ) - hi = i; - else if ( res > 0 ) - lo = i + 1; - else { - lo = hi = i; - break; - } - } - - wxASSERT_MSG( lo == hi, wxT("binary search broken") ); - - Insert(str, lo, nInsert); - - return (size_t)lo; + size_t nIndex = BinarySearch(str); + Insert(str, nIndex, nInsert); + return nIndex; } else { // Now that we must postpone freeing the old memory until we don't need it diff --git a/tests/arrays/arrays.cpp b/tests/arrays/arrays.cpp index 3f61c4ff41..6c815eb52f 100644 --- a/tests/arrays/arrays.cpp +++ b/tests/arrays/arrays.cpp @@ -399,6 +399,11 @@ void ArraysTestCase::SortedArray() ad.Add("Aa"); CPPUNIT_ASSERT_EQUAL( "a", ad[0] ); CPPUNIT_ASSERT_EQUAL( "Aa", ad[1] ); + CPPUNIT_ASSERT_EQUAL( 0, ad.Index("a") ); + CPPUNIT_ASSERT_EQUAL( 1, ad.Index("Aa") ); + CPPUNIT_ASSERT_EQUAL( 2, ad.Index("AB") ); + CPPUNIT_ASSERT_EQUAL( wxNOT_FOUND, ad.Index("A") ); + CPPUNIT_ASSERT_EQUAL( wxNOT_FOUND, ad.Index("z") ); } void ArraysTestCase::wxStringArraySplitTest()