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:
Adrien Destugues
2017-05-29 08:52:43 +02:00
parent affb4e25fe
commit a19a18f553
4 changed files with 68 additions and 97 deletions
+29 -37
View File
@@ -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.
+19 -23
View File
@@ -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;
}
+16 -33
View File
@@ -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) {
+4 -4
View File
@@ -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