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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -41,6 +41,8 @@ UnitTestLib libsupporttest.so
|
||||
StringSubCopyTest.cpp
|
||||
StringUTF8Test.cpp
|
||||
|
||||
StringListTest.cpp
|
||||
|
||||
: be [ TargetLibstdc++ ] libsupporttest_RemoteTestObject.so
|
||||
;
|
||||
|
||||
|
||||
@@ -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());
|
||||
Reference in New Issue
Block a user