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