hb-object-private.hh revision 852e08ec8fbfbce1d50e571d0bb0b52ef4d4cc58
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/* reference_count */ 48 49typedef struct { 50 hb_atomic_int_t ref_count; 51 52#define HB_REFERENCE_COUNT_INVALID_VALUE ((hb_atomic_int_t) -1) 53#define HB_REFERENCE_COUNT_INVALID {HB_REFERENCE_COUNT_INVALID_VALUE} 54 55 inline void init (int v) { ref_count = v; /* non-atomic is fine */ } 56 inline int inc (void) { return hb_atomic_int_fetch_and_add (ref_count, 1); } 57 inline int dec (void) { return hb_atomic_int_fetch_and_add (ref_count, -1); } 58 inline void set (int v) { hb_atomic_int_set (ref_count, v); } 59 60 inline int get (void) const { return hb_atomic_int_get (ref_count); } 61 inline bool is_invalid (void) const { return get () == HB_REFERENCE_COUNT_INVALID_VALUE; } 62 63} hb_reference_count_t; 64 65 66/* user_data */ 67 68/* XXX make this thread-safe, somehow! */ 69 70typedef struct { 71 void *data; 72 hb_destroy_func_t destroy; 73 74 void finish (void) { if (destroy) destroy (data); } 75} hb_user_data_t; 76 77struct hb_user_data_array_t { 78 79 hb_map_t<hb_user_data_key_t *, hb_user_data_t> map; 80 81 inline bool set (hb_user_data_key_t *key, 82 void * data, 83 hb_destroy_func_t destroy) 84 { 85 if (!data && !destroy) { 86 map.unset (key); 87 return true; 88 } 89 hb_user_data_t user_data = {data, destroy}; 90 return map.set (key, user_data); 91 } 92 93 inline void *get (hb_user_data_key_t *key) { 94 return map.get (key); 95 } 96 97 void finish (void) { map.finish (); } 98}; 99 100 101/* object_header */ 102 103typedef struct _hb_object_header_t hb_object_header_t; 104 105struct _hb_object_header_t { 106 hb_reference_count_t ref_count; 107 hb_user_data_array_t user_data; 108 109#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID} 110 111 static inline void *create (unsigned int size) { 112 hb_object_header_t *obj = (hb_object_header_t *) calloc (1, size); 113 114 if (likely (obj)) 115 obj->init (); 116 117 return obj; 118 } 119 120 inline void init (void) { 121 ref_count.init (1); 122 } 123 124 inline bool is_inert (void) const { 125 return unlikely (ref_count.is_invalid ()); 126 } 127 128 inline void reference (void) { 129 if (unlikely (!this || this->is_inert ())) 130 return; 131 ref_count.inc (); 132 } 133 134 inline bool destroy (void) { 135 if (unlikely (!this || this->is_inert ())) 136 return false; 137 if (ref_count.dec () != 1) 138 return false; 139 140 user_data.finish (); 141 142 return true; 143 } 144 145 inline bool set_user_data (hb_user_data_key_t *key, 146 void * data, 147 hb_destroy_func_t destroy) { 148 if (unlikely (!this || this->is_inert ())) 149 return false; 150 151 return user_data.set (key, data, destroy); 152 } 153 154 inline void *get_user_data (hb_user_data_key_t *key) { 155 return user_data.get (key); 156 } 157 158 inline void trace (const char *function) const { 159 (void) (HB_DEBUG_OBJECT && 160 fprintf (stderr, "OBJECT(%p) refcount=%d %s\n", 161 this, 162 this ? ref_count.get () : 0, 163 function)); 164 } 165 166}; 167 168 169HB_END_DECLS 170 171 172/* object */ 173 174template <typename Type> 175static inline void hb_object_trace (const Type *obj, const char *function) 176{ 177 obj->header.trace (function); 178} 179template <typename Type> 180static inline Type *hb_object_create () 181{ 182 Type *obj = (Type *) hb_object_header_t::create (sizeof (Type)); 183 hb_object_trace (obj, HB_FUNC); 184 return obj; 185} 186template <typename Type> 187static inline bool hb_object_is_inert (const Type *obj) 188{ 189 return unlikely (obj->header.is_inert()); 190} 191template <typename Type> 192static inline Type *hb_object_reference (Type *obj) 193{ 194 hb_object_trace (obj, HB_FUNC); 195 obj->header.reference (); 196 return obj; 197} 198template <typename Type> 199static inline bool hb_object_destroy (Type *obj) 200{ 201 hb_object_trace (obj, HB_FUNC); 202 return obj->header.destroy (); 203} 204template <typename Type> 205static inline bool hb_object_set_user_data (Type *obj, 206 hb_user_data_key_t *key, 207 void * data, 208 hb_destroy_func_t destroy) 209{ 210 return obj->header.set_user_data (key, data, destroy); 211} 212 213template <typename Type> 214static inline void *hb_object_get_user_data (Type *obj, 215 hb_user_data_key_t *key) 216{ 217 return obj->header.get_user_data (key); 218} 219 220 221HB_BEGIN_DECLS 222 223 224HB_END_DECLS 225 226#endif /* HB_OBJECT_PRIVATE_HH */ 227