BStringList: add Sort() with custom functions

fix #9268 and a TODO

Change-Id: I3148b32221f34f5fb270d8892a6fc80f69ba2e29
Reviewed-on: https://review.haiku-os.org/c/haiku/+/11104
Reviewed-by: waddlesplash <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Jérôme Duval
2026-06-15 14:49:00 +00:00
parent 22a2180aa5
commit 528bb58299
4 changed files with 158 additions and 1 deletions
+4 -1
View File
@@ -36,7 +36,10 @@ public:
// Reorder items
void Sort(bool ignoreCase = false);
// TODO: Sort() with custom sort function.
void Sort(int (*compareFunc)(const char*,
const char*, void* context), void* context);
void Sort(int (*compareFunc)(const BString&,
const BString&, void* context), void* context);
bool Swap(int32 indexA, int32 indexB);
bool Move(int32 fromIndex, int32 toIndex);
+42
View File
@@ -212,6 +212,48 @@ BStringList::Sort(bool ignoreCase)
}
void
BStringList::Sort(int (*compareFunc)(const BString&, const BString&, void* context),
void* context)
{
struct _sortContext {
static int localSort(const void* pa, const void* pb, void* customSort) {
struct _sortContext* context = (struct _sortContext*)customSort;
return context->compareFunc(BString::Private::StringFromData(*(char **)pa),
BString::Private::StringFromData(*(char **)pb), context->context);
}
int (*compareFunc)(const BString&, const BString&, void* context);
void* context;
} sortContext;
sortContext.compareFunc = compareFunc;
sortContext.context = context;
const char** list = (const char**)fStrings.Items();
qsort_r(list, fStrings.CountItems(), sizeof(*list), _sortContext::localSort, &sortContext);
}
void
BStringList::Sort(int (*compareFunc)(const char*, const char*, void* context),
void* context)
{
struct _sortContext {
static int localSort(const void* pa, const void* pb, void* customSort) {
struct _sortContext* context = (struct _sortContext*)customSort;
return context->compareFunc(*(const char **)pa,
*(const char **)pb, context->context);
}
int (*compareFunc)(const char*, const char*, void* context);
void* context;
} sortContext;
sortContext.compareFunc = compareFunc;
sortContext.context = context;
const char** list = (const char**)fStrings.Items();
qsort_r(list, fStrings.CountItems(), sizeof(*list), _sortContext::localSort, &sortContext);
}
bool
BStringList::Swap(int32 indexA, int32 indexB)
{
+2
View File
@@ -41,6 +41,8 @@ UnitTestLib libsupporttest.so
StringSubCopyTest.cpp
StringUTF8Test.cpp
StringListTest.cpp
: be [ TargetLibstdc++ ] libsupporttest_RemoteTestObject.so
;
+110
View File
@@ -0,0 +1,110 @@
/*
* Copyright 2026, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <String.h>
#include <StringList.h>
#include <TestSuiteAddon.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
static int
CompareWithData(const char* a, const char* b, void* context)
{
return strcmp(a, b);
}
static int
CompareWithDataBString(const BString& a, const BString& b, void* context)
{
return a.Compare(b);
}
class StringListTest : public CppUnit::TestFixture {
public:
CPPUNIT_TEST_SUITE(StringListTest);
CPPUNIT_TEST(SortItems_IsSorted);
CPPUNIT_TEST_SUITE_END();
void SortItems_IsSorted();
private:
void Initialize(BStringList& list, int size);
bool Equals(const BStringList& list1, const BStringList& list2);
bool IsSorted(const BStringList& list);
};
void
StringListTest::Initialize(BStringList& list, int size)
{
const char* fruits[] = {"Apple", "Orange", "Banana", "Grapes", "Cherry"};
for (int32 i = 0; i < size; i++)
list.Add(BString(fruits[i % 5]));
}
bool
StringListTest::Equals(const BStringList& list1, const BStringList& list2)
{
const int32 n = list1.CountStrings();
if (n != list2.CountStrings())
return false;
for (int32 i = 0; i < n; i++) {
BString item1 = list1.StringAt(i);
BString item2 = list2.StringAt(i);
if (item1 != item2)
return false;
}
return true;
}
bool
StringListTest::IsSorted(const BStringList& list)
{
BString previtem = list.StringAt(0);
for (int32 i = 1; i < list.CountStrings(); i++) {
BString item = list.StringAt(i);
if (item.Compare(previtem) < 0)
return false;
previtem = item;
}
return true;
}
void
StringListTest::SortItems_IsSorted()
{
for (int i = 10; i <= 20; i++) {
BStringList list;
Initialize(list, i);
BStringList clone(list);
CPPUNIT_ASSERT(Equals(list, clone));
list.Sort(CompareWithData, NULL);
CPPUNIT_ASSERT(IsSorted(list));
clone.Sort(CompareWithDataBString, NULL);
CPPUNIT_ASSERT(IsSorted(clone));
CPPUNIT_ASSERT(Equals(list, clone));
}
}
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(StringListTest, getTestSuiteName());