ICU-22954 Make UCollator predicates usable without U_SHOW_CPLUSPLUS_API.

Until now, the implementation of the UCollator predicates has been using
UnicodeString and StringPiece as convenient wrappers for converting from
standard C++ data types to ICU4C data types.

But as that doesn't work when the client uses ICU4C built without
U_SHOW_CPLUSPLUS_API this is now changed to instead perform these
conversions directly.

(It's a bit more code, but does just the same thing in the end.)
This commit is contained in:
Fredrik Roubert 2025-02-06 18:47:56 +01:00 committed by Fredrik Roubert
parent e8c179dedd
commit ee8806e87c
7 changed files with 164 additions and 9 deletions

View file

@ -283,6 +283,32 @@ inline const char16_t *uprv_char16PtrFromUChar(const T *p) {
#endif
}
}
#if !U_CHAR16_IS_TYPEDEF && (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION < 180000)
/** @internal */
inline const char16_t *uprv_char16PtrFromUint16(const uint16_t *p) {
#if U_SHOW_CPLUSPLUS_API
return ConstChar16Ptr(p).get();
#else
#ifdef U_ALIASING_BARRIER
U_ALIASING_BARRIER(p);
#endif
return reinterpret_cast<const char16_t *>(p);
#endif
}
#endif
#if U_SIZEOF_WCHAR_T==2
/** @internal */
inline const char16_t *uprv_char16PtrFromWchar(const wchar_t *p) {
#if U_SHOW_CPLUSPLUS_API
return ConstChar16Ptr(p).get();
#else
#ifdef U_ALIASING_BARRIER
U_ALIASING_BARRIER(p);
#endif
return reinterpret_cast<const char16_t *>(p);
#endif
}
#endif
#endif
/**

View file

@ -1526,7 +1526,6 @@ ucol_openBinary(const uint8_t *bin, int32_t length,
#include <type_traits>
#include "unicode/char16ptr.h"
#include "unicode/stringpiece.h"
#include "unicode/unistr.h"
namespace U_HEADER_ONLY_NAMESPACE {
@ -1547,6 +1546,7 @@ class Predicate {
/** @internal */
explicit Predicate(const UCollator* ucol) : collator(ucol) {}
#if U_SHOW_CPLUSPLUS_API
/** @internal */
template <
typename T, typename U,
@ -1554,6 +1554,28 @@ class Predicate {
bool operator()(const T& lhs, const U& rhs) const {
return match(UnicodeString::readOnlyAlias(lhs), UnicodeString::readOnlyAlias(rhs));
}
#else
/** @internal */
bool operator()(std::u16string_view lhs, std::u16string_view rhs) const {
return match(lhs, rhs);
}
#if !U_CHAR16_IS_TYPEDEF && (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION < 180000)
/** @internal */
bool operator()(std::basic_string_view<uint16_t> lhs, std::basic_string_view<uint16_t> rhs) const {
return match({uprv_char16PtrFromUint16(lhs.data()), lhs.length()},
{uprv_char16PtrFromUint16(rhs.data()), rhs.length()});
}
#endif
#if U_SIZEOF_WCHAR_T==2
/** @internal */
bool operator()(std::wstring_view lhs, std::wstring_view rhs) const {
return match({uprv_char16PtrFromWchar(lhs.data()), lhs.length()},
{uprv_char16PtrFromWchar(rhs.data()), rhs.length()});
}
#endif
#endif
/** @internal */
bool operator()(std::string_view lhs, std::string_view rhs) const {
@ -1563,27 +1585,28 @@ class Predicate {
#if defined(__cpp_char8_t)
/** @internal */
bool operator()(std::u8string_view lhs, std::u8string_view rhs) const {
return match(lhs, rhs);
return match({reinterpret_cast<const char*>(lhs.data()), lhs.length()},
{reinterpret_cast<const char*>(rhs.data()), rhs.length()});
}
#endif
private:
bool match(UnicodeString lhs, UnicodeString rhs) const {
bool match(std::u16string_view lhs, std::u16string_view rhs) const {
return compare(
ucol_strcoll(
collator,
toUCharPtr(lhs.getBuffer()), lhs.length(),
toUCharPtr(rhs.getBuffer()), rhs.length()),
toUCharPtr(lhs.data()), static_cast<int32_t>(lhs.length()),
toUCharPtr(rhs.data()), static_cast<int32_t>(rhs.length())),
result);
}
bool match(StringPiece lhs, StringPiece rhs) const {
bool match(std::string_view lhs, std::string_view rhs) const {
UErrorCode status = U_ZERO_ERROR;
return compare(
ucol_strcollUTF8(
collator,
lhs.data(), lhs.length(),
rhs.data(), rhs.length(),
lhs.data(), static_cast<int32_t>(lhs.length()),
rhs.data(), static_cast<int32_t>(rhs.length()),
&status),
result);
}

View file

@ -75,7 +75,7 @@ numbertest_parse.o numbertest_doubleconversion.o numbertest_skeletons.o \
static_unisets_test.o numfmtdatadriventest.o numbertest_range.o erarulestest.o \
formattedvaluetest.o formatted_string_builder_test.o numbertest_permutation.o \
units_data_test.o units_router_test.o units_test.o displayoptions_test.o \
numbertest_simple.o uchar_type_build_test.o usetheaderonlytest.o
numbertest_simple.o uchar_type_build_test.o ucolheaderonlytest.o usetheaderonlytest.o
DEPS = $(OBJECTS:.o=.d)

View file

@ -242,6 +242,7 @@
<ClCompile Include="units_router_test.cpp" />
<ClCompile Include="units_test.cpp" />
<ClCompile Include="uchar_type_build_test.cpp" />
<ClCompile Include="ucolheaderonlytest.cpp" />
<ClCompile Include="usetheaderonlytest.cpp" />
</ItemGroup>
<ItemGroup>

View file

@ -580,6 +580,9 @@
<ClCompile Include="messageformat2test_read_json.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="ucolheaderonlytest.cpp">
<Filter>misc</Filter>
</ClCompile>
<ClCompile Include="usetheaderonlytest.cpp">
<Filter>misc</Filter>
</ClCompile>

View file

@ -35,6 +35,9 @@
#include "usettest.h"
extern IntlTest *createBytesTrieTest();
#if !UCONFIG_NO_COLLATION
extern IntlTest *createUColHeaderOnlyTest();
#endif
extern IntlTest *createUSetHeaderOnlyTest();
extern IntlTest *createLocaleMatcherTest();
static IntlTest *createLocalPointerTest();
@ -83,6 +86,9 @@ void IntlTestUtilities::runIndexedTest( int32_t index, UBool exec, const char* &
TESTCASE_AUTO_CLASS(LocaleBuilderTest);
TESTCASE_AUTO_CREATE_CLASS(LocaleMatcherTest);
TESTCASE_AUTO_CREATE_CLASS(UHashTest);
#if !UCONFIG_NO_COLLATION
TESTCASE_AUTO_CREATE_CLASS(UColHeaderOnlyTest);
#endif
TESTCASE_AUTO_CREATE_CLASS(USetHeaderOnlyTest);
TESTCASE_AUTO_END;
}

View file

@ -0,0 +1,96 @@
// © 2025 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
// Test header-only ICU C++ APIs. Do not use other ICU C++ APIs.
// Non-default configuration:
#define U_SHOW_CPLUSPLUS_API 0
#include "unicode/utypes.h"
#if !UCONFIG_NO_COLLATION
#include <string_view>
#include "unicode/ucol.h"
#include "intltest.h"
namespace {
class UColHeaderOnlyTest : public IntlTest {
public:
UColHeaderOnlyTest() = default;
void runIndexedTest(int32_t index, UBool exec, const char*& name, char* par = nullptr) override;
void TestPredicateTypes();
};
void UColHeaderOnlyTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char* /*par*/) {
if (exec) {
logln("TestSuite UColHeaderOnlyTest: ");
}
TESTCASE_AUTO_BEGIN;
TESTCASE_AUTO(TestPredicateTypes);
TESTCASE_AUTO_END;
}
class UCollatorWrapper {
public:
UCollatorWrapper(const char* loc, UErrorCode* status) : ucol(ucol_open(loc, status)) {}
~UCollatorWrapper() { ucol_close(ucol); }
operator UCollator*() { return ucol; }
private:
UCollator* ucol;
};
constexpr char16_t TEXT_CHAR16[] = u"char16";
#if !U_CHAR16_IS_TYPEDEF && (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION < 180000)
constexpr uint16_t TEXT_UINT16[] = {0x75, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x00};
#endif
#if U_SIZEOF_WCHAR_T == 2
constexpr wchar_t TEXT_WCHAR[] = L"wchar";
#endif
constexpr char TEXT_CHAR[] = "char";
#if defined(__cpp_char8_t)
constexpr char8_t TEXT_CHAR8[] = u8"char8";
#endif
// Verify that the UCollator predicates handle all string types.
void UColHeaderOnlyTest::TestPredicateTypes() {
using namespace U_HEADER_NESTED_NAMESPACE;
IcuTestErrorCode status(*this, "TestPredicateTypes");
UCollatorWrapper ucol("", status);
status.assertSuccess();
const auto equal_to = collator::equal_to(ucol);
assertTrue("char16_t", equal_to(TEXT_CHAR16, TEXT_CHAR16));
assertTrue("u16string_view", equal_to(std::u16string_view{TEXT_CHAR16}, TEXT_CHAR16));
#if !U_CHAR16_IS_TYPEDEF && (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION < 180000)
assertTrue("uint16_t", equal_to(TEXT_UINT16, TEXT_UINT16));
assertTrue("basic_string_view<uint16_t>",
equal_to(std::basic_string_view<uint16_t>{TEXT_UINT16}, TEXT_UINT16));
#endif
#if U_SIZEOF_WCHAR_T == 2
assertTrue("wchar_t", equal_to(TEXT_WCHAR, TEXT_WCHAR));
assertTrue("wstring_view", equal_to(std::wstring_view{TEXT_WCHAR}, TEXT_WCHAR));
#endif
assertTrue("char", equal_to(TEXT_CHAR, TEXT_CHAR));
assertTrue("string_view", equal_to(std::string_view{TEXT_CHAR}, TEXT_CHAR));
#if defined(__cpp_char8_t)
assertTrue("char8_t", equal_to(TEXT_CHAR8, TEXT_CHAR8));
assertTrue("u8string_view", equal_to(std::u8string_view{TEXT_CHAR8}, TEXT_CHAR8));
#endif
}
} // namespace
IntlTest* createUColHeaderOnlyTest() {
return new UColHeaderOnlyTest();
}
#endif // !UCONFIG_NO_COLLATION