Kaydet (Commit) 0c8fa58a authored tarafından Stephan Bergmann's avatar Stephan Bergmann

Support ConstCharArrayDetector also for UTF-16 arrays

The long-term benefit will be support of C++11 char16_t string literals (for
cases of string literals with non-ASCII content) once we drop any compilers that
don't support those yet.  The short-term benefit is support for an improved
OUStringLiteral1 that accepts any sal_Unicode value, not just ASCII ones (see
next commit).

Change-Id: I3f8f6697d7eb62b5176b7e812b5a5113c53b83a4
Reviewed-on: https://gerrit.libreoffice.org/28445Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarStephan Bergmann <sbergman@redhat.com>
üst c399004b
......@@ -15,6 +15,7 @@ Any change in this header will cause a rebuild of almost everything.
#define HAVE_CXX11_CONSTEXPR 0
#define HAVE_CXX14_CONSTEXPR 0
#define HAVE_CXX11_REF_QUALIFIER 0
#define HAVE_CXX11_UTF16_STRING_LITERAL 0
#define HAVE_CXX14_SIZED_DEALLOCATION 0
#define HAVE_GCC_BUILTIN_ATOMIC 0
/* _Pragma */
......
......@@ -6390,6 +6390,20 @@ if test "$cxx11_ref_qualifier" = yes; then
AC_DEFINE([HAVE_CXX11_REF_QUALIFIER])
fi
AC_MSG_CHECKING([whether $CXX supports C++11 char16_t string literals])
save_CXXFLAGS=$CXXFLAGS
CXXFLAGS="$CXXFLAGS $CXXFLAGS_CXX11"
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
auto s = u"";
]])], [cxx11_utf16_string_literal=yes], [cxx11_utf16_string_literal=no])
AC_LANG_POP([C++])
CXXFLAGS=$save_CXXFLAGS
AC_MSG_RESULT([$cxx11_utf16_string_literal])
if test "$cxx11_utf16_string_literal" = yes; then
AC_DEFINE([HAVE_CXX11_UTF16_STRING_LITERAL])
fi
AC_MSG_CHECKING([whether $CXX supports C++14 sized deallocation])
dnl At least Clang -fsanitize=address causes "multiple definition of
dnl `operator delete(void*, unsigned long)'" also defined in
......
......@@ -12,6 +12,7 @@
#include <rtl/stringutils.hxx>
#include <cstddef>
#include <string.h>
#ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING"
......@@ -141,6 +142,14 @@ struct ToStringHelper< const char[ N ] >
static const bool allowOUStringConcat = true;
};
template<std::size_t N> struct ToStringHelper<sal_Unicode const[N]> {
static int length(sal_Unicode const[N]) { return N - 1; }
static sal_Unicode * addData(sal_Unicode * buffer, sal_Unicode const str[N])
{ return addDataHelper(buffer, str, N - 1); }
static bool const allowOStringConcat = false;
static bool const allowOUStringConcat = true;
};
template<char C> struct ToStringHelper<OUStringLiteral1_<C>> {
static int length(OUStringLiteral1_<C>) { return 1; }
static char * addData(char * buffer, OUStringLiteral1_<C> literal)
......
......@@ -172,6 +172,15 @@ struct ConstCharArrayDetector< const char[ N ], T >
static char const * toPointer(char const (& literal)[N]) { return literal; }
};
#if defined LIBO_INTERNAL_ONLY
template<std::size_t N, typename T>
struct ConstCharArrayDetector<sal_Unicode const [N], T> {
using TypeUtf16 = T;
static SAL_CONSTEXPR bool const ok = true;
static SAL_CONSTEXPR std::size_t const length = N - 1;
static SAL_CONSTEXPR sal_Unicode const * toPointer(
sal_Unicode const (& literal)[N])
{ return literal; }
};
template<char C, typename T> struct ConstCharArrayDetector<
#if defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ <= 8 \
&& !defined __clang__
......@@ -201,6 +210,8 @@ struct ExceptConstCharArrayDetector< const char[ N ] >
{
};
#if defined LIBO_INTERNAL_ONLY
template<std::size_t N>
struct ExceptConstCharArrayDetector<sal_Unicode const[N]> {};
template<char C> struct ExceptConstCharArrayDetector<
#if defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ <= 8 \
&& !defined __clang__
......@@ -230,6 +241,8 @@ struct ExceptCharArrayDetector< const char[ N ] >
{
};
#if defined LIBO_INTERNAL_ONLY
template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode[N]> {};
template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode const[N]> {};
template<char C> struct ExceptCharArrayDetector<OUStringLiteral1_<C>> {};
#endif
......
......@@ -146,6 +146,24 @@ public:
#endif
}
#if defined LIBO_INTERNAL_ONLY
/** @overload @since LibreOffice 5.3 */
template<typename T>
OUStringBuffer(
T & literal,
typename libreoffice_internal::ConstCharArrayDetector<
T, libreoffice_internal::Dummy>::TypeUtf16
= libreoffice_internal::Dummy()):
pData(nullptr),
nCapacity(libreoffice_internal::ConstCharArrayDetector<T>::length + 16)
{
rtl_uStringbuffer_newFromStr_WithLength(
&pData,
libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
libreoffice_internal::ConstCharArrayDetector<T>::length);
}
#endif
#ifdef RTL_STRING_UNITTEST
/**
* Only used by unittests to detect incorrect conversions.
......@@ -484,6 +502,20 @@ public:
return *this;
}
#if defined LIBO_INTERNAL_ONLY
/** @overload @since LibreOffice 5.3 */
template<typename T>
typename libreoffice_internal::ConstCharArrayDetector<
T, OUStringBuffer &>::TypeUtf16
append(T & literal) {
rtl_uStringbuffer_insert(
&pData, &nCapacity, getLength(),
libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
libreoffice_internal::ConstCharArrayDetector<T>::length);
return *this;
}
#endif
#ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING"
/**
@overload
......@@ -836,6 +868,20 @@ public:
return *this;
}
#if defined LIBO_INTERNAL_ONLY
/** @overload @since LibreOffice 5.3 */
template<typename T>
typename libreoffice_internal::ConstCharArrayDetector<
T, OUStringBuffer &>::TypeUtf16
insert(sal_Int32 offset, T & literal) {
rtl_uStringbuffer_insert(
&pData, &nCapacity, offset,
libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
libreoffice_internal::ConstCharArrayDetector<T>::length);
return *this;
}
#endif
/**
Inserts the string representation of the <code>sal_Bool</code>
argument into this string buffer.
......@@ -1225,6 +1271,21 @@ public:
return n < 0 ? n : n + fromIndex;
}
#if defined LIBO_INTERNAL_ONLY
/** @overload @since LibreOffice 5.3 */
template<typename T>
typename
libreoffice_internal::ConstCharArrayDetector<T, sal_Int32>::TypeUtf16
indexOf(T & literal, sal_Int32 fromIndex = 0) const {
assert(fromIndex >= 0);
auto n = rtl_ustr_indexOfStr_WithLength(
pData->buffer + fromIndex, pData->length - fromIndex,
libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
libreoffice_internal::ConstCharArrayDetector<T>::length);
return n < 0 ? n : n + fromIndex;
}
#endif
/**
Returns the index within this string of the last occurrence of
the specified substring, searching backward starting at the end.
......@@ -1290,6 +1351,19 @@ public:
libreoffice_internal::ConstCharArrayDetector<T>::length);
}
#if defined LIBO_INTERNAL_ONLY
/** @overload @since LibreOffice 5.3 */
template<typename T>
typename
libreoffice_internal::ConstCharArrayDetector<T, sal_Int32>::TypeUtf16
lastIndexOf(T & literal) const {
return rtl_ustr_lastIndexOfStr_WithLength(
pData->buffer, pData->length,
libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
libreoffice_internal::ConstCharArrayDetector<T>::length);
}
#endif
/**
Strip the given character from the start of the buffer.
......
This diff is collapsed.
This diff is collapsed.
......@@ -19,6 +19,7 @@ extern bool rtl_string_unittest_non_const_literal_function;
#include <utility>
#include <sal/types.h>
#include <config_global.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include "rtl/string.h"
......@@ -37,6 +38,7 @@ private:
void checkBuffer();
void checkOUStringLiteral();
void checkOUStringLiteral1();
void checkUtf16();
void testcall( const char str[] );
......@@ -48,6 +50,7 @@ CPPUNIT_TEST(checkNonconstChar);
CPPUNIT_TEST(checkBuffer);
CPPUNIT_TEST(checkOUStringLiteral);
CPPUNIT_TEST(checkOUStringLiteral1);
CPPUNIT_TEST(checkUtf16);
CPPUNIT_TEST_SUITE_END();
};
......@@ -247,6 +250,76 @@ void test::oustring::StringLiterals::checkOUStringLiteral1()
CPPUNIT_ASSERT_EQUAL(sal_Unicode('b'), s2[1]);
}
void test::oustring::StringLiterals::checkUtf16() {
#if HAVE_CXX11_UTF16_STRING_LITERAL
rtl::OUString s1(u"abc");
CPPUNIT_ASSERT_EQUAL(rtl::OUString("abc"), s1);
s1 = u"de";
CPPUNIT_ASSERT_EQUAL(rtl::OUString("de"), s1);
s1 += u"fde";
CPPUNIT_ASSERT_EQUAL(rtl::OUString("defde"), s1);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), s1.reverseCompareTo(u"defde"));
CPPUNIT_ASSERT(s1.equalIgnoreAsciiCase(u"DEFDE"));
CPPUNIT_ASSERT(s1.match(u"fde", 2));
CPPUNIT_ASSERT(s1.matchIgnoreAsciiCase(u"FDE", 2));
rtl::OUString s2;
CPPUNIT_ASSERT(s1.startsWith(u"de", &s2));
CPPUNIT_ASSERT_EQUAL(rtl::OUString(u"fde"), s2);
CPPUNIT_ASSERT(s1.startsWithIgnoreAsciiCase(u"DEFD", &s2));
CPPUNIT_ASSERT_EQUAL(rtl::OUString(u"e"), s2);
CPPUNIT_ASSERT(s1.endsWith(u"de", &s2));
CPPUNIT_ASSERT_EQUAL(rtl::OUString(u"def"), s2);
CPPUNIT_ASSERT(s1.endsWithIgnoreAsciiCase(u"EFDE", &s2));
CPPUNIT_ASSERT_EQUAL(rtl::OUString(u"d"), s2);
CPPUNIT_ASSERT(s1 == u"defde");
CPPUNIT_ASSERT(u"defde" == s1);
CPPUNIT_ASSERT(s1 != u"abc");
CPPUNIT_ASSERT(u"abc" != s1);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), s1.indexOf(u"de", 1));
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), s1.lastIndexOf(u"de"));
sal_Int32 i = 0;
CPPUNIT_ASSERT_EQUAL(
rtl::OUString(u"abcfde"),
s1.replaceFirst(u"de", rtl::OUString("abc"), &i));
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), i);
CPPUNIT_ASSERT_EQUAL(
rtl::OUString(u"abcfde"),
s1.replaceFirst(rtl::OUString("de"), u"abc", &i));
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), i);
CPPUNIT_ASSERT_EQUAL(
rtl::OUString(u"abcfde"), s1.replaceFirst(u"de", u"abc", &i));
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), i);
CPPUNIT_ASSERT_EQUAL(
rtl::OUString(u"abcfde"), s1.replaceFirst(u"de", "abc", &i));
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), i);
CPPUNIT_ASSERT_EQUAL(
rtl::OUString(u"abcfde"), s1.replaceFirst("de", u"abc", &i));
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), i);
CPPUNIT_ASSERT_EQUAL(
rtl::OUString(u"abcfabc"), s1.replaceAll(u"de", rtl::OUString("abc")));
CPPUNIT_ASSERT_EQUAL(
rtl::OUString(u"abcfabc"), s1.replaceAll(rtl::OUString("de"), u"abc"));
CPPUNIT_ASSERT_EQUAL(
rtl::OUString(u"abcfabc"), s1.replaceAll(u"de", u"abc"));
CPPUNIT_ASSERT_EQUAL(
rtl::OUString(u"abcfabc"), s1.replaceAll(u"de", "abc"));
CPPUNIT_ASSERT_EQUAL(
rtl::OUString(u"abcfabc"), s1.replaceAll("de", u"abc"));
CPPUNIT_ASSERT_EQUAL(
rtl::OUString("abcdef"), rtl::OUString(rtl::OUString("abc") + u"def"));
CPPUNIT_ASSERT_EQUAL(
rtl::OUString("abcdef"), rtl::OUString(u"abc" + rtl::OUString("def")));
rtl::OUStringBuffer b(u"abc");
CPPUNIT_ASSERT_EQUAL(rtl::OUString("abc"), b.toString());
b.append(u"def");
CPPUNIT_ASSERT_EQUAL(rtl::OUString("abcdef"), b.toString());
b.insert(2, u"gabab");
CPPUNIT_ASSERT_EQUAL(rtl::OUString("abgababcdef"), b.toString());
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), b.indexOf(u"ab", 1));
CPPUNIT_ASSERT_EQUAL(sal_Int32(5), b.lastIndexOf(u"ab"));
#endif
}
}} // namespace
CPPUNIT_TEST_SUITE_REGISTRATION(test::oustring::StringLiterals);
......
......@@ -631,6 +631,27 @@ void rtl_uString_newConcatAsciiL(
(*newString)->length = n;
}
void rtl_uString_newConcatUtf16L(
rtl_uString ** newString, rtl_uString * left, sal_Unicode const * right,
sal_Int32 rightLength)
{
assert(newString != nullptr);
assert(left != nullptr);
assert(right != nullptr);
assert(rightLength >= 0);
if (left->length > std::numeric_limits<sal_Int32>::max() - rightLength) {
throw std::length_error("rtl_uString_newConcatUtf16L");
}
sal_Int32 n = left->length + rightLength;
rtl_uString_assign(newString, left);
rtl_uString_ensureCapacity(newString, n);
memcpy(
(*newString)->buffer + (*newString)->length, right,
rightLength * sizeof (sal_Unicode));
(*newString)->buffer[n] = 0;
(*newString)->length = n;
}
/* ======================================================================= */
static int rtl_ImplGetFastUTF8UnicodeLen( const sal_Char* pStr, sal_Int32 nLen, bool * ascii )
......@@ -1296,6 +1317,140 @@ void rtl_uString_newReplaceFirstAsciiLAsciiL(
*index = i;
}
void rtl_uString_newReplaceFirstAsciiLUtf16L(
rtl_uString ** newStr, rtl_uString * str, char const * from,
sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
sal_Int32 * index) SAL_THROW_EXTERN_C()
{
assert(str != nullptr);
assert(index != nullptr);
assert(*index >= 0 && *index <= str->length);
assert(fromLength >= 0);
assert(to != nullptr);
assert(toLength >= 0);
sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
str->buffer + *index, str->length - *index, from, fromLength);
if (i == -1) {
rtl_uString_assign(newStr, str);
} else {
assert(i <= str->length - *index);
i += *index;
assert(fromLength <= str->length);
if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
rtl_uString_release(*newStr);
*newStr = nullptr;
} else {
sal_Int32 n = str->length - fromLength + toLength;
rtl_uString_acquire(str); // in case *newStr == str
rtl_uString_new_WithLength(newStr, n);
if (n != 0 && /*TODO:*/ *newStr != nullptr) {
(*newStr)->length = n;
assert(i >= 0 && i < str->length);
memcpy(
(*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
memcpy(
(*newStr)->buffer + i, to, toLength * sizeof (sal_Unicode));
memcpy(
(*newStr)->buffer + i + toLength,
str->buffer + i + fromLength,
(str->length - i - fromLength) * sizeof (sal_Unicode));
}
rtl_uString_release(str);
}
}
*index = i;
}
void rtl_uString_newReplaceFirstUtf16LAsciiL(
rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
sal_Int32 fromLength, char const * to, sal_Int32 toLength,
sal_Int32 * index) SAL_THROW_EXTERN_C()
{
assert(str != nullptr);
assert(index != nullptr);
assert(*index >= 0 && *index <= str->length);
assert(fromLength >= 0);
assert(to != nullptr);
assert(toLength >= 0);
sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
str->buffer + *index, str->length - *index, from, fromLength);
if (i == -1) {
rtl_uString_assign(newStr, str);
} else {
assert(i <= str->length - *index);
i += *index;
assert(fromLength <= str->length);
if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
rtl_uString_release(*newStr);
*newStr = nullptr;
} else {
sal_Int32 n = str->length - fromLength + toLength;
rtl_uString_acquire(str); // in case *newStr == str
rtl_uString_new_WithLength(newStr, n);
if (n != 0 && /*TODO:*/ *newStr != nullptr) {
(*newStr)->length = n;
assert(i >= 0 && i < str->length);
memcpy(
(*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
for (sal_Int32 j = 0; j != toLength; ++j) {
assert(static_cast< unsigned char >(to[j]) <= 0x7F);
(*newStr)->buffer[i + j] = to[j];
}
memcpy(
(*newStr)->buffer + i + toLength,
str->buffer + i + fromLength,
(str->length - i - fromLength) * sizeof (sal_Unicode));
}
rtl_uString_release(str);
}
}
*index = i;
}
void rtl_uString_newReplaceFirstUtf16LUtf16L(
rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
sal_Int32 * index) SAL_THROW_EXTERN_C()
{
assert(str != nullptr);
assert(index != nullptr);
assert(*index >= 0 && *index <= str->length);
assert(fromLength >= 0);
assert(to != nullptr);
assert(toLength >= 0);
sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
str->buffer + *index, str->length - *index, from, fromLength);
if (i == -1) {
rtl_uString_assign(newStr, str);
} else {
assert(i <= str->length - *index);
i += *index;
assert(fromLength <= str->length);
if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
rtl_uString_release(*newStr);
*newStr = nullptr;
} else {
sal_Int32 n = str->length - fromLength + toLength;
rtl_uString_acquire(str); // in case *newStr == str
rtl_uString_new_WithLength(newStr, n);
if (n != 0 && /*TODO:*/ *newStr != nullptr) {
(*newStr)->length = n;
assert(i >= 0 && i < str->length);
memcpy(
(*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
memcpy(
(*newStr)->buffer + i, to, toLength * sizeof (sal_Unicode));
memcpy(
(*newStr)->buffer + i + toLength,
str->buffer + i + fromLength,
(str->length - i - fromLength) * sizeof (sal_Unicode));
}
rtl_uString_release(str);
}
}
*index = i;
}
void rtl_uString_newReplaceAll(
rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
rtl_uString const * to) SAL_THROW_EXTERN_C()
......@@ -1364,4 +1519,52 @@ void rtl_uString_newReplaceAllAsciiLAsciiL(
}
}
void rtl_uString_newReplaceAllAsciiLUtf16L(
rtl_uString ** newStr, rtl_uString * str, char const * from,
sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
SAL_THROW_EXTERN_C()
{
assert(toLength >= 0);
rtl_uString_assign(newStr, str);
for (sal_Int32 i = 0;; i += toLength) {
rtl_uString_newReplaceFirstAsciiLUtf16L(
newStr, *newStr, from, fromLength, to, toLength, &i);
if (i == -1 || *newStr == nullptr) {
break;
}
}
}
void rtl_uString_newReplaceAllUtf16LAsciiL(
rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
sal_Int32 fromLength, char const * to, sal_Int32 toLength)
SAL_THROW_EXTERN_C()
{
assert(toLength >= 0);
rtl_uString_assign(newStr, str);
for (sal_Int32 i = 0;; i += toLength) {
rtl_uString_newReplaceFirstUtf16LAsciiL(
newStr, *newStr, from, fromLength, to, toLength, &i);
if (i == -1 || *newStr == nullptr) {
break;
}
}
}
void rtl_uString_newReplaceAllUtf16LUtf16L(
rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
SAL_THROW_EXTERN_C()
{
assert(toLength >= 0);
rtl_uString_assign(newStr, str);
for (sal_Int32 i = 0;; i += toLength) {
rtl_uString_newReplaceFirstUtf16LUtf16L(
newStr, *newStr, from, fromLength, to, toLength, &i);
if (i == -1 || *newStr == nullptr) {
break;
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -695,6 +695,17 @@ LIBO_UDK_5.2 { # symbols available in >= LibO 5.2
osl_getShortUserName;
} LIBO_UDK_5.1;
LIBO_UDK_5.3 { # symbols available in >= LibO 5.3
global:
rtl_uString_newConcatUtf16L;
rtl_uString_newReplaceAllAsciiLUtf16L;
rtl_uString_newReplaceAllUtf16LAsciiL;
rtl_uString_newReplaceAllUtf16LUtf16L;
rtl_uString_newReplaceFirstAsciiLUtf16L;
rtl_uString_newReplaceFirstUtf16LAsciiL;
rtl_uString_newReplaceFirstUtf16LUtf16L;
} LIBO_UDK_5.2;
PRIVATE_1.0 {
global:
osl_detail_ObjectRegistry_storeAddresses;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment