1 | /* |
2 | * Copyright © 2007,2008,2009,2010 Red Hat, Inc. |
3 | * Copyright © 2012,2018 Google, Inc. |
4 | * |
5 | * This is part of HarfBuzz, a text shaping library. |
6 | * |
7 | * Permission is hereby granted, without written agreement and without |
8 | * license or royalty fees, to use, copy, modify, and distribute this |
9 | * software and its documentation for any purpose, provided that the |
10 | * above copyright notice and the following two paragraphs appear in |
11 | * all copies of this software. |
12 | * |
13 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
15 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
16 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
17 | * DAMAGE. |
18 | * |
19 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
22 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
23 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 | * |
25 | * Red Hat Author(s): Behdad Esfahbod |
26 | * Google Author(s): Behdad Esfahbod |
27 | */ |
28 | |
29 | #ifndef HB_MACHINERY_HH |
30 | #define HB_MACHINERY_HH |
31 | |
32 | #include "hb.hh" |
33 | #include "hb-blob.hh" |
34 | |
35 | #include "hb-dispatch.hh" |
36 | #include "hb-sanitize.hh" |
37 | #include "hb-serialize.hh" |
38 | |
39 | |
40 | /* |
41 | * Casts |
42 | */ |
43 | |
44 | /* Cast to struct T, reference to reference */ |
45 | template<typename Type, typename TObject> |
46 | static inline const Type& CastR(const TObject &X) |
47 | { return reinterpret_cast<const Type&> (X); } |
48 | template<typename Type, typename TObject> |
49 | static inline Type& CastR(TObject &X) |
50 | { return reinterpret_cast<Type&> (X); } |
51 | |
52 | /* Cast to struct T, pointer to pointer */ |
53 | template<typename Type, typename TObject> |
54 | static inline const Type* CastP(const TObject *X) |
55 | { return reinterpret_cast<const Type*> (X); } |
56 | template<typename Type, typename TObject> |
57 | static inline Type* CastP(TObject *X) |
58 | { return reinterpret_cast<Type*> (X); } |
59 | |
60 | /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory |
61 | * location pointed to by P plus Ofs bytes. */ |
62 | template<typename Type> |
63 | static inline const Type& StructAtOffset(const void *P, unsigned int offset) |
64 | { return * reinterpret_cast<const Type*> ((const char *) P + offset); } |
65 | template<typename Type> |
66 | static inline Type& StructAtOffset(void *P, unsigned int offset) |
67 | { return * reinterpret_cast<Type*> ((char *) P + offset); } |
68 | template<typename Type> |
69 | static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset) |
70 | { |
71 | #pragma GCC diagnostic push |
72 | #pragma GCC diagnostic ignored "-Wcast-align" |
73 | return * reinterpret_cast<Type*> ((char *) P + offset); |
74 | #pragma GCC diagnostic pop |
75 | } |
76 | template<typename Type> |
77 | static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset) |
78 | { |
79 | #pragma GCC diagnostic push |
80 | #pragma GCC diagnostic ignored "-Wcast-align" |
81 | return * reinterpret_cast<Type*> ((char *) P + offset); |
82 | #pragma GCC diagnostic pop |
83 | } |
84 | |
85 | /* StructAfter<T>(X) returns the struct T& that is placed after X. |
86 | * Works with X of variable size also. X must implement get_size() */ |
87 | template<typename Type, typename TObject> |
88 | static inline const Type& StructAfter(const TObject &X) |
89 | { return StructAtOffset<Type>(&X, X.get_size()); } |
90 | template<typename Type, typename TObject> |
91 | static inline Type& StructAfter(TObject &X) |
92 | { return StructAtOffset<Type>(&X, X.get_size()); } |
93 | |
94 | |
95 | /* |
96 | * Size checking |
97 | */ |
98 | |
99 | /* Check _assertion in a method environment */ |
100 | #define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \ |
101 | void _instance_assertion_on_line_##_line () const \ |
102 | { static_assert ((_assertion), ""); } |
103 | # define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion) |
104 | # define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion) |
105 | |
106 | /* Check that _code compiles in a method environment */ |
107 | #define _DEFINE_COMPILES_ASSERTION1(_line, _code) \ |
108 | void _compiles_assertion_on_line_##_line () const \ |
109 | { _code; } |
110 | # define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code) |
111 | # define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code) |
112 | |
113 | |
114 | #define DEFINE_SIZE_STATIC(size) \ |
115 | DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)) \ |
116 | unsigned int get_size () const { return (size); } \ |
117 | static constexpr unsigned null_size = (size); \ |
118 | static constexpr unsigned min_size = (size); \ |
119 | static constexpr unsigned static_size = (size) |
120 | |
121 | #define DEFINE_SIZE_UNION(size, _member) \ |
122 | DEFINE_COMPILES_ASSERTION ((void) this->u._member.static_size) \ |
123 | DEFINE_INSTANCE_ASSERTION (sizeof(this->u._member) == (size)) \ |
124 | static constexpr unsigned null_size = (size); \ |
125 | static constexpr unsigned min_size = (size) |
126 | |
127 | #define DEFINE_SIZE_MIN(size) \ |
128 | DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \ |
129 | static constexpr unsigned null_size = (size); \ |
130 | static constexpr unsigned min_size = (size) |
131 | |
132 | #define DEFINE_SIZE_UNBOUNDED(size) \ |
133 | DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \ |
134 | static constexpr unsigned min_size = (size) |
135 | |
136 | #define DEFINE_SIZE_ARRAY(size, array) \ |
137 | DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \ |
138 | DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + HB_VAR_ARRAY * sizeof ((array)[0])) \ |
139 | static constexpr unsigned null_size = (size); \ |
140 | static constexpr unsigned min_size = (size) |
141 | |
142 | #define DEFINE_SIZE_ARRAY_SIZED(size, array) \ |
143 | unsigned int get_size () const { return (size - (array).min_size + (array).get_size ()); } \ |
144 | DEFINE_SIZE_ARRAY(size, array) |
145 | |
146 | |
147 | |
148 | /* |
149 | * Lazy loaders. |
150 | */ |
151 | |
152 | template <typename Data, unsigned int WheresData> |
153 | struct hb_data_wrapper_t |
154 | { |
155 | static_assert (WheresData > 0, "" ); |
156 | |
157 | Data * get_data () const |
158 | { return *(((Data **) (void *) this) - WheresData); } |
159 | |
160 | bool is_inert () const { return !get_data (); } |
161 | |
162 | template <typename Stored, typename Subclass> |
163 | Stored * call_create () const { return Subclass::create (get_data ()); } |
164 | }; |
165 | template <> |
166 | struct hb_data_wrapper_t<void, 0> |
167 | { |
168 | bool is_inert () const { return false; } |
169 | |
170 | template <typename Stored, typename Funcs> |
171 | Stored * call_create () const { return Funcs::create (); } |
172 | }; |
173 | |
174 | template <typename T1, typename T2> struct hb_non_void_t { typedef T1 value; }; |
175 | template <typename T2> struct hb_non_void_t<void, T2> { typedef T2 value; }; |
176 | |
177 | template <typename Returned, |
178 | typename Subclass = void, |
179 | typename Data = void, |
180 | unsigned int WheresData = 0, |
181 | typename Stored = Returned> |
182 | struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> |
183 | { |
184 | typedef typename hb_non_void_t<Subclass, |
185 | hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored> |
186 | >::value Funcs; |
187 | |
188 | void init0 () {} /* Init, when memory is already set to 0. No-op for us. */ |
189 | void init () { instance.set_relaxed (nullptr); } |
190 | void fini () { do_destroy (instance.get ()); } |
191 | |
192 | void free_instance () |
193 | { |
194 | retry: |
195 | Stored *p = instance.get (); |
196 | if (unlikely (p && !cmpexch (p, nullptr))) |
197 | goto retry; |
198 | do_destroy (p); |
199 | } |
200 | |
201 | static void do_destroy (Stored *p) |
202 | { |
203 | if (p && p != const_cast<Stored *> (Funcs::get_null ())) |
204 | Funcs::destroy (p); |
205 | } |
206 | |
207 | const Returned * operator -> () const { return get (); } |
208 | const Returned & operator * () const { return *get (); } |
209 | explicit operator bool () const |
210 | { return get_stored () != Funcs::get_null (); } |
211 | template <typename C> operator const C * () const { return get (); } |
212 | |
213 | Stored * get_stored () const |
214 | { |
215 | retry: |
216 | Stored *p = this->instance.get (); |
217 | if (unlikely (!p)) |
218 | { |
219 | if (unlikely (this->is_inert ())) |
220 | return const_cast<Stored *> (Funcs::get_null ()); |
221 | |
222 | p = this->template call_create<Stored, Funcs> (); |
223 | if (unlikely (!p)) |
224 | p = const_cast<Stored *> (Funcs::get_null ()); |
225 | |
226 | if (unlikely (!cmpexch (nullptr, p))) |
227 | { |
228 | do_destroy (p); |
229 | goto retry; |
230 | } |
231 | } |
232 | return p; |
233 | } |
234 | Stored * get_stored_relaxed () const |
235 | { |
236 | return this->instance.get_relaxed (); |
237 | } |
238 | |
239 | bool cmpexch (Stored *current, Stored *value) const |
240 | { |
241 | /* This *must* be called when there are no other threads accessing. */ |
242 | return this->instance.cmpexch (current, value); |
243 | } |
244 | |
245 | const Returned * get () const { return Funcs::convert (get_stored ()); } |
246 | const Returned * get_relaxed () const { return Funcs::convert (get_stored_relaxed ()); } |
247 | Returned * get_unconst () const { return const_cast<Returned *> (Funcs::convert (get_stored ())); } |
248 | |
249 | /* To be possibly overloaded by subclasses. */ |
250 | static Returned* convert (Stored *p) { return p; } |
251 | |
252 | /* By default null/init/fini the object. */ |
253 | static const Stored* get_null () { return &Null(Stored); } |
254 | static Stored *create (Data *data) |
255 | { |
256 | Stored *p = (Stored *) calloc (1, sizeof (Stored)); |
257 | if (likely (p)) |
258 | p->init (data); |
259 | return p; |
260 | } |
261 | static Stored *create () |
262 | { |
263 | Stored *p = (Stored *) calloc (1, sizeof (Stored)); |
264 | if (likely (p)) |
265 | p->init (); |
266 | return p; |
267 | } |
268 | static void destroy (Stored *p) |
269 | { |
270 | p->fini (); |
271 | free (p); |
272 | } |
273 | |
274 | // private: |
275 | /* Must only have one pointer. */ |
276 | hb_atomic_ptr_t<Stored *> instance; |
277 | }; |
278 | |
279 | /* Specializations. */ |
280 | |
281 | template <typename T, unsigned int WheresFace> |
282 | struct hb_face_lazy_loader_t : hb_lazy_loader_t<T, |
283 | hb_face_lazy_loader_t<T, WheresFace>, |
284 | hb_face_t, WheresFace> {}; |
285 | |
286 | template <typename T, unsigned int WheresFace> |
287 | struct hb_table_lazy_loader_t : hb_lazy_loader_t<T, |
288 | hb_table_lazy_loader_t<T, WheresFace>, |
289 | hb_face_t, WheresFace, |
290 | hb_blob_t> |
291 | { |
292 | static hb_blob_t *create (hb_face_t *face) |
293 | { return hb_sanitize_context_t ().reference_table<T> (face); } |
294 | static void destroy (hb_blob_t *p) { hb_blob_destroy (p); } |
295 | |
296 | static const hb_blob_t *get_null () |
297 | { return hb_blob_get_empty (); } |
298 | |
299 | static const T* convert (const hb_blob_t *blob) |
300 | { return blob->as<T> (); } |
301 | |
302 | hb_blob_t* get_blob () const { return this->get_stored (); } |
303 | }; |
304 | |
305 | template <typename Subclass> |
306 | struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<hb_font_funcs_t, Subclass> |
307 | { |
308 | static void destroy (hb_font_funcs_t *p) |
309 | { hb_font_funcs_destroy (p); } |
310 | static const hb_font_funcs_t *get_null () |
311 | { return hb_font_funcs_get_empty (); } |
312 | }; |
313 | template <typename Subclass> |
314 | struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unicode_funcs_t, Subclass> |
315 | { |
316 | static void destroy (hb_unicode_funcs_t *p) |
317 | { hb_unicode_funcs_destroy (p); } |
318 | static const hb_unicode_funcs_t *get_null () |
319 | { return hb_unicode_funcs_get_empty (); } |
320 | }; |
321 | |
322 | |
323 | #endif /* HB_MACHINERY_HH */ |
324 | |