Fix search in wxSortedArrayString with custom compare function

This commit is contained in:
Pavel Tyunin
2021-02-25 21:23:33 +02:00
parent 752ba82041
commit 2451f8085b
3 changed files with 35 additions and 43 deletions

View File

@@ -398,6 +398,9 @@ private:
// (if the old buffer is big enough, just return NULL). // (if the old buffer is big enough, just return NULL).
wxString *Grow(size_t nIncrement); 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 size_t m_nSize, // current size of the array
m_nCount; // current number of elements m_nCount; // current number of elements

View File

@@ -377,14 +377,9 @@ void wxArrayString::Shrink()
} }
} }
// searches the array for an item (forward or backwards) // Binary search in the sorted array
int wxArrayString::Index(const wxString& str, bool bCase, bool bFromEnd) const size_t wxArrayString::BinarySearch(const wxString& str, bool equal) const
{ {
if ( m_autoSort ) {
// use binary search in the sorted array
wxASSERT_MSG( bCase && !bFromEnd,
wxT("search parameters ignored for auto sorted array") );
size_t size_t
lo = 0, lo = 0,
hi = m_nCount; hi = m_nCount;
@@ -393,7 +388,7 @@ int wxArrayString::Index(const wxString& str, bool bCase, bool bFromEnd) const
i = (lo + hi) / 2; i = (lo + hi) / 2;
int res; int res;
res = str.compare(m_pItems[i]); res = m_compareFunction ? m_compareFunction(str, m_pItems[i]) : str.Cmp(m_pItems[i]);
if (res < 0) if (res < 0)
hi = i; hi = i;
else if (res > 0) else if (res > 0)
@@ -401,8 +396,18 @@ int wxArrayString::Index(const wxString& str, bool bCase, bool bFromEnd) const
else else
return i; return i;
} }
wxASSERT_MSG(lo == hi, wxT("binary search broken"));
return equal ? wxNOT_FOUND : lo;
}
return wxNOT_FOUND; // searches the array for an item (forward or backwards)
int wxArrayString::Index(const wxString& str, bool bCase, bool bFromEnd) const
{
if ( m_autoSort ) {
// use binary search in the sorted array
wxASSERT_MSG( bCase && !bFromEnd,
wxT("search parameters ignored for auto sorted array") );
return BinarySearch(str, true);
} }
else { else {
// use linear search in unsorted array // use linear search in unsorted array
@@ -432,30 +437,9 @@ size_t wxArrayString::Add(const wxString& str, size_t nInsert)
{ {
if ( m_autoSort ) { if ( m_autoSort ) {
// insert the string at the correct position to keep the array sorted // insert the string at the correct position to keep the array sorted
size_t size_t nIndex = BinarySearch(str);
lo = 0, Insert(str, nIndex, nInsert);
hi = m_nCount; return nIndex;
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;
} }
else { else {
// Now that we must postpone freeing the old memory until we don't need it // Now that we must postpone freeing the old memory until we don't need it

View File

@@ -399,6 +399,11 @@ void ArraysTestCase::SortedArray()
ad.Add("Aa"); ad.Add("Aa");
CPPUNIT_ASSERT_EQUAL( "a", ad[0] ); CPPUNIT_ASSERT_EQUAL( "a", ad[0] );
CPPUNIT_ASSERT_EQUAL( "Aa", ad[1] ); 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() void ArraysTestCase::wxStringArraySplitTest()