39 #include "hb-mutex-private.hh" |
39 #include "hb-mutex-private.hh" |
40 |
40 |
41 |
41 |
42 /* reference_count */ |
42 /* reference_count */ |
43 |
43 |
44 #define HB_REFERENCE_COUNT_INERT_VALUE -1 |
44 #define HB_REFERENCE_COUNT_INERT_VALUE 0 |
45 #define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD |
45 #define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD |
46 #define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE)} |
46 #define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT (HB_REFERENCE_COUNT_INERT_VALUE)} |
47 |
47 |
48 struct hb_reference_count_t |
48 struct hb_reference_count_t |
49 { |
49 { |
50 hb_atomic_int_t ref_count; |
50 hb_atomic_int_t ref_count; |
51 |
51 |
52 inline void init (int v) { ref_count.set_unsafe (v); } |
52 inline void init (int v) { ref_count.set_unsafe (v); } |
53 inline int get_unsafe (void) const { return ref_count.get_unsafe (); } |
53 inline int get_unsafe (void) const { return ref_count.get_unsafe (); } |
54 inline int inc (void) { return ref_count.inc (); } |
54 inline int inc (void) { return ref_count.inc (); } |
55 inline int dec (void) { return ref_count.dec (); } |
55 inline int dec (void) { return ref_count.dec (); } |
56 inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); } |
56 inline void fini (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); } |
57 |
57 |
58 inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; } |
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; } |
59 inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; } |
60 }; |
60 }; |
61 |
61 |
62 |
62 |
63 /* user_data */ |
63 /* user_data */ |
64 |
64 |
65 #define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT} |
|
66 struct hb_user_data_array_t |
65 struct hb_user_data_array_t |
67 { |
66 { |
68 struct hb_user_data_item_t { |
67 struct hb_user_data_item_t { |
69 hb_user_data_key_t *key; |
68 hb_user_data_key_t *key; |
70 void *data; |
69 void *data; |
71 hb_destroy_func_t destroy; |
70 hb_destroy_func_t destroy; |
72 |
71 |
73 inline bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; } |
72 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; } |
73 inline bool operator == (hb_user_data_item_t &other) const { return key == other.key; } |
75 |
74 |
76 void finish (void) { if (destroy) destroy (data); } |
75 void fini (void) { if (destroy) destroy (data); } |
77 }; |
76 }; |
78 |
77 |
79 hb_mutex_t lock; |
78 hb_mutex_t lock; |
80 hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items; |
79 hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items; |
81 |
80 |
86 hb_destroy_func_t destroy, |
85 hb_destroy_func_t destroy, |
87 hb_bool_t replace); |
86 hb_bool_t replace); |
88 |
87 |
89 HB_INTERNAL void *get (hb_user_data_key_t *key); |
88 HB_INTERNAL void *get (hb_user_data_key_t *key); |
90 |
89 |
91 inline void finish (void) { items.finish (lock); lock.finish (); } |
90 inline void fini (void) { items.fini (lock); lock.fini (); } |
92 }; |
91 }; |
93 |
92 |
94 |
93 |
95 /* object_header */ |
94 /* object_header */ |
96 |
95 |
97 struct hb_object_header_t |
96 struct hb_object_header_t |
98 { |
97 { |
99 hb_reference_count_t ref_count; |
98 hb_reference_count_t ref_count; |
100 hb_user_data_array_t user_data; |
99 hb_user_data_array_t *user_data; |
101 |
100 |
102 #define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_USER_DATA_ARRAY_INIT} |
101 #define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, nullptr} |
103 |
102 |
104 private: |
103 private: |
105 ASSERT_POD (); |
104 ASSERT_POD (); |
106 }; |
105 }; |
107 |
106 |
131 } |
130 } |
132 template <typename Type> |
131 template <typename Type> |
133 static inline void hb_object_init (Type *obj) |
132 static inline void hb_object_init (Type *obj) |
134 { |
133 { |
135 obj->header.ref_count.init (1); |
134 obj->header.ref_count.init (1); |
136 obj->header.user_data.init (); |
135 obj->header.user_data = nullptr; |
137 } |
136 } |
138 template <typename Type> |
137 template <typename Type> |
139 static inline bool hb_object_is_inert (const Type *obj) |
138 static inline bool hb_object_is_inert (const Type *obj) |
140 { |
139 { |
141 return unlikely (obj->header.ref_count.is_inert ()); |
140 return unlikely (obj->header.ref_count.is_inert ()); |
163 return false; |
162 return false; |
164 assert (hb_object_is_valid (obj)); |
163 assert (hb_object_is_valid (obj)); |
165 if (obj->header.ref_count.dec () != 1) |
164 if (obj->header.ref_count.dec () != 1) |
166 return false; |
165 return false; |
167 |
166 |
168 obj->header.ref_count.finish (); /* Do this before user_data */ |
167 hb_object_fini (obj); |
169 obj->header.user_data.finish (); |
|
170 return true; |
168 return true; |
|
169 } |
|
170 template <typename Type> |
|
171 static inline void hb_object_fini (Type *obj) |
|
172 { |
|
173 obj->header.ref_count.fini (); /* Do this before user_data */ |
|
174 if (obj->header.user_data) |
|
175 { |
|
176 obj->header.user_data->fini (); |
|
177 free (obj->header.user_data); |
|
178 } |
171 } |
179 } |
172 template <typename Type> |
180 template <typename Type> |
173 static inline bool hb_object_set_user_data (Type *obj, |
181 static inline bool hb_object_set_user_data (Type *obj, |
174 hb_user_data_key_t *key, |
182 hb_user_data_key_t *key, |
175 void * data, |
183 void * data, |
177 hb_bool_t replace) |
185 hb_bool_t replace) |
178 { |
186 { |
179 if (unlikely (!obj || hb_object_is_inert (obj))) |
187 if (unlikely (!obj || hb_object_is_inert (obj))) |
180 return false; |
188 return false; |
181 assert (hb_object_is_valid (obj)); |
189 assert (hb_object_is_valid (obj)); |
182 return obj->header.user_data.set (key, data, destroy, replace); |
190 |
|
191 retry: |
|
192 hb_user_data_array_t *user_data = (hb_user_data_array_t *) hb_atomic_ptr_get (&obj->header.user_data); |
|
193 if (unlikely (!user_data)) |
|
194 { |
|
195 user_data = (hb_user_data_array_t *) calloc (sizeof (hb_user_data_array_t), 1); |
|
196 if (unlikely (!user_data)) |
|
197 return false; |
|
198 user_data->init (); |
|
199 if (unlikely (!hb_atomic_ptr_cmpexch (&obj->header.user_data, nullptr, user_data))) |
|
200 { |
|
201 user_data->fini (); |
|
202 free (user_data); |
|
203 goto retry; |
|
204 } |
|
205 } |
|
206 |
|
207 return user_data->set (key, data, destroy, replace); |
183 } |
208 } |
184 |
209 |
185 template <typename Type> |
210 template <typename Type> |
186 static inline void *hb_object_get_user_data (Type *obj, |
211 static inline void *hb_object_get_user_data (Type *obj, |
187 hb_user_data_key_t *key) |
212 hb_user_data_key_t *key) |
188 { |
213 { |
189 if (unlikely (!obj || hb_object_is_inert (obj))) |
214 if (unlikely (!obj || hb_object_is_inert (obj) || !obj->header.user_data)) |
190 return nullptr; |
215 return nullptr; |
191 assert (hb_object_is_valid (obj)); |
216 assert (hb_object_is_valid (obj)); |
192 return obj->header.user_data.get (key); |
217 return obj->header.user_data->get (key); |
193 } |
218 } |
194 |
219 |
195 |
220 |
196 #endif /* HB_OBJECT_PRIVATE_HH */ |
221 #endif /* HB_OBJECT_PRIVATE_HH */ |