1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 // This file is available under and governed by the GNU General Public 26 // License version 2 only, as published by the Free Software Foundation. 27 // However, the following notice accompanied the original version of this 28 // file: 29 // 30 /* 31 * Copyright © 2007 Chris Wilson 32 * Copyright © 2009,2010 Red Hat, Inc. 33 * Copyright © 2011,2012 Google, Inc. 34 * 35 * This is part of HarfBuzz, a text shaping library. 36 * 37 * Permission is hereby granted, without written agreement and without 38 * license or royalty fees, to use, copy, modify, and distribute this 39 * software and its documentation for any purpose, provided that the 40 * above copyright notice and the following two paragraphs appear in 41 * all copies of this software. 42 * 43 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 44 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 45 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 46 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 47 * DAMAGE. 48 * 49 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 50 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 51 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 52 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 53 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 54 * 55 * Contributor(s): 56 * Chris Wilson <chris@chris-wilson.co.uk> 57 * Red Hat Author(s): Behdad Esfahbod 58 * Google Author(s): Behdad Esfahbod 59 */ 60 61 #ifndef HB_OBJECT_PRIVATE_HH 62 #define HB_OBJECT_PRIVATE_HH 63 64 #include "hb-private.hh" 65 66 #include "hb-atomic-private.hh" 67 #include "hb-mutex-private.hh" 68 69 70 /* Debug */ 71 72 #ifndef HB_DEBUG_OBJECT 73 #define HB_DEBUG_OBJECT (HB_DEBUG+0) 74 #endif 75 76 77 /* reference_count */ 78 79 #define HB_REFERENCE_COUNT_INERT_VALUE -1 80 #define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD 81 #define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE)} 82 83 struct hb_reference_count_t 84 { 85 hb_atomic_int_t ref_count; 86 87 inline void init (int v) { ref_count.set_unsafe (v); } 88 inline int get_unsafe (void) const { return ref_count.get_unsafe (); } 89 inline int inc (void) { return ref_count.inc (); } 90 inline int dec (void) { return ref_count.dec (); } 91 inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); } 92 93 inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; } 94 inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; } 95 }; 96 97 98 /* user_data */ 99 100 #define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT} 101 struct hb_user_data_array_t 102 { 103 struct hb_user_data_item_t { 104 hb_user_data_key_t *key; 105 void *data; 106 hb_destroy_func_t destroy; 107 108 inline bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; } 109 inline bool operator == (hb_user_data_item_t &other) const { return key == other.key; } 110 111 void finish (void) { if (destroy) destroy (data); } 112 }; 113 114 hb_mutex_t lock; 115 hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items; 116 117 inline void init (void) { lock.init (); items.init (); } 118 119 HB_INTERNAL bool set (hb_user_data_key_t *key, 120 void * data, 121 hb_destroy_func_t destroy, 122 hb_bool_t replace); 123 124 HB_INTERNAL void *get (hb_user_data_key_t *key); 125 126 inline void finish (void) { items.finish (lock); lock.finish (); } 127 }; 128 129 130 /* object_header */ 131 132 struct hb_object_header_t 133 { 134 hb_reference_count_t ref_count; 135 hb_user_data_array_t user_data; 136 137 #define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_USER_DATA_ARRAY_INIT} 138 139 private: 140 ASSERT_POD (); 141 }; 142 143 144 /* object */ 145 146 template <typename Type> 147 static inline void hb_object_trace (const Type *obj, const char *function) 148 { 149 DEBUG_MSG (OBJECT, (void *) obj, 150 "%s refcount=%d", 151 function, 152 obj ? obj->header.ref_count.get_unsafe () : 0); 153 } 154 155 template <typename Type> 156 static inline Type *hb_object_create (void) 157 { 158 Type *obj = (Type *) calloc (1, sizeof (Type)); 159 160 if (unlikely (!obj)) 161 return obj; 162 163 hb_object_init (obj); 164 hb_object_trace (obj, HB_FUNC); 165 return obj; 166 } 167 template <typename Type> 168 static inline void hb_object_init (Type *obj) 169 { 170 obj->header.ref_count.init (1); 171 obj->header.user_data.init (); 172 } 173 template <typename Type> 174 static inline bool hb_object_is_inert (const Type *obj) 175 { 176 return unlikely (obj->header.ref_count.is_inert ()); 177 } 178 template <typename Type> 179 static inline bool hb_object_is_valid (const Type *obj) 180 { 181 return likely (obj->header.ref_count.is_valid ()); 182 } 183 template <typename Type> 184 static inline Type *hb_object_reference (Type *obj) 185 { 186 hb_object_trace (obj, HB_FUNC); 187 if (unlikely (!obj || hb_object_is_inert (obj))) 188 return obj; 189 assert (hb_object_is_valid (obj)); 190 obj->header.ref_count.inc (); 191 return obj; 192 } 193 template <typename Type> 194 static inline bool hb_object_destroy (Type *obj) 195 { 196 hb_object_trace (obj, HB_FUNC); 197 if (unlikely (!obj || hb_object_is_inert (obj))) 198 return false; 199 assert (hb_object_is_valid (obj)); 200 if (obj->header.ref_count.dec () != 1) 201 return false; 202 203 obj->header.ref_count.finish (); /* Do this before user_data */ 204 obj->header.user_data.finish (); 205 return true; 206 } 207 template <typename Type> 208 static inline bool hb_object_set_user_data (Type *obj, 209 hb_user_data_key_t *key, 210 void * data, 211 hb_destroy_func_t destroy, 212 hb_bool_t replace) 213 { 214 if (unlikely (!obj || hb_object_is_inert (obj))) 215 return false; 216 assert (hb_object_is_valid (obj)); 217 return obj->header.user_data.set (key, data, destroy, replace); 218 } 219 220 template <typename Type> 221 static inline void *hb_object_get_user_data (Type *obj, 222 hb_user_data_key_t *key) 223 { 224 if (unlikely (!obj || hb_object_is_inert (obj))) 225 return NULL; 226 assert (hb_object_is_valid (obj)); 227 return obj->header.user_data.get (key); 228 } 229 230 231 #endif /* HB_OBJECT_PRIVATE_HH */