summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Le Ray <sebastien-libreoffice@orniz.org>2011-02-10 16:54:04 +0100
committerCédric Bosdonnat <cedricbosdo@openoffice.org>2011-02-10 16:54:04 +0100
commit5cb80049f5a9472260947056a25d89fef31d86b1 (patch)
treeef7881b28c5f9680d392f2e589b398dc92630856
parentb1ca63cb764cfea0eb7e6e924b6ec0023e9d1cd1 (diff)
Add compareToNumeric to OUString & Co
-rw-r--r--sal/inc/rtl/string.h23
-rw-r--r--sal/inc/rtl/string.hxx22
-rw-r--r--sal/inc/rtl/ustring.h23
-rw-r--r--sal/inc/rtl/ustring.hxx22
-rw-r--r--sal/qa/rtl/strings/test_oustring_compare.cxx58
-rw-r--r--sal/rtl/source/strtmpl.c47
-rwxr-xr-xsal/util/sal.map2
7 files changed, 197 insertions, 0 deletions
diff --git a/sal/inc/rtl/string.h b/sal/inc/rtl/string.h
index 2a7a2d943..0051fc30e 100644
--- a/sal/inc/rtl/string.h
+++ b/sal/inc/rtl/string.h
@@ -73,6 +73,29 @@ sal_Int32 SAL_CALL rtl_str_getLength( const sal_Char * str ) SAL_THROW_EXTERN_C(
*/
sal_Int32 SAL_CALL rtl_str_compare( const sal_Char * first, const sal_Char * second ) SAL_THROW_EXTERN_C();
+/** Compare two strings using natural order.
+
+ For non digit characters, the comparison use the same algorithm as
+ rtl_str_compare. When a number is encountered during the comparison,
+ natural order is used. Thus, Heading 10 will be considered as greater
+ than Heading 2. Numerical comparison is done using decimal representation.
+
+ Beware that "MyString 001" and "MyString 1" will be considered as equal
+ since leading 0 are meaningless.
+
+ @param first
+ the first null-terminated string to be compared.
+
+ @param second
+ the second null-terminated string which is compared with the first one.
+
+ @return
+ 0 if both strings are equal, a value less than 0 if the first string is
+ less than the second string, and a value greater than 0 if the first
+ string is greater than the second string.
+ */
+sal_Int32 SAL_CALL rtl_str_compare_Numeric( const sal_Char * first, const sal_Char * second ) SAL_THROW_EXTERN_C();
+
/** Compare two strings.
The comparison is based on the numeric value of each character in the
diff --git a/sal/inc/rtl/string.hxx b/sal/inc/rtl/string.hxx
index 186b515ca..bd0fa030d 100644
--- a/sal/inc/rtl/string.hxx
+++ b/sal/inc/rtl/string.hxx
@@ -283,6 +283,28 @@ public:
}
/**
+ Compares two strings using natural order.
+
+ For non digit characters, the comparison use the same algorithm as
+ rtl_str_compare. When a number is encountered during the comparison,
+ natural order is used. Thus, Heading 10 will be considered as greater
+ than Heading 2. Numerical comparison is done using decimal representation.
+
+ Beware that "MyString 001" and "MyString 1" will be considered as equal
+ since leading 0 are meaningless.
+
+ @param str the object to be compared.
+ @return 0 - if both strings are equal
+ < 0 - if this string is less than the string argument
+ > 0 - if this string is greater than the string argument
+ */
+ sal_Int32 compareToNumeric( const OString & str ) const SAL_THROW(())
+ {
+ return rtl_str_compare_Numeric( pData->buffer,
+ str.pData->buffer );
+ }
+
+ /**
Compares two strings with an maximum count of characters.
The comparison is based on the numeric value of each character in
diff --git a/sal/inc/rtl/ustring.h b/sal/inc/rtl/ustring.h
index 723117c03..0ed0bbf6b 100644
--- a/sal/inc/rtl/ustring.h
+++ b/sal/inc/rtl/ustring.h
@@ -74,6 +74,29 @@ sal_Int32 SAL_CALL rtl_ustr_getLength( const sal_Unicode * str ) SAL_THROW_EXTER
*/
sal_Int32 SAL_CALL rtl_ustr_compare( const sal_Unicode * first, const sal_Unicode * second ) SAL_THROW_EXTERN_C();
+/** Compare two strings using natural order.
+
+ For non digit characters, the comparison use the same algorithm as
+ rtl_str_compare. When a number is encountered during the comparison,
+ natural order is used. Thus, Heading 10 will be considered as greater
+ than Heading 2. Numerical comparison is done using decimal representation.
+
+ Beware that "MyString 001" and "MyString 1" will be considered as equal
+ since leading 0 are meaningless.
+
+ @param first
+ the first null-terminated string to be compared.
+
+ @param second
+ the second null-terminated string which is compared with the first one.
+
+ @return
+ 0 if both strings are equal, a value less than 0 if the first string is
+ less than the second string, and a value greater than 0 if the first
+ string is greater than the second string.
+ */
+sal_Int32 SAL_CALL rtl_ustr_compare_Numeric( const sal_Unicode * first, const sal_Unicode * second ) SAL_THROW_EXTERN_C();
+
/** Compare two strings.
The comparison is based on the numeric value of each character in the
diff --git a/sal/inc/rtl/ustring.hxx b/sal/inc/rtl/ustring.hxx
index f948a0c87..c44603ea2 100644
--- a/sal/inc/rtl/ustring.hxx
+++ b/sal/inc/rtl/ustring.hxx
@@ -330,6 +330,28 @@ public:
}
/**
+ Compares two strings using natural order.
+
+ For non digit characters, the comparison use the same algorithm as
+ rtl_str_compare. When a number is encountered during the comparison,
+ natural order is used. Thus, Heading 10 will be considered as greater
+ than Heading 2. Numerical comparison is done using decimal representation.
+
+ Beware that "MyString 001" and "MyString 1" will be considered as equal
+ since leading 0 are meaningless.
+
+ @param str the object to be compared.
+ @return 0 - if both strings are equal
+ < 0 - if this string is less than the string argument
+ > 0 - if this string is greater than the string argument
+ */
+ sal_Int32 compareToNumeric( const OUString & str ) const SAL_THROW(())
+ {
+ return rtl_ustr_compare_Numeric( pData->buffer,
+ str.pData->buffer );
+ }
+
+ /**
Compares two strings with an maximum count of characters.
The comparison is based on the numeric value of each character in
diff --git a/sal/qa/rtl/strings/test_oustring_compare.cxx b/sal/qa/rtl/strings/test_oustring_compare.cxx
index 1d4246d5e..daa3958b4 100644
--- a/sal/qa/rtl/strings/test_oustring_compare.cxx
+++ b/sal/qa/rtl/strings/test_oustring_compare.cxx
@@ -40,9 +40,11 @@ class Compare: public CppUnit::TestFixture
{
private:
void equalsIgnoreAsciiCaseAscii();
+ void compareNumeric();
CPPUNIT_TEST_SUITE(Compare);
CPPUNIT_TEST(equalsIgnoreAsciiCaseAscii);
+CPPUNIT_TEST(compareNumeric);
CPPUNIT_TEST_SUITE_END();
};
@@ -68,4 +70,60 @@ void test::oustring::Compare::equalsIgnoreAsciiCaseAscii()
equalsIgnoreAsciiCaseAscii("abcd"));
}
+void test::oustring::Compare::compareNumeric()
+{
+// --- Some generic tests to ensure we do not alter original behavior
+// outside what we want
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("ABC"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("ABC")))) == 0
+ );
+ // Case sensitivity
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("ABC"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("abc")))) < 0
+ );
+ // Reverse
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("abc"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("ABC")))) > 0
+ );
+ // First shorter
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("alongstring"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("alongerstring")))) > 0
+ );
+ // Second shorter
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("alongerstring"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("alongstring")))) < 0
+ );
+// -- Here we go on natural order, each one is followed by classic compare and the reverse comparison
+ // That's why we originally made the patch
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("Heading 9"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("Heading 10")))) < 0
+ );
+ // Original behavior
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("Heading 9"))).compareTo(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("Heading 10")))) > 0
+ );
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("Heading 10"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("Heading 9")))) > 0
+ );
+ // Harder
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("July, the 4th"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("July, the 10th")))) < 0
+ );
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("July, the 4th"))).compareTo(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("July, the 10th")))) > 0
+ );
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("July, the 10th"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("July, the 4th")))) > 0
+ );
+ // Hardest
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("abc08"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("abc010")))) < 0
+ );
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("abc08"))).compareTo(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("abc010")))) > 0
+ );
+ CPPUNIT_ASSERT(
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("abc010"))).compareToNumeric(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(("abc08")))) > 0
+ );
+}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/source/strtmpl.c b/sal/rtl/source/strtmpl.c
index 98c09f15a..18bc95983 100644
--- a/sal/rtl/source/strtmpl.c
+++ b/sal/rtl/source/strtmpl.c
@@ -60,6 +60,8 @@ inline void rtl_str_ImplCopy( IMPL_RTL_STRCODE* pDest,
} \
}
+#define IS_DIGIT(CHAR) (((CHAR) >= 48) && ((CHAR <= 57)))
+
/* ======================================================================= */
/* C-String functions which could be used without the String-Class */
/* ======================================================================= */
@@ -91,6 +93,51 @@ sal_Int32 SAL_CALL IMPL_RTL_STRNAME( compare )( const IMPL_RTL_STRCODE* pStr1,
/* ----------------------------------------------------------------------- */
+sal_Int32 SAL_CALL IMPL_RTL_STRNAME( compare_Numeric )( const IMPL_RTL_STRCODE* pStr1,
+ const IMPL_RTL_STRCODE* pStr2 )
+{
+ sal_Int32 nRet;
+ do {
+ while ( ((nRet = ((sal_Int32)(IMPL_RTL_USTRCODE(*pStr1)))-
+ ((sal_Int32)(IMPL_RTL_USTRCODE(*pStr2)))) == 0) &&
+ *pStr2 )
+ {
+ pStr1++;
+ pStr2++;
+ }
+
+ if(*pStr1 && *pStr2)
+ {
+ IMPL_RTL_STRCODE c1 = (sal_Int32)IMPL_RTL_USTRCODE( *pStr1 );
+ IMPL_RTL_STRCODE c2 = (sal_Int32)IMPL_RTL_USTRCODE( *pStr2 );
+ sal_Int64 number1 = 0;
+ sal_Int64 number2 = 0;
+ if(IS_DIGIT(c1) && IS_DIGIT(c2))
+ {
+ do
+ {
+ number1 = number1 * 10 + (c1 - '0');
+ pStr1++;
+ c1 = (sal_Int32)IMPL_RTL_USTRCODE( *pStr1 );
+ } while(IS_DIGIT(c1));
+
+ do
+ {
+ number2 = number2 * 10 + (c2 - '0');
+ pStr2++;
+ c2 = (sal_Int32)IMPL_RTL_USTRCODE( *pStr2 );
+ } while(IS_DIGIT(c2));
+
+ nRet = number1 - number2;
+ }
+ }
+ } while(nRet == 0 && *pStr1 && *pStr2);
+
+ return nRet;
+}
+
+/* ----------------------------------------------------------------------- */
+
sal_Int32 SAL_CALL IMPL_RTL_STRNAME( compare_WithLength )( const IMPL_RTL_STRCODE* pStr1,
sal_Int32 nStr1Len,
const IMPL_RTL_STRCODE* pStr2,
diff --git a/sal/util/sal.map b/sal/util/sal.map
index 8b1c079ec..a7e3eb6be 100755
--- a/sal/util/sal.map
+++ b/sal/util/sal.map
@@ -194,6 +194,7 @@ UDK_3_0_0 {
rtl_locale_setDefault;
rtl_str_getLength;
rtl_str_compare;
+ rtl_str_compare_Numeric;
rtl_str_compare_WithLength;
rtl_str_shortenedCompare_WithLength;
rtl_str_reverseCompare_WithLength;
@@ -251,6 +252,7 @@ UDK_3_0_0 {
rtl_stringbuffer_newFromStr_WithLength;
rtl_stringbuffer_newFromStringBuffer;
rtl_ustr_compare;
+ rtl_ustr_compare_Numeric;
rtl_ustr_compare_WithLength;
rtl_ustr_shortenedCompare_WithLength;
rtl_ustr_reverseCompare_WithLength;