Rework BCollator API
- Strength is now set once, instead of at each comparison, to improve performance and fix potential locking issues - Add a way to enable "numeric" collation (aka "natural order")
This commit is contained in:
@@ -35,9 +35,9 @@
|
||||
natural number sorting so that 2 is sorted before 10 unlike byte-based
|
||||
sorting.
|
||||
|
||||
\warning This class is not multithread-safe, as Compare() change the
|
||||
ICUCollator (the strength). So if you want to use a BCollator
|
||||
from more than one thread you need to protect it with a lock.
|
||||
\warning This class is not multithread-safe. So if you want to use a
|
||||
BCollator from more than one thread you need to protect it with
|
||||
a lock.
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
@@ -121,12 +121,9 @@
|
||||
|
||||
|
||||
/*!
|
||||
\fn void BCollator::SetDefaultStrength(int8 strength)
|
||||
\fn void BCollator::SetStrength(int8 strength)
|
||||
\brief Set the \a strength of the collator.
|
||||
|
||||
Note that the \a strength can also be chosen on a case-by-case basis
|
||||
when calling other methods.
|
||||
|
||||
\param strength The collator class provide four level of \a strength.
|
||||
\li \c B_COLLATE_PRIMARY doesn't differentiate e from é,
|
||||
\li \c B_COLLATE_SECONDARY takes letter accents into account,
|
||||
@@ -138,16 +135,6 @@
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\fn int8 BCollator::DefaultStrength() const
|
||||
\brief Get the current strength of this catalog.
|
||||
|
||||
\returns The current strength of the catalog.
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\fn void BCollator::SetIgnorePunctuation(bool ignore)
|
||||
\brief Enable or disable punctuation handling.
|
||||
@@ -172,8 +159,21 @@
|
||||
|
||||
|
||||
/*!
|
||||
\fn status_t BCollator::GetSortKey(const char* string, BString* key,
|
||||
int8 strength) const
|
||||
\fn void BCollator::SetNumericSorting(bool ignore)
|
||||
\brief Enable or disable numeric order sorting.
|
||||
|
||||
Numeric sorting enables the collator to identify strings of digits as
|
||||
numbers, and sort them in ascending number. For example, the string "123"
|
||||
is sorted after "234". Numbers and other characters can be mixed in the
|
||||
same string.
|
||||
|
||||
\since Haiku R1
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\fn status_t BCollator::GetSortKey(const char* string, BString* key)
|
||||
const
|
||||
\brief Compute the sortkey of a \a string.
|
||||
|
||||
The sortkey is a modified version of the input \a string that you can use
|
||||
@@ -184,7 +184,6 @@
|
||||
|
||||
\param string String from which to compute the sortkey.
|
||||
\param key The resulting sortkey.
|
||||
\param strength The \a strength to use to compute the sortkey.
|
||||
|
||||
\retval B_OK if everything went well.
|
||||
\retval B_ERROR if an error occurred generating the sortkey.
|
||||
@@ -194,17 +193,15 @@
|
||||
|
||||
|
||||
/*!
|
||||
\fn int BCollator::Compare(const char* s1, const char* s2,
|
||||
int8 strength) const
|
||||
\brief Returns the difference betweens the two strings according to the
|
||||
collation defined by the \a strength parameter.
|
||||
\fn int BCollator::Compare(const char* s1, const char* s2)
|
||||
const
|
||||
\brief Returns the difference betweens the two strings.
|
||||
|
||||
This method should be used in place of the strcmp() function to perform
|
||||
locale-aware comparisons.
|
||||
|
||||
\param s1 The first string to compare.
|
||||
\param s2 The second string to compare.
|
||||
\param strength The \a strength to use for the string comparison.
|
||||
|
||||
\returns An integer value representing how the strings compare to each
|
||||
other.
|
||||
@@ -219,8 +216,8 @@
|
||||
|
||||
|
||||
/*!
|
||||
\fn bool BCollator::Equal(const char* s1, const char* s2,
|
||||
int8 strength) const
|
||||
\fn bool BCollator::Equal(const char* s1, const char* s2)
|
||||
const
|
||||
\brief Compares two strings for equality.
|
||||
|
||||
Note that strings that are not byte-by-byte identical may end up being
|
||||
@@ -232,7 +229,6 @@
|
||||
|
||||
\param s1 The first string to compare.
|
||||
\param s2 The second string to compare.
|
||||
\param strength The \a strength to use for the string comparison.
|
||||
|
||||
\returns \c true if the strings are identical, \c false otherwise.
|
||||
|
||||
@@ -241,8 +237,8 @@
|
||||
|
||||
|
||||
/*!
|
||||
\fn bool BCollator::Greater(const char* s1, const char* s2,
|
||||
int8 strength = B_COLLATE_DEFAULT) const
|
||||
\fn bool BCollator::Greater(const char* s1, const char* s2)
|
||||
const
|
||||
\brief Determine if a string is greater than another.
|
||||
|
||||
\note !Greater(s1, s2) is the same as GreaterOrEqual(s2, s1). This means
|
||||
@@ -250,7 +246,6 @@
|
||||
|
||||
\param s1 The first string to compare.
|
||||
\param s2 The second string to compare.
|
||||
\param strength The \a strength to use for the string comparison.
|
||||
|
||||
\returns \c true if s1 is greater than, but not equal to, s2.
|
||||
|
||||
@@ -259,15 +254,14 @@
|
||||
|
||||
|
||||
/*!
|
||||
\fn bool BCollator::GreaterOrEqual(const char* s1, const char* s2,
|
||||
int8 strength = B_COLLATE_DEFAULT) const
|
||||
\fn bool BCollator::GreaterOrEqual(const char* s1, const char* s2)
|
||||
const
|
||||
\brief Determines if one string is greater than another.
|
||||
|
||||
\note !GreaterOrEqual(s1, s2) is the same as Greater(s2, s1).
|
||||
|
||||
\param s1 The first string to compare.
|
||||
\param s2 The second string to compare.
|
||||
\param strength The \a strength to use for the string comparison.
|
||||
|
||||
\returns \c true if s1 is greater or equal than s2.
|
||||
|
||||
@@ -280,9 +274,7 @@
|
||||
\brief Unarchive the collator
|
||||
|
||||
This method allows you to restore a collator that you previously
|
||||
archived. It is faster to archive and unarchive a collator than it is
|
||||
to create a new one up each time you need a BCollator object with the
|
||||
same settings.
|
||||
archived.
|
||||
|
||||
\param archive The message to restore the collator from.
|
||||
|
||||
|
||||
@@ -34,9 +34,6 @@ enum collator_strengths {
|
||||
};
|
||||
|
||||
|
||||
// N.B.: This class is not multithread-safe, as Compare() and GetKey() change
|
||||
// the ICUCollator (the strength). So if you want to use a BCollator from
|
||||
// more than one thread, you need to protect it with a lock
|
||||
class BCollator : public BArchivable {
|
||||
public:
|
||||
BCollator();
|
||||
@@ -51,55 +48,54 @@ public:
|
||||
|
||||
BCollator& operator=(const BCollator& source);
|
||||
|
||||
void SetDefaultStrength(int8 strength);
|
||||
int8 DefaultStrength() const;
|
||||
status_t SetStrength(int8 strength) const;
|
||||
|
||||
void SetIgnorePunctuation(bool ignore);
|
||||
bool IgnorePunctuation() const;
|
||||
|
||||
status_t GetSortKey(const char* string, BString* key,
|
||||
int8 strength = B_COLLATE_DEFAULT) const;
|
||||
status_t SetNumericSorting(bool enable);
|
||||
|
||||
int Compare(const char* s1, const char* s2,
|
||||
int8 strength = B_COLLATE_DEFAULT) const;
|
||||
bool Equal(const char* s1, const char* s2,
|
||||
int8 strength = B_COLLATE_DEFAULT) const;
|
||||
bool Greater(const char* s1, const char* s2,
|
||||
int8 strength = B_COLLATE_DEFAULT) const;
|
||||
bool GreaterOrEqual(const char* s1, const char* s2,
|
||||
int8 strength = B_COLLATE_DEFAULT) const;
|
||||
status_t GetSortKey(const char* string, BString* key)
|
||||
const;
|
||||
|
||||
int Compare(const char* s1, const char* s2)
|
||||
const;
|
||||
bool Equal(const char* s1, const char* s2)
|
||||
const;
|
||||
bool Greater(const char* s1, const char* s2)
|
||||
const;
|
||||
bool GreaterOrEqual(const char* s1, const char* s2)
|
||||
const;
|
||||
|
||||
// (un-)archiving API
|
||||
status_t Archive(BMessage* archive, bool deep) const;
|
||||
static BArchivable* Instantiate(BMessage* archive);
|
||||
|
||||
private:
|
||||
status_t _SetStrength(int8 strength) const;
|
||||
|
||||
mutable U_ICU_NAMESPACE::Collator* fICUCollator;
|
||||
int8 fDefaultStrength;
|
||||
bool fIgnorePunctuation;
|
||||
};
|
||||
|
||||
|
||||
inline bool
|
||||
BCollator::Equal(const char *s1, const char *s2, int8 strength) const
|
||||
BCollator::Equal(const char *s1, const char *s2) const
|
||||
{
|
||||
return Compare(s1, s2, strength) == 0;
|
||||
return Compare(s1, s2) == 0;
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
BCollator::Greater(const char *s1, const char *s2, int8 strength) const
|
||||
BCollator::Greater(const char *s1, const char *s2) const
|
||||
{
|
||||
return Compare(s1, s2, strength) > 0;
|
||||
return Compare(s1, s2) > 0;
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
BCollator::GreaterOrEqual(const char *s1, const char *s2, int8 strength) const
|
||||
BCollator::GreaterOrEqual(const char *s1, const char *s2) const
|
||||
{
|
||||
return Compare(s1, s2, strength) >= 0;
|
||||
return Compare(s1, s2) >= 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
BCollator::BCollator()
|
||||
:
|
||||
fDefaultStrength(B_COLLATE_PRIMARY),
|
||||
fIgnorePunctuation(true)
|
||||
{
|
||||
// TODO: the collator construction will have to change; the default
|
||||
@@ -33,16 +32,17 @@ BCollator::BCollator()
|
||||
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
fICUCollator = Collator::createInstance(error);
|
||||
SetStrength(B_COLLATE_TERTIARY);
|
||||
}
|
||||
|
||||
|
||||
BCollator::BCollator(const char* locale, int8 strength, bool ignorePunctuation)
|
||||
:
|
||||
fDefaultStrength(strength),
|
||||
fIgnorePunctuation(ignorePunctuation)
|
||||
{
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
fICUCollator = Collator::createInstance(locale, error);
|
||||
SetStrength(strength);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,15 +50,8 @@ BCollator::BCollator(BMessage* archive)
|
||||
:
|
||||
BArchivable(archive),
|
||||
fICUCollator(NULL),
|
||||
fDefaultStrength(B_COLLATE_PRIMARY),
|
||||
fIgnorePunctuation(true)
|
||||
{
|
||||
int32 data;
|
||||
if (archive->FindInt32("loc:strength", &data) == B_OK)
|
||||
fDefaultStrength = (uint8)data;
|
||||
else
|
||||
fDefaultStrength = B_COLLATE_PRIMARY;
|
||||
|
||||
archive->FindBool("loc:punctuation", &fIgnorePunctuation);
|
||||
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
@@ -101,7 +94,6 @@ BCollator& BCollator::operator=(const BCollator& source)
|
||||
fICUCollator = source.fICUCollator != NULL
|
||||
? source.fICUCollator->clone()
|
||||
: NULL;
|
||||
fDefaultStrength = source.fDefaultStrength;
|
||||
fIgnorePunctuation = source.fIgnorePunctuation;
|
||||
}
|
||||
|
||||
@@ -109,20 +101,6 @@ BCollator& BCollator::operator=(const BCollator& source)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BCollator::SetDefaultStrength(int8 strength)
|
||||
{
|
||||
fDefaultStrength = strength;
|
||||
}
|
||||
|
||||
|
||||
int8
|
||||
BCollator::DefaultStrength() const
|
||||
{
|
||||
return fDefaultStrength;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BCollator::SetIgnorePunctuation(bool ignore)
|
||||
{
|
||||
@@ -138,10 +116,19 @@ BCollator::IgnorePunctuation() const
|
||||
|
||||
|
||||
status_t
|
||||
BCollator::GetSortKey(const char* string, BString* key, int8 strength) const
|
||||
BCollator::SetNumericSorting(bool enable)
|
||||
{
|
||||
_SetStrength(strength);
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
fICUCollator->setAttribute(UCOL_NUMERIC_COLLATION,
|
||||
enable ? UCOL_ON : UCOL_OFF, error);
|
||||
|
||||
return error == U_ZERO_ERROR ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BCollator::GetSortKey(const char* string, BString* key) const
|
||||
{
|
||||
// TODO : handle fIgnorePunctuation
|
||||
|
||||
int length = strlen(string);
|
||||
@@ -175,10 +162,8 @@ BCollator::GetSortKey(const char* string, BString* key, int8 strength) const
|
||||
|
||||
|
||||
int
|
||||
BCollator::Compare(const char* s1, const char* s2, int8 strength) const
|
||||
BCollator::Compare(const char* s1, const char* s2) const
|
||||
{
|
||||
_SetStrength(strength);
|
||||
|
||||
// TODO : handle fIgnorePunctuation
|
||||
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
@@ -193,8 +178,6 @@ BCollator::Archive(BMessage* archive, bool deep) const
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (status == B_OK)
|
||||
status = archive->AddInt32("loc:strength", fDefaultStrength);
|
||||
if (status == B_OK)
|
||||
status = archive->AddBool("loc:punctuation", fIgnorePunctuation);
|
||||
|
||||
@@ -229,10 +212,10 @@ BCollator::Instantiate(BMessage* archive)
|
||||
|
||||
|
||||
status_t
|
||||
BCollator::_SetStrength(int8 strength) const
|
||||
BCollator::SetStrength(int8 strength) const
|
||||
{
|
||||
if (strength == B_COLLATE_DEFAULT)
|
||||
strength = fDefaultStrength;
|
||||
strength = B_COLLATE_TERTIARY;
|
||||
|
||||
Collator::ECollationStrength icuStrength;
|
||||
switch (strength) {
|
||||
|
||||
@@ -50,11 +50,11 @@ CollatorTest::TestSortKeys()
|
||||
|
||||
for (int32 strength = B_COLLATE_PRIMARY; strength < 4; strength++) {
|
||||
BString a, b;
|
||||
collator.GetSortKey(tests[i].first, &a, strength);
|
||||
collator.GetSortKey(tests[i].second, &b, strength);
|
||||
collator.SetStrength(strength);
|
||||
collator.GetSortKey(tests[i].first, &a);
|
||||
collator.GetSortKey(tests[i].second, &b);
|
||||
|
||||
int difference = collator.Compare(tests[i].first, tests[i].second,
|
||||
strength);
|
||||
int difference = collator.Compare(tests[i].first, tests[i].second);
|
||||
CPPUNIT_ASSERT_EQUAL(tests[i].sign[strength - 1], difference);
|
||||
int keydiff = strcmp(a.String(), b.String());
|
||||
// Check that the keys compare the same as the strings. Either both
|
||||
|
||||
Reference in New Issue
Block a user