1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3
4 // char16ptr.h
5 // created: 2017feb28 Markus W. Scherer
6
7 #ifndef __CHAR16PTR_H__
8 #define __CHAR16PTR_H__
9
10 #include "unicode/utypes.h"
11
12 #if LIBANDROIDICU_U_SHOW_CPLUSPLUS_API
13
14 #include <cstddef>
15 #include <string_view>
16
17 /**
18 * \file
19 * \brief C++ API: char16_t pointer wrappers with
20 * implicit conversion from bit-compatible raw pointer types.
21 * Also conversion functions from char16_t * to UChar * and OldUChar *.
22 */
23
24 U_NAMESPACE_BEGIN
25
26 /**
27 * \def U_ALIASING_BARRIER
28 * Barrier for pointer anti-aliasing optimizations even across function boundaries.
29 * @internal
30 */
31 #ifdef U_ALIASING_BARRIER
32 // Use the predefined value.
33 #elif (defined(__clang__) || defined(__GNUC__)) && U_PLATFORM != U_PF_BROWSER_NATIVE_CLIENT
34 # define U_ALIASING_BARRIER(ptr) asm volatile("" : : "rm"(ptr) : "memory")
35 #elif defined(U_IN_DOXYGEN)
36 # define U_ALIASING_BARRIER(ptr)
37 #endif
38
39 /**
40 * char16_t * wrapper with implicit conversion from distinct but bit-compatible pointer types.
41 * @stable ICU 59
42 */
43 class U_COMMON_API Char16Ptr final {
44 public:
45 /**
46 * Copies the pointer.
47 * @param p pointer
48 * @stable ICU 59
49 */
50 inline Char16Ptr(char16_t *p);
51 #if !U_CHAR16_IS_TYPEDEF
52 /**
53 * Converts the pointer to char16_t *.
54 * @param p pointer to be converted
55 * @stable ICU 59
56 */
57 inline Char16Ptr(uint16_t *p);
58 #endif
59 #if U_SIZEOF_WCHAR_T==2 || defined(U_IN_DOXYGEN)
60 /**
61 * Converts the pointer to char16_t *.
62 * (Only defined if U_SIZEOF_WCHAR_T==2.)
63 * @param p pointer to be converted
64 * @stable ICU 59
65 */
66 inline Char16Ptr(wchar_t *p);
67 #endif
68 /**
69 * nullptr constructor.
70 * @param p nullptr
71 * @stable ICU 59
72 */
73 inline Char16Ptr(std::nullptr_t p);
74 /**
75 * Destructor.
76 * @stable ICU 59
77 */
78 inline ~Char16Ptr();
79
80 /**
81 * Pointer access.
82 * @return the wrapped pointer
83 * @stable ICU 59
84 */
85 inline char16_t *get() const;
86 /**
87 * char16_t pointer access via type conversion (e.g., static_cast).
88 * @return the wrapped pointer
89 * @stable ICU 59
90 */
91 inline operator char16_t *() const { return get(); }
92
93 private:
94 Char16Ptr() = delete;
95
96 #ifdef U_ALIASING_BARRIER
cast(T * t)97 template<typename T> static char16_t *cast(T *t) {
98 U_ALIASING_BARRIER(t);
99 return reinterpret_cast<char16_t *>(t);
100 }
101
102 char16_t *p_;
103 #else
104 union {
105 char16_t *cp;
106 uint16_t *up;
107 wchar_t *wp;
108 } u_;
109 #endif
110 };
111
112 /// \cond
113 #ifdef U_ALIASING_BARRIER
114
Char16Ptr(char16_t * p)115 Char16Ptr::Char16Ptr(char16_t *p) : p_(p) {}
116 #if !U_CHAR16_IS_TYPEDEF
Char16Ptr(uint16_t * p)117 Char16Ptr::Char16Ptr(uint16_t *p) : p_(cast(p)) {}
118 #endif
119 #if U_SIZEOF_WCHAR_T==2
Char16Ptr(wchar_t * p)120 Char16Ptr::Char16Ptr(wchar_t *p) : p_(cast(p)) {}
121 #endif
Char16Ptr(std::nullptr_t p)122 Char16Ptr::Char16Ptr(std::nullptr_t p) : p_(p) {}
~Char16Ptr()123 Char16Ptr::~Char16Ptr() {
124 U_ALIASING_BARRIER(p_);
125 }
126
get()127 char16_t *Char16Ptr::get() const { return p_; }
128
129 #else
130
Char16Ptr(char16_t * p)131 Char16Ptr::Char16Ptr(char16_t *p) { u_.cp = p; }
132 #if !U_CHAR16_IS_TYPEDEF
Char16Ptr(uint16_t * p)133 Char16Ptr::Char16Ptr(uint16_t *p) { u_.up = p; }
134 #endif
135 #if U_SIZEOF_WCHAR_T==2
Char16Ptr(wchar_t * p)136 Char16Ptr::Char16Ptr(wchar_t *p) { u_.wp = p; }
137 #endif
Char16Ptr(std::nullptr_t p)138 Char16Ptr::Char16Ptr(std::nullptr_t p) { u_.cp = p; }
~Char16Ptr()139 Char16Ptr::~Char16Ptr() {}
140
get()141 char16_t *Char16Ptr::get() const { return u_.cp; }
142
143 #endif
144 /// \endcond
145
146 /**
147 * const char16_t * wrapper with implicit conversion from distinct but bit-compatible pointer types.
148 * @stable ICU 59
149 */
150 class U_COMMON_API ConstChar16Ptr final {
151 public:
152 /**
153 * Copies the pointer.
154 * @param p pointer
155 * @stable ICU 59
156 */
157 inline ConstChar16Ptr(const char16_t *p);
158 #if !U_CHAR16_IS_TYPEDEF
159 /**
160 * Converts the pointer to char16_t *.
161 * @param p pointer to be converted
162 * @stable ICU 59
163 */
164 inline ConstChar16Ptr(const uint16_t *p);
165 #endif
166 #if U_SIZEOF_WCHAR_T==2 || defined(U_IN_DOXYGEN)
167 /**
168 * Converts the pointer to char16_t *.
169 * (Only defined if U_SIZEOF_WCHAR_T==2.)
170 * @param p pointer to be converted
171 * @stable ICU 59
172 */
173 inline ConstChar16Ptr(const wchar_t *p);
174 #endif
175 /**
176 * nullptr constructor.
177 * @param p nullptr
178 * @stable ICU 59
179 */
180 inline ConstChar16Ptr(const std::nullptr_t p);
181
182 /**
183 * Destructor.
184 * @stable ICU 59
185 */
186 inline ~ConstChar16Ptr();
187
188 /**
189 * Pointer access.
190 * @return the wrapped pointer
191 * @stable ICU 59
192 */
193 inline const char16_t *get() const;
194 /**
195 * char16_t pointer access via type conversion (e.g., static_cast).
196 * @return the wrapped pointer
197 * @stable ICU 59
198 */
199 inline operator const char16_t *() const { return get(); }
200
201 private:
202 ConstChar16Ptr() = delete;
203
204 #ifdef U_ALIASING_BARRIER
cast(const T * t)205 template<typename T> static const char16_t *cast(const T *t) {
206 U_ALIASING_BARRIER(t);
207 return reinterpret_cast<const char16_t *>(t);
208 }
209
210 const char16_t *p_;
211 #else
212 union {
213 const char16_t *cp;
214 const uint16_t *up;
215 const wchar_t *wp;
216 } u_;
217 #endif
218 };
219
220 /// \cond
221 #ifdef U_ALIASING_BARRIER
222
ConstChar16Ptr(const char16_t * p)223 ConstChar16Ptr::ConstChar16Ptr(const char16_t *p) : p_(p) {}
224 #if !U_CHAR16_IS_TYPEDEF
ConstChar16Ptr(const uint16_t * p)225 ConstChar16Ptr::ConstChar16Ptr(const uint16_t *p) : p_(cast(p)) {}
226 #endif
227 #if U_SIZEOF_WCHAR_T==2
ConstChar16Ptr(const wchar_t * p)228 ConstChar16Ptr::ConstChar16Ptr(const wchar_t *p) : p_(cast(p)) {}
229 #endif
ConstChar16Ptr(const std::nullptr_t p)230 ConstChar16Ptr::ConstChar16Ptr(const std::nullptr_t p) : p_(p) {}
~ConstChar16Ptr()231 ConstChar16Ptr::~ConstChar16Ptr() {
232 U_ALIASING_BARRIER(p_);
233 }
234
get()235 const char16_t *ConstChar16Ptr::get() const { return p_; }
236
237 #else
238
ConstChar16Ptr(const char16_t * p)239 ConstChar16Ptr::ConstChar16Ptr(const char16_t *p) { u_.cp = p; }
240 #if !U_CHAR16_IS_TYPEDEF
ConstChar16Ptr(const uint16_t * p)241 ConstChar16Ptr::ConstChar16Ptr(const uint16_t *p) { u_.up = p; }
242 #endif
243 #if U_SIZEOF_WCHAR_T==2
ConstChar16Ptr(const wchar_t * p)244 ConstChar16Ptr::ConstChar16Ptr(const wchar_t *p) { u_.wp = p; }
245 #endif
ConstChar16Ptr(const std::nullptr_t p)246 ConstChar16Ptr::ConstChar16Ptr(const std::nullptr_t p) { u_.cp = p; }
~ConstChar16Ptr()247 ConstChar16Ptr::~ConstChar16Ptr() {}
248
get()249 const char16_t *ConstChar16Ptr::get() const { return u_.cp; }
250
251 #endif
252 /// \endcond
253
254 /**
255 * Converts from const char16_t * to const UChar *.
256 * Includes an aliasing barrier if available.
257 * @param p pointer
258 * @return p as const UChar *
259 * @stable ICU 59
260 */
toUCharPtr(const char16_t * p)261 inline const UChar *toUCharPtr(const char16_t *p) {
262 #ifdef U_ALIASING_BARRIER
263 U_ALIASING_BARRIER(p);
264 #endif
265 return reinterpret_cast<const UChar *>(p);
266 }
267
268 /**
269 * Converts from char16_t * to UChar *.
270 * Includes an aliasing barrier if available.
271 * @param p pointer
272 * @return p as UChar *
273 * @stable ICU 59
274 */
toUCharPtr(char16_t * p)275 inline UChar *toUCharPtr(char16_t *p) {
276 #ifdef U_ALIASING_BARRIER
277 U_ALIASING_BARRIER(p);
278 #endif
279 return reinterpret_cast<UChar *>(p);
280 }
281
282 /**
283 * Converts from const char16_t * to const OldUChar *.
284 * Includes an aliasing barrier if available.
285 * @param p pointer
286 * @return p as const OldUChar *
287 * @stable ICU 59
288 */
toOldUCharPtr(const char16_t * p)289 inline const OldUChar *toOldUCharPtr(const char16_t *p) {
290 #ifdef U_ALIASING_BARRIER
291 U_ALIASING_BARRIER(p);
292 #endif
293 return reinterpret_cast<const OldUChar *>(p);
294 }
295
296 /**
297 * Converts from char16_t * to OldUChar *.
298 * Includes an aliasing barrier if available.
299 * @param p pointer
300 * @return p as OldUChar *
301 * @stable ICU 59
302 */
toOldUCharPtr(char16_t * p)303 inline OldUChar *toOldUCharPtr(char16_t *p) {
304 #ifdef U_ALIASING_BARRIER
305 U_ALIASING_BARRIER(p);
306 #endif
307 return reinterpret_cast<OldUChar *>(p);
308 }
309
310 #ifndef U_FORCE_HIDE_INTERNAL_API
311 /**
312 * Is T convertible to a std::u16string_view or some other 16-bit string view?
313 * @internal
314 */
315 template<typename T>
316 constexpr bool ConvertibleToU16StringView =
317 std::is_convertible_v<T, std::u16string_view>
318 #if !U_CHAR16_IS_TYPEDEF && (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION < 180000)
319 || std::is_convertible_v<T, std::basic_string_view<uint16_t>>
320 #endif
321 #if U_SIZEOF_WCHAR_T==2
322 || std::is_convertible_v<T, std::wstring_view>
323 #endif
324 ;
325
326 namespace internal {
327 /**
328 * Pass-through overload.
329 * @internal
330 */
toU16StringView(std::u16string_view sv)331 inline std::u16string_view toU16StringView(std::u16string_view sv) { return sv; }
332
333 #if !U_CHAR16_IS_TYPEDEF && (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION < 180000)
334 /**
335 * Basically undefined behavior but sometimes necessary conversion
336 * from std::basic_string_view<uint16_t> to std::u16string_view.
337 * @internal
338 */
toU16StringView(std::basic_string_view<uint16_t> sv)339 inline std::u16string_view toU16StringView(std::basic_string_view<uint16_t> sv) {
340 return { ConstChar16Ptr(sv.data()), sv.length() };
341 }
342 #endif
343
344 #if U_SIZEOF_WCHAR_T==2
345 /**
346 * Basically undefined behavior but sometimes necessary conversion
347 * from std::wstring_view to std::u16string_view.
348 * @internal
349 */
toU16StringView(std::wstring_view sv)350 inline std::u16string_view toU16StringView(std::wstring_view sv) {
351 return { ConstChar16Ptr(sv.data()), sv.length() };
352 }
353 #endif
354
355 /**
356 * Pass-through overload.
357 * @internal
358 */
359 template <typename T,
360 typename = typename std::enable_if_t<!std::is_pointer_v<std::remove_reference_t<T>>>>
toU16StringViewNullable(const T & text)361 inline std::u16string_view toU16StringViewNullable(const T& text) {
362 return toU16StringView(text);
363 }
364
365 /**
366 * In case of nullptr, return an empty view.
367 * @internal
368 */
369 template <typename T,
370 typename = typename std::enable_if_t<std::is_pointer_v<std::remove_reference_t<T>>>,
371 typename = void>
toU16StringViewNullable(const T & text)372 inline std::u16string_view toU16StringViewNullable(const T& text) {
373 if (text == nullptr) return {}; // For backward compatibility.
374 return toU16StringView(text);
375 }
376
377 } // internal
378 #endif // U_FORCE_HIDE_INTERNAL_API
379
380 U_NAMESPACE_END
381
382 #endif /* LIBANDROIDICU_U_SHOW_CPLUSPLUS_API */
383
384 #endif // __CHAR16PTR_H__
385