hb-object-private.hh revision 29c67d3f70b081766a6c01353980f457f38aeb12
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 37HB_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 49HB_END_DECLS 50 51 52template <typename Type, unsigned int StaticSize> 53struct 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 108template <typename Type> 109struct hb_array_t : hb_static_array_t<Type, 2> {}; 110 111 112template <typename Key, typename Value> 113struct 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 174HB_BEGIN_DECLS 175 176typedef 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 183struct 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 208typedef struct _hb_object_header_t hb_object_header_t; 209 210struct _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 274HB_END_DECLS 275 276template <typename Type> 277static inline void hb_object_trace (const Type *obj, const char *function) 278{ 279 obj->header.trace (function); 280} 281template <typename Type> 282static 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} 288template <typename Type> 289static inline bool hb_object_is_inert (const Type *obj) 290{ 291 return unlikely (obj->header.is_inert()); 292} 293template <typename Type> 294static inline Type *hb_object_reference (Type *obj) 295{ 296 hb_object_trace (obj, HB_FUNC); 297 obj->header.reference (); 298 return obj; 299} 300template <typename Type> 301static inline bool hb_object_destroy (Type *obj) 302{ 303 hb_object_trace (obj, HB_FUNC); 304 return obj->header.destroy (); 305} 306 307 308HB_BEGIN_DECLS 309 310 311HB_END_DECLS 312 313#endif /* HB_OBJECT_PRIVATE_HH */ 314