* and from NULL.
* @draft ICU 59
*/
-class U_COMMON_API Char16Ptr {
+class U_COMMON_API Char16Ptr final {
public:
/**
* Copies the pointer.
* @draft ICU 59
*/
inline Char16Ptr(uint16_t *p);
-#if U_SIZEOF_WCHAR_T==2
+#if U_SIZEOF_WCHAR_T==2 || defined(U_IN_DOXYGEN)
/**
* Converts the pointer to char16_t *.
+ * (Only defined if U_SIZEOF_WCHAR_T==2.)
* @draft ICU 59
*/
inline Char16Ptr(wchar_t *p);
* @draft ICU 59
*/
inline Char16Ptr(std::nullptr_t p);
+ /**
+ * NULL constructor.
+ * Must only be used for 0 which is usually the value of NULL.
+ * @draft ICU 59
+ */
+ Char16Ptr(int null);
/**
* Pointer access.
* @draft ICU 59
*/
- inline operator char16_t *();
+ inline char16_t *get();
+ /**
+ * Pointer access via type conversion (e.g., static_cast).
+ * @draft ICU 59
+ */
+ operator char16_t *() { return get(); }
private:
+ Char16Ptr() = delete;
+
#ifdef U_ALIASING_BARRIER
template<typename T> char16_t *cast(T *t) {
U_ALIASING_BARRIER(t);
#endif
Char16Ptr::Char16Ptr(std::nullptr_t p) : p(p) {}
-Char16Ptr::operator char16_t *() { return p; }
+char16_t *Char16Ptr::get() { return p; }
#else
#endif
Char16Ptr::Char16Ptr(std::nullptr_t p) { u.cp = p; }
-Char16Ptr::operator char16_t *() { return u.cp; }
+char16_t *Char16Ptr::get() { return u.cp; }
#endif
* and from NULL.
* @draft ICU 59
*/
-class U_COMMON_API ConstChar16Ptr {
+class U_COMMON_API ConstChar16Ptr final {
public:
/**
* Copies the pointer.
* @draft ICU 59
*/
inline ConstChar16Ptr(const uint16_t *p);
-#if U_SIZEOF_WCHAR_T==2
+#if U_SIZEOF_WCHAR_T==2 || defined(U_IN_DOXYGEN)
/**
* Converts the pointer to char16_t *.
+ * (Only defined if U_SIZEOF_WCHAR_T==2.)
* @draft ICU 59
*/
inline ConstChar16Ptr(const wchar_t *p);
* @draft ICU 59
*/
inline ConstChar16Ptr(const std::nullptr_t p);
+ /**
+ * NULL constructor.
+ * Must only be used for 0 which is usually the value of NULL.
+ * @draft ICU 59
+ */
+ ConstChar16Ptr(int null);
/**
* Pointer access.
* @draft ICU 59
*/
- inline operator const char16_t *() const;
+ inline const char16_t *get() const;
+ /**
+ * Pointer access via type conversion (e.g., static_cast).
+ * @draft ICU 59
+ */
+ operator const char16_t *() { return get(); }
private:
+ ConstChar16Ptr() = delete;
+
#ifdef U_ALIASING_BARRIER
template<typename T> const char16_t *cast(const T *t) {
U_ALIASING_BARRIER(t);
#endif
ConstChar16Ptr::ConstChar16Ptr(const std::nullptr_t p) : p(p) {}
-ConstChar16Ptr::operator const char16_t *() const { return p; }
+const char16_t *ConstChar16Ptr::get() const { return p; }
#else
#endif
ConstChar16Ptr::ConstChar16Ptr(const std::nullptr_t p) { u.cp = p; }
-ConstChar16Ptr::operator const char16_t *() const { return u.cp; }
+const char16_t *ConstChar16Ptr::get() const { return u.cp; }
#endif
* @draft ICU 59
*/
UNISTR_FROM_STRING_EXPLICIT UnicodeString(const uint16_t *text) :
- UnicodeString(static_cast<const UChar *>(ConstChar16Ptr(text))) {}
+ UnicodeString(ConstChar16Ptr(text).get()) {}
-#if U_SIZEOF_WCHAR_T==2
+#if U_SIZEOF_WCHAR_T==2 || defined(U_IN_DOXYGEN)
/**
* wchar_t * constructor.
+ * (Only defined if U_SIZEOF_WCHAR_T==2.)
* Delegates to UnicodeString(const UChar *).
*
* It is recommended to mark this constructor "explicit" by
* @draft ICU 59
*/
UNISTR_FROM_STRING_EXPLICIT UnicodeString(const wchar_t *text) :
- UnicodeString(static_cast<const UChar *>(ConstChar16Ptr(text))) {}
+ UnicodeString(ConstChar16Ptr(text).get()) {}
#endif
/**
* @draft ICU 59
*/
UnicodeString(const uint16_t *text, int32_t length) :
- UnicodeString(static_cast<const UChar *>(ConstChar16Ptr(text)), length) {}
+ UnicodeString(ConstChar16Ptr(text).get(), length) {}
-#if U_SIZEOF_WCHAR_T==2
+#if U_SIZEOF_WCHAR_T==2 || defined(U_IN_DOXYGEN)
/**
* wchar_t * constructor.
+ * (Only defined if U_SIZEOF_WCHAR_T==2.)
* Delegates to UnicodeString(const UChar *, int32_t).
* @param text NUL-terminated UTF-16 string
* @param length string length
* @draft ICU 59
*/
UnicodeString(const wchar_t *text, int32_t length) :
- UnicodeString(static_cast<const UChar *>(ConstChar16Ptr(text)), length) {}
+ UnicodeString(ConstChar16Ptr(text).get(), length) {}
#endif
/**
* @draft ICU 59
*/
UnicodeString(uint16_t *buffer, int32_t buffLength, int32_t buffCapacity) :
- UnicodeString(static_cast<UChar *>(Char16Ptr(buffer)), buffLength, buffCapacity) {}
+ UnicodeString(Char16Ptr(buffer).get(), buffLength, buffCapacity) {}
-#if U_SIZEOF_WCHAR_T==2
+#if U_SIZEOF_WCHAR_T==2 || defined(U_IN_DOXYGEN)
/**
* Writable-aliasing wchar_t * constructor.
+ * (Only defined if U_SIZEOF_WCHAR_T==2.)
* Delegates to UnicodeString(const UChar *, int32_t, int32_t).
* @param buffer writable buffer of/for UTF-16 text
* @param buffLength length of the current buffer contents
* @draft ICU 59
*/
UnicodeString(wchar_t *buffer, int32_t buffLength, int32_t buffCapacity) :
- UnicodeString(static_cast<UChar *>(Char16Ptr(buffer)), buffLength, buffCapacity) {}
+ UnicodeString(Char16Ptr(buffer).get(), buffLength, buffCapacity) {}
#endif
/**
U_NAMESPACE_BEGIN
+#ifdef U_ALIASING_BARRIER
+
+Char16Ptr::Char16Ptr(int null) : p(nullptr) {
+ U_ASSERT(null == 0);
+ if (null != 0) {
+ // Try to provoke a crash.
+ p = reinterpret_cast<char16_t *>(1);
+ }
+}
+
+ConstChar16Ptr::ConstChar16Ptr(int null) : p(nullptr) {
+ U_ASSERT(null == 0);
+ if (null != 0) {
+ // Try to provoke a crash.
+ p = reinterpret_cast<char16_t *>(1);
+ }
+}
+
+#else
+
+Char16Ptr::Char16Ptr(int null) {
+ U_ASSERT(null == 0);
+ if (null == 0) {
+ u.cp = nullptr;
+ } else {
+ // Try to provoke a crash.
+ u.cp = reinterpret_cast<char16_t *>(1);
+ }
+}
+
+ConstChar16Ptr::ConstChar16Ptr(int null) {
+ U_ASSERT(null == 0);
+ if (null == 0) {
+ u.cp = nullptr;
+ } else {
+ // Try to provoke a crash.
+ u.cp = reinterpret_cast<char16_t *>(1);
+ }
+}
+
+#endif
+
/* The Replaceable virtual destructor can't be defined in the header
due to how AIX works with multiple definitions of virtual functions.
*/
// text is terminated, or else it would have failed the above test
textLength = u_strlen(text);
}
- setArray(const_cast<UChar *>(static_cast<const char16_t *>(text)), textLength,
+ setArray(const_cast<UChar *>(text.get()), textLength,
isTerminated ? textLength + 1 : textLength);
}
}
TESTCASE_AUTO(TestSizeofUnicodeString);
TESTCASE_AUTO(TestStartsWithAndEndsWithNulTerminated);
TESTCASE_AUTO(TestMoveSwap);
+ TESTCASE_AUTO(TestUInt16Pointers);
+ TESTCASE_AUTO(TestWCharPointers);
+ TESTCASE_AUTO(TestNullPointers);
+ TESTCASE_AUTO(TestZeroPointers);
TESTCASE_AUTO_END;
}
errln("UnicodeString copy after self-move did not work");
}
}
+
+void
+UnicodeStringTest::TestUInt16Pointers() {
+ static const uint16_t carr[] = { 0x61, 0x62, 0x63, 0 };
+ uint16_t arr[4];
+
+ UnicodeString expected(u"abc");
+ assertEquals("abc from pointer", expected, UnicodeString(carr));
+ assertEquals("abc from pointer+length", expected, UnicodeString(carr, 3));
+ assertEquals("abc from read-only-alias pointer", expected, UnicodeString(TRUE, carr, 3));
+
+ UnicodeString alias(arr, 0, 4);
+ alias.append(u'a').append(u'b').append(u'c');
+ assertEquals("abc from writable alias", expected, alias);
+ assertEquals("buffer=abc from writable alias", expected, UnicodeString(arr, 3));
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ int32_t length = UnicodeString(u"def").extract(arr, 4, errorCode);
+ TEST_ASSERT_STATUS(errorCode);
+ assertEquals("def from extract()", UnicodeString(u"def"), UnicodeString(arr, length));
+}
+
+void
+UnicodeStringTest::TestWCharPointers() {
+#if U_SIZEOF_WCHAR_T==2
+ static const wchar_t carr[] = { 0x61, 0x62, 0x63, 0 };
+ wchar_t arr[4];
+
+ UnicodeString expected(u"abc");
+ assertEquals("abc from pointer", expected, UnicodeString(carr));
+ assertEquals("abc from pointer+length", expected, UnicodeString(carr, 3));
+ assertEquals("abc from read-only-alias pointer", expected, UnicodeString(TRUE, carr, 3));
+
+ UnicodeString alias(arr, 0, 4);
+ alias.append(u'a').append(u'b').append(u'c');
+ assertEquals("abc from writable alias", expected, alias);
+ assertEquals("buffer=abc from writable alias", expected, UnicodeString(arr, 3));
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ int32_t length = UnicodeString(u"def").extract(arr, 4, errorCode);
+ TEST_ASSERT_STATUS(errorCode);
+ assertEquals("def from extract()", UnicodeString(u"def"), UnicodeString(arr, length));
+#endif
+}
+
+void
+UnicodeStringTest::TestNullPointers() {
+ assertTrue("empty from nullptr", UnicodeString(nullptr).isEmpty());
+ assertTrue("empty from nullptr+length", UnicodeString(nullptr, 2).isEmpty());
+ assertTrue("empty from read-only-alias nullptr", UnicodeString(TRUE, nullptr, 3).isEmpty());
+
+ UnicodeString alias(nullptr, 4, 4); // empty, no alias
+ assertTrue("empty from writable alias", alias.isEmpty());
+ alias.append(u'a').append(u'b').append(u'c');
+ UnicodeString expected(u"abc");
+ assertEquals("abc from writable alias", expected, alias);
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ UnicodeString(u"def").extract(nullptr, 0, errorCode);
+ assertEquals("buffer overflow extracting to nullptr", U_BUFFER_OVERFLOW_ERROR, errorCode);
+}
+
+void
+UnicodeStringTest::TestZeroPointers() {
+ // There are constructor overloads with one and three integer parameters
+ // which match passing 0, so we cannot test using 0 for UnicodeString(pointer)
+ // or UnicodeString(read-only or writable alias).
+ // There are multiple two-parameter constructors that make using 0
+ // for the first parameter ambiguous already,
+ // so we cannot test using 0 for UnicodeString(pointer, length).
+
+ // extract() also has enough overloads to be ambiguous with 0.
+ // Test the pointer wrapper directly.
+ assertTrue("0 --> nullptr", Char16Ptr(0).get() == nullptr);
+ assertTrue("0 --> const nullptr", ConstChar16Ptr(0).get() == nullptr);
+}
void TestUnicodeStringImplementsAppendable();
void TestSizeofUnicodeString();
void TestMoveSwap();
+
+ void TestUInt16Pointers();
+ void TestWCharPointers();
+ void TestNullPointers();
+ void TestZeroPointers();
};
#endif