1 | /* |
2 | * Copyright © 2007 Chris Wilson |
3 | * Copyright © 2009,2010 Red Hat, Inc. |
4 | * Copyright © 2011,2012 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 | #include "hb-debug.hh" |
37 | |
38 | #include "hb-atomic-private.hh" |
39 | #include "hb-mutex-private.hh" |
40 | |
41 | |
42 | /* reference_count */ |
43 | |
44 | #define HB_REFERENCE_COUNT_INERT_VALUE -1 |
45 | #define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD |
46 | #define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE)} |
47 | |
48 | struct hb_reference_count_t |
49 | { |
50 | hb_atomic_int_t ref_count; |
51 | |
52 | inline void init (int v) { ref_count.set_unsafe (v); } |
53 | inline int get_unsafe (void) const { return ref_count.get_unsafe (); } |
54 | inline int inc (void) { return ref_count.inc (); } |
55 | inline int dec (void) { return ref_count.dec (); } |
56 | inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); } |
57 | |
58 | inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; } |
59 | inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; } |
60 | }; |
61 | |
62 | |
63 | /* user_data */ |
64 | |
65 | #define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT} |
66 | struct hb_user_data_array_t |
67 | { |
68 | struct hb_user_data_item_t { |
69 | hb_user_data_key_t *key; |
70 | void *data; |
71 | hb_destroy_func_t destroy; |
72 | |
73 | inline bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; } |
74 | inline bool operator == (hb_user_data_item_t &other) const { return key == other.key; } |
75 | |
76 | void finish (void) { if (destroy) destroy (data); } |
77 | }; |
78 | |
79 | hb_mutex_t lock; |
80 | hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items; |
81 | |
82 | inline void init (void) { lock.init (); items.init (); } |
83 | |
84 | HB_INTERNAL bool set (hb_user_data_key_t *key, |
85 | void * data, |
86 | hb_destroy_func_t destroy, |
87 | hb_bool_t replace); |
88 | |
89 | HB_INTERNAL void *get (hb_user_data_key_t *key); |
90 | |
91 | inline void finish (void) { items.finish (l&: lock); lock.finish (); } |
92 | }; |
93 | |
94 | |
95 | /* object_header */ |
96 | |
97 | struct |
98 | { |
99 | hb_reference_count_t ; |
100 | hb_user_data_array_t ; |
101 | |
102 | #define {HB_REFERENCE_COUNT_INIT, HB_USER_DATA_ARRAY_INIT} |
103 | |
104 | private: |
105 | ASSERT_POD (); |
106 | }; |
107 | |
108 | |
109 | /* object */ |
110 | |
111 | template <typename Type> |
112 | static inline void hb_object_trace (const Type *obj, const char *function) |
113 | { |
114 | DEBUG_MSG (OBJECT, (void *) obj, |
115 | "%s refcount=%d" , |
116 | function, |
117 | obj ? obj->header.ref_count.get_unsafe () : 0); |
118 | } |
119 | |
120 | template <typename Type> |
121 | static inline Type *hb_object_create (void) |
122 | { |
123 | Type *obj = (Type *) calloc (nmemb: 1, size: sizeof (Type)); |
124 | |
125 | if (unlikely (!obj)) |
126 | return obj; |
127 | |
128 | hb_object_init (obj); |
129 | hb_object_trace (obj, HB_FUNC); |
130 | return obj; |
131 | } |
132 | template <typename Type> |
133 | static inline void hb_object_init (Type *obj) |
134 | { |
135 | obj->header.ref_count.init (1); |
136 | obj->header.user_data.init (); |
137 | } |
138 | template <typename Type> |
139 | static inline bool hb_object_is_inert (const Type *obj) |
140 | { |
141 | return unlikely (obj->header.ref_count.is_inert ()); |
142 | } |
143 | template <typename Type> |
144 | static inline bool hb_object_is_valid (const Type *obj) |
145 | { |
146 | return likely (obj->header.ref_count.is_valid ()); |
147 | } |
148 | template <typename Type> |
149 | static inline Type *hb_object_reference (Type *obj) |
150 | { |
151 | hb_object_trace (obj, HB_FUNC); |
152 | if (unlikely (!obj || hb_object_is_inert (obj))) |
153 | return obj; |
154 | assert (hb_object_is_valid (obj)); |
155 | obj->header.ref_count.inc (); |
156 | return obj; |
157 | } |
158 | template <typename Type> |
159 | static inline bool hb_object_destroy (Type *obj) |
160 | { |
161 | hb_object_trace (obj, HB_FUNC); |
162 | if (unlikely (!obj || hb_object_is_inert (obj))) |
163 | return false; |
164 | assert (hb_object_is_valid (obj)); |
165 | if (obj->header.ref_count.dec () != 1) |
166 | return false; |
167 | |
168 | obj->header.ref_count.finish (); /* Do this before user_data */ |
169 | obj->header.user_data.finish (); |
170 | return true; |
171 | } |
172 | template <typename Type> |
173 | static inline bool hb_object_set_user_data (Type *obj, |
174 | hb_user_data_key_t *key, |
175 | void * data, |
176 | hb_destroy_func_t destroy, |
177 | hb_bool_t replace) |
178 | { |
179 | if (unlikely (!obj || hb_object_is_inert (obj))) |
180 | return false; |
181 | assert (hb_object_is_valid (obj)); |
182 | return obj->header.user_data.set (key, data, destroy, replace); |
183 | } |
184 | |
185 | template <typename Type> |
186 | static inline void *hb_object_get_user_data (Type *obj, |
187 | hb_user_data_key_t *key) |
188 | { |
189 | if (unlikely (!obj || hb_object_is_inert (obj))) |
190 | return nullptr; |
191 | assert (hb_object_is_valid (obj)); |
192 | return obj->header.user_data.get (key); |
193 | } |
194 | |
195 | |
196 | #endif /* HB_OBJECT_PRIVATE_HH */ |
197 | |