Changeset View
Standalone View
src/lib/ecore/efl_boolean_model.c
1 | #ifdef HAVE_CONFIG_H | 1 | #ifdef HAVE_CONFIG_H | ||
---|---|---|---|---|---|
2 | # include <config.h> | 2 | # include <config.h> | ||
3 | #endif | 3 | #endif | ||
4 | 4 | | |||
5 | #include <Efl_Core.h> | 5 | #include <Efl_Core.h> | ||
6 | 6 | | |||
7 | #include "ecore_internal.h" | 7 | #include "ecore_internal.h" | ||
8 | 8 | | |||
9 | typedef struct _Efl_Boolean_Model_Data Efl_Boolean_Model_Data; | 9 | typedef struct _Efl_Boolean_Model_Data Efl_Boolean_Model_Data; | ||
10 | typedef struct _Efl_Boolean_Model_Value Efl_Boolean_Model_Value; | 10 | typedef struct _Efl_Boolean_Model_Value Efl_Boolean_Model_Value; | ||
11 | typedef struct _Efl_Boolean_Model_Storage_Range Efl_Boolean_Model_Storage_Range; | ||||
11 | 12 | | |||
12 | struct _Efl_Boolean_Model_Data | 13 | struct _Efl_Boolean_Model_Data | ||
13 | { | 14 | { | ||
14 | Efl_Boolean_Model_Data *parent; | 15 | Efl_Boolean_Model_Data *parent; | ||
15 | Eina_Hash *values; | 16 | Eina_Hash *values; | ||
16 | }; | 17 | }; | ||
17 | 18 | | |||
19 | struct _Efl_Boolean_Model_Storage_Range | ||||
20 | { | ||||
21 | EINA_RBTREE; | ||||
22 | | ||||
23 | unsigned int offset; | ||||
24 | uint16_t length; // Maximum length of the buffer will be 256, to avoid math error we rely on 16bits here. | ||||
bu5hm4n: uhm, this is 16 bit long, so it can have 0..2^16, so i think this comment about 256 is wrong? | |||||
25 | | ||||
26 | // We over allocate this buffer to have things fitting in one alloc | ||||
27 | unsigned char buffer[256]; | ||||
Not Done ReplyI think this buffer needs to be bigger ? bu5hm4n: I think this buffer needs to be bigger ? | |||||
Not Done ReplyNah the size is correct. Problem with 256, is that if you use a uchar to count, you will wrap in some case without a way to detect it (So for safety I switched to ushort). Will change the comment accordingly. cedric: Nah the size is correct. Problem with 256, is that if you use a uchar to count, you will wrap… | |||||
28 | }; | ||||
29 | | ||||
18 | struct _Efl_Boolean_Model_Value | 30 | struct _Efl_Boolean_Model_Value | ||
19 | { | 31 | { | ||
20 | Eina_Stringshare *property; | 32 | Eina_Stringshare *property; | ||
21 | 33 | | |||
22 | // This is not the best for supporting sparse bitfield with random insertion | 34 | Eina_Rbtree *buffers_root; | ||
23 | // but will do for now (Would be best to have a tree of fixed size array | 35 | Efl_Boolean_Model_Storage_Range *last; | ||
24 | // or something along that line). | | |||
25 | unsigned char *buffer; | | |||
26 | unsigned int buffer_count; | | |||
27 | 36 | | |||
28 | Eina_Bool default_value; | 37 | Eina_Bool default_value; | ||
29 | }; | 38 | }; | ||
30 | 39 | | |||
40 | static Eina_Rbtree_Direction | ||||
41 | _storage_range_cmp(const Efl_Boolean_Model_Storage_Range *left, | ||||
42 | const Efl_Boolean_Model_Storage_Range *right, | ||||
43 | void *data EINA_UNUSED) | ||||
44 | { | ||||
45 | // We should not have any overlapping range | ||||
46 | if (left->offset < right->offset) | ||||
47 | return EINA_RBTREE_LEFT; | ||||
48 | return EINA_RBTREE_RIGHT; | ||||
49 | } | ||||
50 | | ||||
51 | static int | ||||
52 | _storage_range_key(const Efl_Boolean_Model_Storage_Range *node, | ||||
53 | const unsigned int *key, int length EINA_UNUSED, void *data EINA_UNUSED) | ||||
54 | { | ||||
55 | if (node->offset > *key) return 1; | ||||
56 | if (node->offset + node->length < *key) return -1; | ||||
57 | // The key is in the range! | ||||
58 | return 0; | ||||
59 | } | ||||
60 | | ||||
61 | static void | ||||
62 | _storage_range_free(Eina_Rbtree *node, void *data EINA_UNUSED) | ||||
63 | { | ||||
64 | free(node); | ||||
65 | } | ||||
66 | | ||||
67 | static Efl_Boolean_Model_Storage_Range * | ||||
68 | _storage_lookup(Efl_Boolean_Model_Data *pd, | ||||
69 | const char *property, | ||||
70 | unsigned int index, | ||||
71 | Eina_Bool allocate, | ||||
72 | Eina_Bool value, | ||||
73 | Eina_Bool *found, | ||||
74 | Eina_Bool *default_value) | ||||
75 | { | ||||
76 | Efl_Boolean_Model_Storage_Range *lookup; | ||||
77 | Efl_Boolean_Model_Value *v; | ||||
78 | Eina_Stringshare *s; | ||||
79 | | ||||
80 | // Check if this is requesting a defined boolean property | ||||
81 | // Property are defined and their value are stored on the parent BOOLEAN | ||||
82 | s = eina_stringshare_add(property); | ||||
83 | v = eina_hash_find(pd->parent->values, s); | ||||
84 | eina_stringshare_del(s); | ||||
85 | | ||||
86 | if (!v) return NULL; | ||||
87 | *found = EINA_TRUE; | ||||
88 | *default_value = !!v->default_value; | ||||
89 | | ||||
90 | lookup = (void*) eina_rbtree_inline_lookup(v->buffers_root, &index, sizeof (unsigned int), | ||||
91 | EINA_RBTREE_CMP_KEY_CB(_storage_range_key), NULL); | ||||
92 | if (lookup) return lookup; | ||||
93 | if (!allocate) return NULL; | ||||
94 | | ||||
95 | // The value is the same as the default value, why bother allocate | ||||
96 | if (*default_value == value) return NULL; | ||||
97 | | ||||
98 | // For simplicity we do not create a sparse array, every boolean potentially needed are allocated | ||||
99 | // FIXME: keep it a sparse allocated buffer and only allocate needed buffer on demand | ||||
100 | do | ||||
101 | { | ||||
102 | lookup = calloc(1, sizeof (Efl_Boolean_Model_Storage_Range)); | ||||
103 | if (!lookup) return NULL; | ||||
104 | | ||||
105 | lookup->offset = v->last ? v->last->offset + v->last->length + 1 : 0; | ||||
106 | lookup->length = sizeof (lookup->buffer) * 8; // Number of bits in the buffer | ||||
Not Done ReplyAre you sure about the & in the sizeof? bu5hm4n: Are you sure about the & in the sizeof? | |||||
Not Done ReplyI will double check that. I did make a few change along the way and it is indeed not clear this is correct. cedric: I will double check that. I did make a few change along the way and it is indeed not clear this… | |||||
107 | // Initialize the buffer to the right default value | ||||
108 | if (default_value) memset(&lookup->buffer[0], *default_value, sizeof (&lookup->buffer)); | ||||
Not Done ReplyI think this here is a problem, the default value is either 0 or 1 but memset does set things bytewise. bu5hm4n: I think this here is a problem, the default value is either 0 or 1 but memset does set things… | |||||
Not Done Replydefault_value is set via !! which force a full bytewise 0 and 1 to be set. cedric: default_value is set via !! which force a full bytewise 0 and 1 to be set. | |||||
Not Done ReplyOh, that is new black magic to me. bu5hm4n: Oh, that is new black magic to me. | |||||
109 | | ||||
110 | v->buffers_root = eina_rbtree_inline_insert(v->buffers_root, EINA_RBTREE_GET(lookup), | ||||
111 | EINA_RBTREE_CMP_NODE_CB(_storage_range_cmp), NULL); | ||||
112 | v->last = lookup; | ||||
113 | } | ||||
114 | while (v->last->offset + v->last->length < index); | ||||
115 | | ||||
116 | return lookup; | ||||
117 | } | ||||
118 | | ||||
31 | static Eina_Iterator * | 119 | static Eina_Iterator * | ||
32 | _efl_boolean_model_efl_model_properties_get(const Eo *obj, | 120 | _efl_boolean_model_efl_model_properties_get(const Eo *obj, | ||
33 | Efl_Boolean_Model_Data *pd) | 121 | Efl_Boolean_Model_Data *pd) | ||
34 | { | 122 | { | ||
35 | Eina_Iterator *properties = NULL; | 123 | Eina_Iterator *properties = NULL; | ||
36 | 124 | | |||
37 | if (pd->parent) | 125 | if (pd->parent) | ||
38 | properties = eina_hash_iterator_key_new(pd->parent->values); | 126 | properties = eina_hash_iterator_key_new(pd->parent->values); | ||
39 | EFL_COMPOSITE_MODEL_PROPERTIES_SUPER(props, | 127 | EFL_COMPOSITE_MODEL_PROPERTIES_SUPER(props, | ||
40 | obj, EFL_BOOLEAN_MODEL_CLASS, | 128 | obj, EFL_BOOLEAN_MODEL_CLASS, | ||
41 | properties); | 129 | properties); | ||
42 | return props; | 130 | return props; | ||
43 | } | 131 | } | ||
44 | 132 | | |||
45 | static Eina_Value * | 133 | static Eina_Value * | ||
46 | _efl_boolean_model_efl_model_property_get(const Eo *obj, | 134 | _efl_boolean_model_efl_model_property_get(const Eo *obj, | ||
47 | Efl_Boolean_Model_Data *pd, | 135 | Efl_Boolean_Model_Data *pd, | ||
48 | const char *property) | 136 | const char *property) | ||
49 | { | 137 | { | ||
50 | Efl_Boolean_Model_Value *v; | 138 | Efl_Boolean_Model_Storage_Range *sr; | ||
51 | Eina_Stringshare *s; | | |||
52 | Eina_Bool flag; | 139 | Eina_Bool flag; | ||
53 | unsigned int index; | 140 | unsigned int index; | ||
141 | unsigned int offset; | ||||
142 | Eina_Bool found = EINA_FALSE; | ||||
143 | Eina_Bool default_value = EINA_FALSE; | ||||
54 | 144 | | |||
55 | if (property == NULL) return NULL; | 145 | if (property == NULL) return NULL; | ||
56 | 146 | | |||
57 | // If we do not have a parent set that his a BOOLEAN, then we should just forward up the call | 147 | // If we do not have a parent set that his a BOOLEAN, then we should just forward up the call | ||
58 | if (!pd->parent) | 148 | if (!pd->parent) | ||
59 | return efl_model_property_get(efl_super(obj, EFL_BOOLEAN_MODEL_CLASS), property); | 149 | return efl_model_property_get(efl_super(obj, EFL_BOOLEAN_MODEL_CLASS), property); | ||
60 | 150 | | |||
61 | // Check if this is requesting a defined boolean property | 151 | index = efl_composite_model_index_get(obj); | ||
62 | // Property are defined and their value are stored on the parent BOOLEAN | | |||
63 | s = eina_stringshare_add(property); | | |||
64 | v = eina_hash_find(pd->parent->values, s); | | |||
65 | eina_stringshare_del(s); | | |||
66 | 152 | | |||
67 | if (!v) // Not a property handle by this object, forward | 153 | | ||
154 | sr = _storage_lookup(pd, property, index, EINA_FALSE, EINA_FALSE, &found, &default_value); | ||||
155 | if (!found) // Not a property handle by this object, forward | ||||
68 | return efl_model_property_get(efl_super(obj, EFL_BOOLEAN_MODEL_CLASS), property); | 156 | return efl_model_property_get(efl_super(obj, EFL_BOOLEAN_MODEL_CLASS), property); | ||
69 | 157 | | |||
70 | index = efl_composite_model_index_get(obj); | 158 | if (!sr) // Not found in storage, should be the default value | ||
159 | return eina_value_bool_new(default_value); | ||||
71 | 160 | | |||
72 | // As an optimization we do optimistically allocate the boolean array | 161 | // Calculate the matching offset for the requested index | ||
73 | // Better would be to have a sparse boolean array | 162 | offset = index - sr->offset; | ||
74 | if ((index >> 3) >= v->buffer_count) | 163 | | ||
75 | flag = v->default_value; | 164 | flag = sr->buffer[offset >> 3] & (((unsigned char)1) << (offset & 0x7)); | ||
76 | else | | |||
77 | flag = v->buffer[index >> 3] & (((unsigned char)1) << (index & 0x7)); | | |||
78 | 165 | | |||
79 | return eina_value_bool_new(!!flag); | 166 | return eina_value_bool_new(!!flag); | ||
80 | } | 167 | } | ||
81 | 168 | | |||
82 | static Eina_Future * | 169 | static Eina_Future * | ||
83 | _efl_boolean_model_efl_model_property_set(Eo *obj, | 170 | _efl_boolean_model_efl_model_property_set(Eo *obj, | ||
84 | Efl_Boolean_Model_Data *pd, | 171 | Efl_Boolean_Model_Data *pd, | ||
85 | const char *property, Eina_Value *value) | 172 | const char *property, Eina_Value *value) | ||
86 | { | 173 | { | ||
87 | Efl_Boolean_Model_Value *v; | 174 | Efl_Boolean_Model_Storage_Range *sr; | ||
88 | Eina_Stringshare *s; | | |||
89 | Eina_Bool flag; | | |||
90 | unsigned int index; | 175 | unsigned int index; | ||
176 | unsigned int offset; | ||||
177 | Eina_Bool flag = EINA_FALSE; | ||||
178 | Eina_Bool found = EINA_FALSE; | ||||
179 | Eina_Bool convert_fail = EINA_FALSE; | ||||
180 | Eina_Bool default_value = EINA_FALSE; | ||||
91 | 181 | | |||
92 | if (!property) | 182 | if (!property) return efl_loop_future_rejected(obj, EFL_MODEL_ERROR_UNKNOWN); | ||
93 | return efl_loop_future_rejected(obj, | | |||
94 | EFL_MODEL_ERROR_UNKNOWN); | | |||
95 | 183 | | |||
96 | // If we do not have a parent set that his a BOOLEAN, then we should just forward up the call | 184 | // If we do not have a parent set that his a BOOLEAN, then we should just forward up the call | ||
97 | if (!pd->parent) | 185 | if (!pd->parent) | ||
98 | return efl_model_property_set(efl_super(obj, EFL_BOOLEAN_MODEL_CLASS), | 186 | return efl_model_property_set(efl_super(obj, EFL_BOOLEAN_MODEL_CLASS), | ||
99 | property, value); | 187 | property, value); | ||
100 | 188 | | |||
101 | // Check if this is requesting a defined boolean property | 189 | index = efl_composite_model_index_get(obj); | ||
102 | // Property are defined and their value are stored on the parent BOOLEAN | 190 | if (!eina_value_bool_convert(value, &flag)) | ||
103 | s = eina_stringshare_add(property); | 191 | convert_fail = EINA_TRUE; | ||
104 | v = eina_hash_find(pd->parent->values, s); | | |||
105 | eina_stringshare_del(s); | | |||
106 | 192 | | |||
107 | if (!v) | 193 | sr = _storage_lookup(pd, property, index, EINA_TRUE, flag, &found, &default_value); | ||
194 | if (!found) | ||||
108 | return efl_model_property_set(efl_super(obj, EFL_BOOLEAN_MODEL_CLASS), | 195 | return efl_model_property_set(efl_super(obj, EFL_BOOLEAN_MODEL_CLASS), | ||
109 | property, value); | 196 | property, value); | ||
110 | 197 | | |||
111 | if (!eina_value_bool_convert(value, &flag)) | 198 | // Convert did fail and we actually should have a valid Boolean to put in the buffer | ||
199 | if (convert_fail) | ||||
112 | return efl_loop_future_rejected(obj, EFL_MODEL_ERROR_UNKNOWN); | 200 | return efl_loop_future_rejected(obj, EFL_MODEL_ERROR_UNKNOWN); | ||
113 | 201 | | |||
114 | index = efl_composite_model_index_get(obj); | 202 | if (!sr) | ||
203 | return efl_loop_future_resolved(obj, eina_value_bool_init(default_value)); | ||||
115 | 204 | | |||
116 | // We are optimistically allocating the boolean buffer now. | 205 | // Calculate the matching offset for the requested index | ||
117 | // Aligning it on 64bits | 206 | offset = index - sr->offset; | ||
118 | if (v->buffer_count < (((index) >> 3) | 0x7) + 1) | | |||
119 | { | | |||
120 | unsigned int rcount = (((index | 0xF) >> 3) | 0x7) + 1; | | |||
121 | unsigned char *tmp; | | |||
122 | | ||||
123 | tmp = realloc(v->buffer, rcount); | | |||
124 | if (!tmp) return efl_loop_future_rejected(obj, ENOMEM); | | |||
125 | v->buffer = tmp; | | |||
126 | memset(v->buffer + v->buffer_count, 0, rcount - v->buffer_count); | | |||
127 | v->buffer_count = rcount; | | |||
128 | } | | |||
129 | 207 | | |||
130 | // It is assumed that during slice get the buffer is properly sized | 208 | // It is assumed that during slice get the buffer is properly sized | ||
131 | if (flag) | 209 | if (flag) | ||
132 | v->buffer[index >> 3] |= ((unsigned char)1) << (index & 0x7); | 210 | sr->buffer[offset >> 3] |= ((unsigned char)1) << (offset & 0x7); | ||
133 | else | 211 | else | ||
134 | v->buffer[index >> 3] &= ~(((unsigned char)1) << (index & 0x7)); | 212 | sr->buffer[offset >> 3] &= ~(((unsigned char)1) << (offset & 0x7)); | ||
135 | 213 | | |||
136 | // Calling "properties,changed" event | 214 | // Calling "properties,changed" event | ||
137 | efl_model_properties_changed(obj, property); | 215 | efl_model_properties_changed(obj, property); | ||
138 | 216 | | |||
139 | // Return fulfilled future | 217 | // Return fulfilled future | ||
140 | return efl_loop_future_resolved(obj, eina_value_bool_init(!!flag)); | 218 | return efl_loop_future_resolved(obj, eina_value_bool_init(!!flag)); | ||
141 | } | 219 | } | ||
142 | 220 | | |||
143 | static void | 221 | static void | ||
144 | _boolean_value_free(void *data) | 222 | _boolean_value_free(void *data) | ||
145 | { | 223 | { | ||
146 | Efl_Boolean_Model_Value *value = data; | 224 | Efl_Boolean_Model_Value *value = data; | ||
147 | 225 | | |||
148 | eina_stringshare_del(value->property); | 226 | eina_stringshare_del(value->property); | ||
149 | value->property = NULL; | 227 | value->property = NULL; | ||
150 | 228 | | |||
151 | free(value->buffer); | 229 | eina_rbtree_delete(value->buffers_root, _storage_range_free, NULL); | ||
152 | value->buffer = NULL; | 230 | value->last = NULL; | ||
153 | value->buffer_count = 0; | | |||
154 | 231 | | |||
155 | free(value); | 232 | free(value); | ||
156 | } | 233 | } | ||
157 | 234 | | |||
235 | static void | ||||
236 | _mark_greater(Efl_Boolean_Model_Storage_Range *root, Eina_Array *mark, const unsigned int upper) | ||||
237 | { | ||||
238 | if (!root) return ; | ||||
239 | | ||||
240 | if (root->offset > upper) | ||||
241 | { | ||||
242 | eina_array_push(mark, root); | ||||
243 | _mark_greater((void*) EINA_RBTREE_GET(root)->son[0], mark, upper); | ||||
244 | _mark_greater((void*) EINA_RBTREE_GET(root)->son[1], mark, upper); | ||||
245 | } | ||||
246 | else | ||||
247 | { | ||||
248 | _mark_greater((void*) EINA_RBTREE_GET(root)->son[0], mark, upper); | ||||
249 | } | ||||
250 | } | ||||
251 | | ||||
252 | static void | ||||
253 | _child_removed(void *data, const Efl_Event *event) | ||||
254 | { | ||||
255 | Efl_Boolean_Model_Data *pd = data; | ||||
256 | Efl_Model_Children_Event *ev = event->info; | ||||
257 | Efl_Boolean_Model_Value *v; | ||||
258 | Eina_Iterator *it; | ||||
259 | Eina_Array updated; | ||||
260 | | ||||
261 | if (!pd->parent) return; | ||||
262 | | ||||
263 | eina_array_step_set(&updated, sizeof (Eina_Array), 8); | ||||
264 | | ||||
265 | it = eina_hash_iterator_data_new(pd->parent->values); | ||||
266 | EINA_ITERATOR_FOREACH(it, v) | ||||
267 | { | ||||
268 | Efl_Boolean_Model_Storage_Range *lookup; | ||||
269 | Eina_Array_Iterator iterator; | ||||
270 | unsigned int i; | ||||
271 | | ||||
272 | // Remove the data from the buffer it belong to | ||||
273 | lookup = (void*) eina_rbtree_inline_lookup(v->buffers_root, &ev->index, sizeof (unsigned int), | ||||
274 | EINA_RBTREE_CMP_KEY_CB(_storage_range_key), NULL); | ||||
275 | if (lookup) | ||||
276 | { | ||||
277 | unsigned char lower_mask = (((unsigned char)1) << (ev->index & 0x7)) - 1; | ||||
278 | unsigned char upper_mask = (~(((unsigned char)1) << (ev->index & 0x7))) & (~lower_mask); | ||||
279 | unsigned char offset = (ev->index - lookup->offset) >> 3; | ||||
280 | uint16_t byte_length = lookup->length >> 3; | ||||
281 | | ||||
282 | // Manually shift all the byte in the buffer | ||||
283 | while (offset < byte_length) | ||||
284 | { | ||||
285 | lookup->buffer[offset] = (lookup->buffer[offset] & upper_mask) | | ||||
286 | ((lookup->buffer[offset] & lower_mask) << 1); | ||||
287 | if (offset + 1 < byte_length) | ||||
288 | lookup->buffer[offset] |= lookup->buffer[offset + 1] & 0x1; | ||||
289 | | ||||
290 | lower_mask = 0; | ||||
291 | upper_mask = 0xFE; | ||||
292 | offset++; | ||||
293 | } | ||||
294 | | ||||
295 | lookup->length--; | ||||
296 | if (lookup->length == 0) | ||||
297 | { | ||||
298 | v->buffers_root = eina_rbtree_inline_remove(v->buffers_root, EINA_RBTREE_GET(lookup), | ||||
299 | EINA_RBTREE_CMP_NODE_CB(_storage_range_cmp), NULL); | ||||
300 | free(lookup); | ||||
301 | | ||||
302 | if (lookup == v->last) | ||||
303 | { | ||||
304 | if (v->buffers_root) | ||||
305 | { | ||||
306 | unsigned int last_index = ev->index - 1; | ||||
307 | | ||||
308 | lookup = (void*) eina_rbtree_inline_lookup(v->buffers_root, &last_index, | ||||
309 | sizeof (unsigned int), | ||||
310 | EINA_RBTREE_CMP_KEY_CB(_storage_range_key), | ||||
311 | NULL); | ||||
312 | v->last = lookup; | ||||
313 | } | ||||
314 | else | ||||
315 | { | ||||
316 | // Nobody left | ||||
317 | v->last = NULL; | ||||
318 | } | ||||
319 | } | ||||
320 | } | ||||
321 | } | ||||
322 | | ||||
323 | _mark_greater((void*) v->buffers_root, &updated, ev->index); | ||||
324 | | ||||
325 | // Correct all the buffer after it | ||||
326 | // There is no need to remove and reinsert them as their relative order will not change. | ||||
327 | EINA_ARRAY_ITER_NEXT(&updated, i, lookup, iterator) | ||||
328 | { | ||||
329 | lookup->offset--; | ||||
330 | } | ||||
331 | | ||||
332 | eina_array_clean(&updated); | ||||
333 | } | ||||
334 | eina_iterator_free(it); | ||||
335 | | ||||
336 | eina_array_flush(&updated); | ||||
337 | } | ||||
338 | | ||||
158 | static Eo * | 339 | static Eo * | ||
159 | _efl_boolean_model_efl_object_constructor(Eo *obj, Efl_Boolean_Model_Data *pd) | 340 | _efl_boolean_model_efl_object_constructor(Eo *obj, Efl_Boolean_Model_Data *pd) | ||
160 | { | 341 | { | ||
161 | Eo *parent; | 342 | Eo *parent; | ||
162 | obj = efl_constructor(efl_super(obj, EFL_BOOLEAN_MODEL_CLASS)); | 343 | obj = efl_constructor(efl_super(obj, EFL_BOOLEAN_MODEL_CLASS)); | ||
163 | 344 | | |||
164 | if (!obj) return NULL; | 345 | if (!obj) return NULL; | ||
165 | 346 | | |||
166 | pd->values = eina_hash_stringshared_new(_boolean_value_free); | 347 | pd->values = eina_hash_stringshared_new(_boolean_value_free); | ||
167 | // Only add a reference to the parent if it is actually a BOOLEAN_MODEL_CLASS | 348 | // Only add a reference to the parent if it is actually a BOOLEAN_MODEL_CLASS | ||
168 | // The root typically doesn't have any boolean property, only its child do | 349 | // The root typically doesn't have any boolean property, only its child do | ||
169 | parent = efl_parent_get(obj); | 350 | parent = efl_parent_get(obj); | ||
170 | if (efl_isa(parent, EFL_BOOLEAN_MODEL_CLASS)) | 351 | if (efl_isa(parent, EFL_BOOLEAN_MODEL_CLASS)) | ||
171 | pd->parent = efl_data_scope_get(parent, EFL_BOOLEAN_MODEL_CLASS); | 352 | pd->parent = efl_data_scope_get(parent, EFL_BOOLEAN_MODEL_CLASS); | ||
172 | 353 | | |||
354 | efl_event_callback_add(obj, EFL_MODEL_EVENT_CHILD_REMOVED, _child_removed, pd); | ||||
355 | | ||||
173 | return obj; | 356 | return obj; | ||
174 | } | 357 | } | ||
175 | 358 | | |||
176 | static void | 359 | static void | ||
177 | _efl_boolean_model_efl_object_destructor(Eo *obj, Efl_Boolean_Model_Data *pd) | 360 | _efl_boolean_model_efl_object_destructor(Eo *obj, Efl_Boolean_Model_Data *pd) | ||
178 | { | 361 | { | ||
179 | eina_hash_free(pd->values); | 362 | eina_hash_free(pd->values); | ||
180 | 363 | | |||
Show All 34 Lines | |||||
215 | 398 | | |||
216 | struct _Eina_Iterator_Boolean | 399 | struct _Eina_Iterator_Boolean | ||
217 | { | 400 | { | ||
218 | Eina_Iterator iterator; | 401 | Eina_Iterator iterator; | ||
219 | 402 | | |||
220 | Eo *obj; | 403 | Eo *obj; | ||
221 | Efl_Boolean_Model_Data *pd; | 404 | Efl_Boolean_Model_Data *pd; | ||
222 | Efl_Boolean_Model_Value *v; | 405 | Efl_Boolean_Model_Value *v; | ||
406 | Efl_Boolean_Model_Storage_Range *sr; | ||||
407 | Eina_Iterator *infix; | ||||
223 | 408 | | |||
224 | uint64_t index; | 409 | uint64_t index; | ||
225 | uint64_t total; | 410 | uint64_t total; | ||
226 | 411 | | |||
227 | Eina_Bool request; | 412 | Eina_Bool request; | ||
228 | }; | 413 | }; | ||
229 | 414 | | |||
230 | static inline Eina_Bool | 415 | static Eina_Bool | ||
231 | _lookup_next_chunk(uint64_t *index, uint64_t total, | 416 | _efl_boolean_model_iterator_storage_index_find(Eina_Iterator_Boolean *it) | ||
232 | Efl_Boolean_Model_Value *v, unsigned char pattern) | | |||
233 | { | 417 | { | ||
234 | uint64_t upidx = *index >> 3; | 418 | uint16_t offset; | ||
419 | uint16_t byte_length; | ||||
235 | 420 | | |||
236 | while (upidx < v->buffer_count && | 421 | offset = it->index - it->sr->offset; | ||
237 | v->buffer[upidx] == pattern) | 422 | byte_length = it->sr->length >> 3; | ||
238 | upidx++; | | |||
239 | 423 | | |||
240 | *index = upidx << 3; | 424 | while (offset < it->sr->length) | ||
241 | if (upidx == v->buffer_count && | 425 | { | ||
242 | *index >= total) return EINA_FALSE; | 426 | uint64_t upidx; | ||
243 | return EINA_TRUE; | 427 | | ||
428 | upidx = offset >> 3; | ||||
429 | | ||||
430 | // Quickly dismiss byte that really do not match | ||||
431 | while (upidx < byte_length && | ||||
432 | it->sr->buffer[upidx] == (it->request ? 0x00 : 0xFF)) | ||||
433 | upidx++; | ||||
434 | | ||||
435 | // Make the indexes jump | ||||
436 | if (upidx != (offset >> 3)) | ||||
437 | { | ||||
438 | offset = upidx << 3; | ||||
439 | it->index = it->sr->offset + offset; | ||||
440 | } | ||||
441 | | ||||
442 | // Search inside the said byte | ||||
443 | while (((offset >> 3) == upidx) && | ||||
444 | (offset < it->sr->length)) | ||||
445 | { | ||||
446 | Eina_Bool flag = it->sr->buffer[offset >> 3] & | ||||
447 | (((unsigned char)1) << (offset & 0x7)); | ||||
448 | | ||||
449 | if (it->request == !!flag) | ||||
450 | return EINA_TRUE; | ||||
451 | | ||||
452 | it->index++; | ||||
453 | offset++; | ||||
454 | } | ||||
455 | } | ||||
456 | | ||||
457 | return EINA_FALSE; | ||||
244 | } | 458 | } | ||
245 | 459 | | |||
246 | static Eina_Bool | 460 | static Eina_Bool | ||
247 | efl_boolean_model_iterator_next(Eina_Iterator_Boolean *it, void **data) | 461 | _efl_boolean_model_iterator_index_find(Eina_Iterator_Boolean *it) | ||
248 | { | 462 | { | ||
249 | uint64_t upidx; | 463 | while (it->index < it->total) | ||
Not Done ReplyIsnt that wrong and we should only do that if the first bit is equal to request earlier on ? bu5hm4n: Isnt that wrong and we should only do that if the first bit is equal to request earlier on ? | |||||
Not Done ReplyYou are right the init case is not properly handle. Need to make sure that at least there is one first run being done before returning an index. cedric: You are right the init case is not properly handle. Need to make sure that at least there is… | |||||
250 | | ||||
251 | *data = &it->index; | | |||
252 | it->index++; | | |||
253 | | ||||
254 | retry: | | |||
255 | if (it->index >= it->total) return EINA_FALSE; | | |||
256 | if ((it->index >> 3) >= it->v->buffer_count) | | |||
257 | { | 464 | { | ||
258 | if (it->v->default_value != it->request) | 465 | // If we are not walking on an existing storage range, look for a new one | ||
259 | return EINA_FALSE; | 466 | if (!it->sr) | ||
260 | return EINA_TRUE; | 467 | { | ||
468 | if (!eina_iterator_next(it->infix, (void**) &it->sr)) | ||||
469 | { | ||||
Not Done ReplyI think all default values in the iterator have to be the same as we are walking the same boolean property type, why is this check here? bu5hm4n: I think all default values in the iterator have to be the same as we are walking the same… | |||||
Not Done ReplyYou can request an iterator on all value being TRUE or FALSE. As the default value can also be one or the other, we need to stop walking if the default value is not the same as the requested value for the iterator. cedric: You can request an iterator on all value being TRUE or FALSE. As the default value can also be… | |||||
470 | // All the rest of the data are not allocated and there value is still default | ||||
471 | if (it->v->default_value != it->request) | ||||
472 | return EINA_FALSE; | ||||
473 | return EINA_TRUE; | ||||
474 | } | ||||
475 | } | ||||
476 | | ||||
477 | if (_efl_boolean_model_iterator_storage_index_find(it)) | ||||
478 | return EINA_TRUE; | ||||
479 | | ||||
480 | // Nothing more to look at in this buffer | ||||
481 | it->sr = NULL; | ||||
261 | } | 482 | } | ||
262 | 483 | | |||
263 | upidx = it->index >> 3; | 484 | return EINA_FALSE; | ||
264 | while ((it->index >> 3) == upidx) | 485 | } | ||
265 | { | | |||
266 | Eina_Bool flag = it->v->buffer[it->index >> 3] & | | |||
267 | (((unsigned char)1) << (it->index & 0x7)); | | |||
268 | | ||||
269 | if (it->request == !!flag) | | |||
270 | break; | | |||
271 | | ||||
272 | it->index++; | | |||
273 | } | | |||
274 | 486 | | |||
275 | if ((it->index >> 3) != upidx) | 487 | static Eina_Bool | ||
276 | { | 488 | efl_boolean_model_iterator_next(Eina_Iterator_Boolean *it, void **data) | ||
277 | if (!_lookup_next_chunk(&it->index, it->total, it->v, it->request ? 0x00 : 0xFF)) | 489 | { | ||
278 | return EINA_FALSE; | 490 | *data = &it->index; | ||
279 | goto retry; | 491 | it->index++; | ||
280 | } | | |||
281 | 492 | | |||
282 | return EINA_TRUE; | 493 | return _efl_boolean_model_iterator_index_find(it); | ||
283 | } | 494 | } | ||
284 | 495 | | |||
285 | static Eo * | 496 | static Eo * | ||
286 | efl_boolean_model_iterator_get_container(Eina_Iterator_Boolean *it) | 497 | efl_boolean_model_iterator_get_container(Eina_Iterator_Boolean *it) | ||
287 | { | 498 | { | ||
288 | return it->obj; | 499 | return it->obj; | ||
289 | } | 500 | } | ||
290 | 501 | | |||
291 | static void | 502 | static void | ||
292 | efl_boolean_model_iterator_free(Eina_Iterator_Boolean *it) | 503 | efl_boolean_model_iterator_free(Eina_Iterator_Boolean *it) | ||
293 | { | 504 | { | ||
505 | eina_iterator_free(it->infix); | ||||
294 | efl_unref(it->obj); | 506 | efl_unref(it->obj); | ||
295 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_NONE); | 507 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_NONE); | ||
296 | free(it); | 508 | free(it); | ||
297 | } | 509 | } | ||
298 | 510 | | |||
299 | static Eina_Iterator * | 511 | static Eina_Iterator * | ||
300 | _efl_boolean_model_boolean_iterator_get(Eo *obj, Efl_Boolean_Model_Data *pd, const char *name, Eina_Bool request) | 512 | _efl_boolean_model_boolean_iterator_get(Eo *obj, Efl_Boolean_Model_Data *pd, const char *name, Eina_Bool request) | ||
301 | { | 513 | { | ||
302 | Eina_Iterator_Boolean *itb; | 514 | Eina_Iterator_Boolean *itb; | ||
303 | Efl_Boolean_Model_Value *v; | 515 | Efl_Boolean_Model_Value *v; | ||
304 | Eina_Stringshare *s; | 516 | Eina_Stringshare *s; | ||
305 | 517 | | |||
306 | s = eina_stringshare_add(name); | 518 | s = eina_stringshare_add(name); | ||
307 | v = eina_hash_find(pd->values, s); | 519 | v = eina_hash_find(pd->values, s); | ||
308 | eina_stringshare_del(s); | 520 | eina_stringshare_del(s); | ||
309 | if (!v) return NULL; | 521 | if (!v) return NULL; | ||
310 | 522 | | |||
311 | itb = calloc(1, sizeof (Eina_Iterator_Boolean)); | 523 | itb = calloc(1, sizeof (Eina_Iterator_Boolean)); | ||
312 | if (!itb) return NULL; | 524 | if (!itb) return NULL; | ||
313 | 525 | | |||
314 | itb->obj = efl_ref(obj); | 526 | itb->obj = efl_ref(obj); | ||
315 | itb->pd = pd; | 527 | itb->pd = pd; | ||
316 | itb->v = v; | 528 | itb->v = v; | ||
529 | itb->infix = eina_rbtree_iterator_infix(v->buffers_root); | ||||
530 | // Search the first index that do have the valid value | ||||
531 | _efl_boolean_model_iterator_index_find(itb); | ||||
317 | itb->index = 0; | 532 | itb->index = 0; | ||
318 | itb->total = efl_model_children_count_get(obj); | 533 | itb->total = efl_model_children_count_get(obj); | ||
319 | itb->request = !!request; | 534 | itb->request = !!request; | ||
320 | 535 | | |||
321 | itb->iterator.version = EINA_ITERATOR_VERSION; | 536 | itb->iterator.version = EINA_ITERATOR_VERSION; | ||
322 | itb->iterator.next = FUNC_ITERATOR_NEXT(efl_boolean_model_iterator_next); | 537 | itb->iterator.next = FUNC_ITERATOR_NEXT(efl_boolean_model_iterator_next); | ||
323 | itb->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(efl_boolean_model_iterator_get_container); | 538 | itb->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(efl_boolean_model_iterator_get_container); | ||
324 | itb->iterator.free = FUNC_ITERATOR_FREE(efl_boolean_model_iterator_free); | 539 | itb->iterator.free = FUNC_ITERATOR_FREE(efl_boolean_model_iterator_free); | ||
325 | 540 | | |||
326 | EINA_MAGIC_SET(&itb->iterator, EINA_MAGIC_ITERATOR); | 541 | EINA_MAGIC_SET(&itb->iterator, EINA_MAGIC_ITERATOR); | ||
327 | return &itb->iterator; | 542 | return &itb->iterator; | ||
328 | } | 543 | } | ||
329 | 544 | | |||
330 | 545 | | |||
331 | #include "efl_boolean_model.eo.c" | 546 | #include "efl_boolean_model.eo.c" |
uhm, this is 16 bit long, so it can have 0..2^16, so i think this comment about 256 is wrong?