Add initial implementation of user_data to objects
[profile/ivi/org.tizen.video-player.git] / src / hb-object-private.hh
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 HB_BEGIN_DECLS
38
39
40 /* Debug */
41
42 #ifndef HB_DEBUG_OBJECT
43 #define HB_DEBUG_OBJECT (HB_DEBUG+0)
44 #endif
45
46
47 /* user_data */
48
49 HB_END_DECLS
50
51
52 template <typename Type, unsigned int StaticSize>
53 struct hb_static_array_t {
54
55   unsigned int len;
56   unsigned int allocated;
57   Type *array;
58   Type static_array[StaticSize];
59
60   void finish (void) { for (unsigned i = 0; i < len; i++) array[i].finish (); }
61
62   inline Type& operator [] (unsigned int i)
63   {
64     return array[i];
65   }
66
67   inline Type *push (void)
68   {
69     if (!array) {
70       array = static_array;
71       allocated = ARRAY_LENGTH (static_array);
72     }
73     if (likely (len < allocated))
74       return &array[len++];
75     /* Need to reallocate */
76     unsigned int new_allocated = allocated + (allocated >> 1) + 8;
77     Type *new_array;
78     if (array == static_array) {
79       new_array = (Type *) calloc (new_allocated, sizeof (Type));
80       if (new_array) {
81         memcpy (new_array, array, len * sizeof (Type));
82         array = new_array;
83       }
84     } else {
85       bool overflows = new_allocated >= ((unsigned int) -1) / sizeof (Type);
86       if (unlikely (overflows))
87         new_array = NULL;
88       else
89         new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
90       if (new_array) {
91         free (array);
92         array = new_array;
93       }
94     }
95     if ((len < allocated))
96       return &array[len++];
97     else
98       return NULL;
99   }
100
101   inline void pop (void)
102   {
103     len--;
104     /* TODO: shrink array if needed */
105   }
106 };
107
108 template <typename Type>
109 struct hb_array_t : hb_static_array_t<Type, 2> {};
110
111
112 template <typename Key, typename Value>
113 struct hb_map_t
114 {
115   struct item_t {
116     Key key;
117     /* unsigned int hash; */
118     Value value;
119
120     void finish (void) { value.finish (); }
121   };
122
123   hb_array_t <item_t> items;
124
125   private:
126
127   inline item_t *find (Key key) {
128     if (unlikely (!key)) return NULL;
129     for (unsigned int i = 0; i < items.len; i++)
130       if (key == items[i].key)
131         return &items[i];
132     return NULL;
133   }
134
135   public:
136
137   inline bool set (Key   key,
138                    Value &value)
139   {
140     if (unlikely (!key)) return NULL;
141     item_t *item;
142     item = find (key);
143     if (item)
144       item->finish ();
145     else
146       item = items.push ();
147     if (unlikely (!item)) return false;
148     item->key = key;
149     item->value = value;
150     return true;
151   }
152
153   inline void unset (Key &key)
154   {
155     item_t *item;
156     item = find (key);
157     if (!item) return;
158
159     item->finish ();
160     items[items.len - 1] = *item;
161     items.pop ();
162   }
163
164   inline Value *get (Key key)
165   {
166     item_t *item = find (key);
167     return item ? &item->value : NULL;
168   }
169
170   void finish (void) { items.finish (); }
171 };
172
173
174 HB_BEGIN_DECLS
175
176 typedef struct {
177   void *data;
178   hb_destroy_func_t destroy;
179
180   void finish (void) { if (destroy) destroy (data); }
181 } hb_user_data_t;
182
183 struct hb_user_data_array_t {
184
185   hb_map_t<hb_user_data_key_t *, hb_user_data_t> map;
186
187   inline bool set (hb_user_data_key_t *key,
188                    void *              data,
189                    hb_destroy_func_t   destroy)
190   {
191     if (!data && !destroy) {
192       map.unset (key);
193       return true;
194     }
195     hb_user_data_t user_data = {data, destroy};
196     return map.set (key, user_data);
197   }
198
199   inline void *get (hb_user_data_key_t *key) {
200     return map.get (key);
201   }
202
203   void finish (void) { map.finish (); }
204 };
205
206
207
208 typedef struct _hb_object_header_t hb_object_header_t;
209
210 struct _hb_object_header_t {
211   hb_reference_count_t ref_count;
212   hb_user_data_array_t user_data;
213
214 #define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID}
215
216   static inline void *create (unsigned int size) {
217     hb_object_header_t *obj = (hb_object_header_t *) calloc (1, size);
218
219     if (likely (obj))
220       obj->init ();
221
222     return obj;
223   }
224
225   inline void init (void) {
226     ref_count.init (1);
227   }
228
229   inline bool is_inert (void) const {
230     return unlikely (ref_count.is_invalid ());
231   }
232
233   inline void reference (void) {
234     if (unlikely (!this || this->is_inert ()))
235       return;
236     ref_count.inc ();
237   }
238
239   inline bool destroy (void) {
240     if (unlikely (!this || this->is_inert ()))
241       return false;
242     if (ref_count.dec () != 1)
243       return false;
244
245     user_data.finish ();
246
247     return true;
248   }
249
250   inline bool set_user_data (hb_user_data_key_t *key,
251                              void *              data,
252                              hb_destroy_func_t   destroy) {
253     if (unlikely (!this || this->is_inert ()))
254       return false;
255
256     return user_data.set (key, data, destroy);
257   }
258
259   inline void *get_user_data (hb_user_data_key_t *key) {
260     return user_data.get (key);
261   }
262
263   inline void trace (const char *function) const {
264     (void) (HB_DEBUG_OBJECT &&
265             fprintf (stderr, "OBJECT(%p) refcount=%d %s\n",
266                      this,
267                      this ? ref_count.get () : 0,
268                      function));
269   }
270
271 };
272
273
274 HB_END_DECLS
275
276 template <typename Type>
277 static inline void hb_object_trace (const Type *obj, const char *function)
278 {
279   obj->header.trace (function);
280 }
281 template <typename Type>
282 static inline Type *hb_object_create ()
283 {
284   Type *obj = (Type *) hb_object_header_t::create (sizeof (Type));
285   hb_object_trace (obj, HB_FUNC);
286   return obj;
287 }
288 template <typename Type>
289 static inline bool hb_object_is_inert (const Type *obj)
290 {
291   return unlikely (obj->header.is_inert());
292 }
293 template <typename Type>
294 static inline Type *hb_object_reference (Type *obj)
295 {
296   hb_object_trace (obj, HB_FUNC);
297   obj->header.reference ();
298   return obj;
299 }
300 template <typename Type>
301 static inline bool hb_object_destroy (Type *obj)
302 {
303   hb_object_trace (obj, HB_FUNC);
304   return obj->header.destroy ();
305 }
306
307
308 HB_BEGIN_DECLS
309
310
311 HB_END_DECLS
312
313 #endif /* HB_OBJECT_PRIVATE_HH */