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 <cstddef>
11 #include "unicode/utypes.h"
12 
13 /**
14  * \file
15  * \brief C++ API: char16_t pointer wrappers with
16  *        implicit conversion from bit-compatible raw pointer types.
17  *        Also conversion functions from char16_t * to UChar * and OldUChar *.
18  */
19 
20 U_NAMESPACE_BEGIN
21 
22 /**
23  * \def U_ALIASING_BARRIER
24  * Barrier for pointer anti-aliasing optimizations even across function boundaries.
25  * @internal
26  */
27 #ifdef U_ALIASING_BARRIER
28     // Use the predefined value.
29 #elif (defined(__clang__) || defined(__GNUC__)) && U_PLATFORM != U_PF_BROWSER_NATIVE_CLIENT
30 #   define U_ALIASING_BARRIER(ptr) asm volatile("" : : "rm"(ptr) : "memory")
31 #elif defined(U_IN_DOXYGEN)
32 #   define U_ALIASING_BARRIER(ptr)
33 #endif
34 
35 /**
36  * char16_t * wrapper with implicit conversion from distinct but bit-compatible pointer types.
37  * @stable ICU 59
38  */
39 class U_COMMON_API Char16Ptr U_FINAL {
40 public:
41     /**
42      * Copies the pointer.
43      * @param p pointer
44      * @stable ICU 59
45      */
46     inline Char16Ptr(char16_t *p);
47 #if !U_CHAR16_IS_TYPEDEF
48     /**
49      * Converts the pointer to char16_t *.
50      * @param p pointer to be converted
51      * @stable ICU 59
52      */
53     inline Char16Ptr(uint16_t *p);
54 #endif
55 #if U_SIZEOF_WCHAR_T==2 || defined(U_IN_DOXYGEN)
56     /**
57      * Converts the pointer to char16_t *.
58      * (Only defined if U_SIZEOF_WCHAR_T==2.)
59      * @param p pointer to be converted
60      * @stable ICU 59
61      */
62     inline Char16Ptr(wchar_t *p);
63 #endif
64     /**
65      * nullptr constructor.
66      * @param p nullptr
67      * @stable ICU 59
68      */
69     inline Char16Ptr(std::nullptr_t p);
70     /**
71      * Destructor.
72      * @stable ICU 59
73      */
74     inline ~Char16Ptr();
75 
76     /**
77      * Pointer access.
78      * @return the wrapped pointer
79      * @stable ICU 59
80      */
81     inline char16_t *get() const;
82     /**
83      * char16_t pointer access via type conversion (e.g., static_cast).
84      * @return the wrapped pointer
85      * @stable ICU 59
86      */
87     inline operator char16_t *() const { return get(); }
88 
89 private:
90     Char16Ptr() = delete;
91 
92 #ifdef U_ALIASING_BARRIER
cast(T * t)93     template<typename T> static char16_t *cast(T *t) {
94         U_ALIASING_BARRIER(t);
95         return reinterpret_cast<char16_t *>(t);
96     }
97 
98     char16_t *p_;
99 #else
100     union {
101         char16_t *cp;
102         uint16_t *up;
103         wchar_t *wp;
104     } u_;
105 #endif
106 };
107 
108 /// \cond
109 #ifdef U_ALIASING_BARRIER
110 
Char16Ptr(char16_t * p)111 Char16Ptr::Char16Ptr(char16_t *p) : p_(p) {}
112 #if !U_CHAR16_IS_TYPEDEF
Char16Ptr(uint16_t * p)113 Char16Ptr::Char16Ptr(uint16_t *p) : p_(cast(p)) {}
114 #endif
115 #if U_SIZEOF_WCHAR_T==2
Char16Ptr(wchar_t * p)116 Char16Ptr::Char16Ptr(wchar_t *p) : p_(cast(p)) {}
117 #endif
Char16Ptr(std::nullptr_t p)118 Char16Ptr::Char16Ptr(std::nullptr_t p) : p_(p) {}
~Char16Ptr()119 Char16Ptr::~Char16Ptr() {
120     U_ALIASING_BARRIER(p_);
121 }
122 
get()123 char16_t *Char16Ptr::get() const { return p_; }
124 
125 #else
126 
Char16Ptr(char16_t * p)127 Char16Ptr::Char16Ptr(char16_t *p) { u_.cp = p; }
128 #if !U_CHAR16_IS_TYPEDEF
Char16Ptr(uint16_t * p)129 Char16Ptr::Char16Ptr(uint16_t *p) { u_.up = p; }
130 #endif
131 #if U_SIZEOF_WCHAR_T==2
Char16Ptr(wchar_t * p)132 Char16Ptr::Char16Ptr(wchar_t *p) { u_.wp = p; }
133 #endif
Char16Ptr(std::nullptr_t p)134 Char16Ptr::Char16Ptr(std::nullptr_t p) { u_.cp = p; }
~Char16Ptr()135 Char16Ptr::~Char16Ptr() {}
136 
get()137 char16_t *Char16Ptr::get() const { return u_.cp; }
138 
139 #endif
140 /// \endcond
141 
142 /**
143  * const char16_t * wrapper with implicit conversion from distinct but bit-compatible pointer types.
144  * @stable ICU 59
145  */
146 class U_COMMON_API ConstChar16Ptr U_FINAL {
147 public:
148     /**
149      * Copies the pointer.
150      * @param p pointer
151      * @stable ICU 59
152      */
153     inline ConstChar16Ptr(const char16_t *p);
154 #if !U_CHAR16_IS_TYPEDEF
155     /**
156      * Converts the pointer to char16_t *.
157      * @param p pointer to be converted
158      * @stable ICU 59
159      */
160     inline ConstChar16Ptr(const uint16_t *p);
161 #endif
162 #if U_SIZEOF_WCHAR_T==2 || defined(U_IN_DOXYGEN)
163     /**
164      * Converts the pointer to char16_t *.
165      * (Only defined if U_SIZEOF_WCHAR_T==2.)
166      * @param p pointer to be converted
167      * @stable ICU 59
168      */
169     inline ConstChar16Ptr(const wchar_t *p);
170 #endif
171     /**
172      * nullptr constructor.
173      * @param p nullptr
174      * @stable ICU 59
175      */
176     inline ConstChar16Ptr(const std::nullptr_t p);
177 
178     /**
179      * Destructor.
180      * @stable ICU 59
181      */
182     inline ~ConstChar16Ptr();
183 
184     /**
185      * Pointer access.
186      * @return the wrapped pointer
187      * @stable ICU 59
188      */
189     inline const char16_t *get() const;
190     /**
191      * char16_t pointer access via type conversion (e.g., static_cast).
192      * @return the wrapped pointer
193      * @stable ICU 59
194      */
195     inline operator const char16_t *() const { return get(); }
196 
197 private:
198     ConstChar16Ptr() = delete;
199 
200 #ifdef U_ALIASING_BARRIER
cast(const T * t)201     template<typename T> static const char16_t *cast(const T *t) {
202         U_ALIASING_BARRIER(t);
203         return reinterpret_cast<const char16_t *>(t);
204     }
205 
206     const char16_t *p_;
207 #else
208     union {
209         const char16_t *cp;
210         const uint16_t *up;
211         const wchar_t *wp;
212     } u_;
213 #endif
214 };
215 
216 /// \cond
217 #ifdef U_ALIASING_BARRIER
218 
ConstChar16Ptr(const char16_t * p)219 ConstChar16Ptr::ConstChar16Ptr(const char16_t *p) : p_(p) {}
220 #if !U_CHAR16_IS_TYPEDEF
ConstChar16Ptr(const uint16_t * p)221 ConstChar16Ptr::ConstChar16Ptr(const uint16_t *p) : p_(cast(p)) {}
222 #endif
223 #if U_SIZEOF_WCHAR_T==2
ConstChar16Ptr(const wchar_t * p)224 ConstChar16Ptr::ConstChar16Ptr(const wchar_t *p) : p_(cast(p)) {}
225 #endif
ConstChar16Ptr(const std::nullptr_t p)226 ConstChar16Ptr::ConstChar16Ptr(const std::nullptr_t p) : p_(p) {}
~ConstChar16Ptr()227 ConstChar16Ptr::~ConstChar16Ptr() {
228     U_ALIASING_BARRIER(p_);
229 }
230 
get()231 const char16_t *ConstChar16Ptr::get() const { return p_; }
232 
233 #else
234 
ConstChar16Ptr(const char16_t * p)235 ConstChar16Ptr::ConstChar16Ptr(const char16_t *p) { u_.cp = p; }
236 #if !U_CHAR16_IS_TYPEDEF
ConstChar16Ptr(const uint16_t * p)237 ConstChar16Ptr::ConstChar16Ptr(const uint16_t *p) { u_.up = p; }
238 #endif
239 #if U_SIZEOF_WCHAR_T==2
ConstChar16Ptr(const wchar_t * p)240 ConstChar16Ptr::ConstChar16Ptr(const wchar_t *p) { u_.wp = p; }
241 #endif
ConstChar16Ptr(const std::nullptr_t p)242 ConstChar16Ptr::ConstChar16Ptr(const std::nullptr_t p) { u_.cp = p; }
~ConstChar16Ptr()243 ConstChar16Ptr::~ConstChar16Ptr() {}
244 
get()245 const char16_t *ConstChar16Ptr::get() const { return u_.cp; }
246 
247 #endif
248 /// \endcond
249 
250 /**
251  * Converts from const char16_t * to const UChar *.
252  * Includes an aliasing barrier if available.
253  * @param p pointer
254  * @return p as const UChar *
255  * @stable ICU 59
256  */
toUCharPtr(const char16_t * p)257 inline const UChar *toUCharPtr(const char16_t *p) {
258 #ifdef U_ALIASING_BARRIER
259     U_ALIASING_BARRIER(p);
260 #endif
261     return reinterpret_cast<const UChar *>(p);
262 }
263 
264 /**
265  * Converts from char16_t * to UChar *.
266  * Includes an aliasing barrier if available.
267  * @param p pointer
268  * @return p as UChar *
269  * @stable ICU 59
270  */
toUCharPtr(char16_t * p)271 inline UChar *toUCharPtr(char16_t *p) {
272 #ifdef U_ALIASING_BARRIER
273     U_ALIASING_BARRIER(p);
274 #endif
275     return reinterpret_cast<UChar *>(p);
276 }
277 
278 /**
279  * Converts from const char16_t * to const OldUChar *.
280  * Includes an aliasing barrier if available.
281  * @param p pointer
282  * @return p as const OldUChar *
283  * @stable ICU 59
284  */
toOldUCharPtr(const char16_t * p)285 inline const OldUChar *toOldUCharPtr(const char16_t *p) {
286 #ifdef U_ALIASING_BARRIER
287     U_ALIASING_BARRIER(p);
288 #endif
289     return reinterpret_cast<const OldUChar *>(p);
290 }
291 
292 /**
293  * Converts from char16_t * to OldUChar *.
294  * Includes an aliasing barrier if available.
295  * @param p pointer
296  * @return p as OldUChar *
297  * @stable ICU 59
298  */
toOldUCharPtr(char16_t * p)299 inline OldUChar *toOldUCharPtr(char16_t *p) {
300 #ifdef U_ALIASING_BARRIER
301     U_ALIASING_BARRIER(p);
302 #endif
303     return reinterpret_cast<OldUChar *>(p);
304 }
305 
306 U_NAMESPACE_END
307 
308 #endif  // __CHAR16PTR_H__
309