1 : /*
2 : * Copyright © 2007 Chris Wilson
3 : * Copyright © 2009,2010 Red Hat, Inc.
4 : * Copyright © 2011 Google, Inc.
5 : *
6 : * This is part of HarfBuzz, a text shaping library.
7 : *
8 : * Permission is hereby granted, without written agreement and without
9 : * license or royalty fees, to use, copy, modify, and distribute this
10 : * software and its documentation for any purpose, provided that the
11 : * above copyright notice and the following two paragraphs appear in
12 : * all copies of this software.
13 : *
14 : * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15 : * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16 : * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17 : * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 : * DAMAGE.
19 : *
20 : * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21 : * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 : * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
23 : * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24 : * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 : *
26 : * Contributor(s):
27 : * Chris Wilson <chris@chris-wilson.co.uk>
28 : * Red Hat Author(s): Behdad Esfahbod
29 : * Google Author(s): Behdad Esfahbod
30 : */
31 :
32 : #ifndef HB_OBJECT_PRIVATE_HH
33 : #define HB_OBJECT_PRIVATE_HH
34 :
35 : #include "hb-private.hh"
36 :
37 : #include "hb-mutex-private.hh"
38 :
39 :
40 :
41 : /* Debug */
42 :
43 : #ifndef HB_DEBUG_OBJECT
44 : #define HB_DEBUG_OBJECT (HB_DEBUG+0)
45 : #endif
46 :
47 :
48 : /* atomic_int */
49 :
50 : /* We need external help for these */
51 :
52 : #ifdef HAVE_GLIB
53 :
54 : #include <glib.h>
55 :
56 : typedef volatile int hb_atomic_int_t;
57 : #if GLIB_CHECK_VERSION(2,29,5)
58 : #define hb_atomic_int_add(AI, V) g_atomic_int_add (&(AI), V)
59 : #else
60 : #define hb_atomic_int_add(AI, V) g_atomic_int_exchange_and_add (&(AI), V)
61 : #endif
62 : #define hb_atomic_int_get(AI) g_atomic_int_get (&(AI))
63 : #define hb_atomic_int_set(AI, V) g_atomic_int_set (&(AI), V)
64 :
65 :
66 : #elif defined(_MSC_VER) && _MSC_VER >= 1600
67 :
68 : #include <intrin.h>
69 :
70 : typedef long hb_atomic_int_t;
71 : #define hb_atomic_int_add(AI, V) _InterlockedExchangeAdd (&(AI), V)
72 : #define hb_atomic_int_get(AI) (_ReadBarrier (), (AI))
73 : #define hb_atomic_int_set(AI, V) ((void) _InterlockedExchange (&(AI), (V)))
74 :
75 :
76 : #else
77 :
78 : #ifdef _MSC_VER
79 : #pragma message("Could not find any system to define atomic_int macros, library will NOT be thread-safe")
80 : #else
81 : #warning "Could not find any system to define atomic_int macros, library will NOT be thread-safe"
82 : #endif
83 :
84 : typedef volatile int hb_atomic_int_t;
85 : #define hb_atomic_int_add(AI, V) ((AI) += (V), (AI) - (V))
86 : #define hb_atomic_int_get(AI) (AI)
87 : #define hb_atomic_int_set(AI, V) ((void) ((AI) = (V)))
88 :
89 :
90 : #endif
91 :
92 :
93 :
94 :
95 : /* reference_count */
96 :
97 : typedef struct {
98 : hb_atomic_int_t ref_count;
99 :
100 : #define HB_REFERENCE_COUNT_INVALID_VALUE ((hb_atomic_int_t) -1)
101 : #define HB_REFERENCE_COUNT_INVALID {HB_REFERENCE_COUNT_INVALID_VALUE}
102 :
103 0 : inline void init (int v) { ref_count = v; /* non-atomic is fine */ }
104 0 : inline int inc (void) { return hb_atomic_int_add (ref_count, 1); }
105 0 : inline int dec (void) { return hb_atomic_int_add (ref_count, -1); }
106 : inline void set (int v) { hb_atomic_int_set (ref_count, v); }
107 :
108 0 : inline int get (void) const { return hb_atomic_int_get (ref_count); }
109 0 : inline bool is_invalid (void) const { return get () == HB_REFERENCE_COUNT_INVALID_VALUE; }
110 :
111 : } hb_reference_count_t;
112 :
113 :
114 : /* user_data */
115 :
116 8784 : struct hb_user_data_array_t {
117 :
118 : struct hb_user_data_item_t {
119 : hb_user_data_key_t *key;
120 : void *data;
121 : hb_destroy_func_t destroy;
122 :
123 0 : inline bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; }
124 0 : inline bool operator == (hb_user_data_item_t &other) const { return key == other.key; }
125 :
126 0 : void finish (void) { if (destroy) destroy (data); }
127 : };
128 :
129 : hb_lockable_set_t<hb_user_data_item_t, hb_static_mutex_t> items;
130 :
131 : HB_INTERNAL bool set (hb_user_data_key_t *key,
132 : void * data,
133 : hb_destroy_func_t destroy,
134 : hb_bool_t replace);
135 :
136 : HB_INTERNAL void *get (hb_user_data_key_t *key);
137 :
138 : HB_INTERNAL void finish (void);
139 : };
140 :
141 :
142 : /* object_header */
143 :
144 : typedef struct _hb_object_header_t hb_object_header_t;
145 :
146 : struct _hb_object_header_t {
147 : hb_reference_count_t ref_count;
148 : hb_user_data_array_t user_data;
149 :
150 : #define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID}
151 :
152 0 : static inline void *create (unsigned int size) {
153 0 : hb_object_header_t *obj = (hb_object_header_t *) calloc (1, size);
154 :
155 0 : if (likely (obj))
156 0 : obj->init ();
157 :
158 0 : return obj;
159 : }
160 :
161 0 : inline void init (void) {
162 0 : ref_count.init (1);
163 0 : }
164 :
165 0 : inline bool is_inert (void) const {
166 0 : return unlikely (ref_count.is_invalid ());
167 : }
168 :
169 0 : inline void reference (void) {
170 0 : if (unlikely (!this || this->is_inert ()))
171 0 : return;
172 0 : ref_count.inc ();
173 : }
174 :
175 0 : inline bool destroy (void) {
176 0 : if (unlikely (!this || this->is_inert ()))
177 0 : return false;
178 0 : if (ref_count.dec () != 1)
179 0 : return false;
180 :
181 0 : ref_count.init (HB_REFERENCE_COUNT_INVALID_VALUE);
182 :
183 0 : user_data.finish ();
184 :
185 0 : return true;
186 : }
187 :
188 0 : inline bool set_user_data (hb_user_data_key_t *key,
189 : void * data,
190 : hb_destroy_func_t destroy_func,
191 : hb_bool_t replace) {
192 0 : if (unlikely (!this || this->is_inert ()))
193 0 : return false;
194 :
195 0 : return user_data.set (key, data, destroy_func, replace);
196 : }
197 :
198 0 : inline void *get_user_data (hb_user_data_key_t *key) {
199 0 : return user_data.get (key);
200 : }
201 :
202 0 : inline void trace (const char *function) const {
203 : DEBUG_MSG (OBJECT, (void *) this,
204 : "refcount=%d %s",
205 : this ? ref_count.get () : 0,
206 0 : function);
207 0 : }
208 :
209 : };
210 :
211 :
212 :
213 :
214 : /* object */
215 :
216 : template <typename Type>
217 0 : static inline void hb_object_trace (const Type *obj, const char *function)
218 : {
219 0 : obj->header.trace (function);
220 0 : }
221 : template <typename Type>
222 0 : static inline Type *hb_object_create (void)
223 : {
224 0 : Type *obj = (Type *) hb_object_header_t::create (sizeof (Type));
225 0 : hb_object_trace (obj, HB_FUNC);
226 0 : return obj;
227 : }
228 : template <typename Type>
229 0 : static inline bool hb_object_is_inert (const Type *obj)
230 : {
231 0 : return unlikely (obj->header.is_inert ());
232 : }
233 : template <typename Type>
234 0 : static inline Type *hb_object_reference (Type *obj)
235 : {
236 0 : hb_object_trace (obj, HB_FUNC);
237 0 : obj->header.reference ();
238 0 : return obj;
239 : }
240 : template <typename Type>
241 0 : static inline bool hb_object_destroy (Type *obj)
242 : {
243 0 : hb_object_trace (obj, HB_FUNC);
244 0 : return obj->header.destroy ();
245 : }
246 : template <typename Type>
247 0 : static inline bool hb_object_set_user_data (Type *obj,
248 : hb_user_data_key_t *key,
249 : void * data,
250 : hb_destroy_func_t destroy,
251 : hb_bool_t replace)
252 : {
253 0 : return obj->header.set_user_data (key, data, destroy, replace);
254 : }
255 :
256 : template <typename Type>
257 0 : static inline void *hb_object_get_user_data (Type *obj,
258 : hb_user_data_key_t *key)
259 : {
260 0 : return obj->header.get_user_data (key);
261 : }
262 :
263 :
264 :
265 :
266 :
267 : #endif /* HB_OBJECT_PRIVATE_HH */
|