summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <mail@marcel-hollerbach.de>2019-07-24 20:49:38 +0200
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2019-07-25 19:47:45 +0200
commit35c0b7d3b883a32acf6ce5a518012e27a750de78 (patch)
tree35625983ebd8f78afa74f83cf3bf76ba1154f308
parent5a3d659006c66c82617aafa544218f141d33d323 (diff)
efl_ui_item_container: speed up item lookup
the problem with accessor is that the normal eina accessor is only for immutable lists, by the time you change the list, the accessor has a problem and might crash. This would mean we have to recreate the accessors after every change to the internal list representation, which would invalidate the cache all the time. The usage of grid and list here is also very performant in cache using, all the usages normally iterate forward or backward, which makes this cache really helpfull. With this commit the lookup of sizes is improved a lot, because eina_list_nth is not used anymore. (Cuts of ~90ms in creation time) Differential Revision: https://phab.enlightenment.org/D9387
-rw-r--r--src/lib/elementary/efl_ui_item_container.c275
1 files changed, 138 insertions, 137 deletions
diff --git a/src/lib/elementary/efl_ui_item_container.c b/src/lib/elementary/efl_ui_item_container.c
index c7758ba8a9..e2a8a65b7d 100644
--- a/src/lib/elementary/efl_ui_item_container.c
+++ b/src/lib/elementary/efl_ui_item_container.c
@@ -12,102 +12,40 @@
12#include "elm_widget.h" 12#include "elm_widget.h"
13#include "elm_priv.h" 13#include "elm_priv.h"
14 14
15#define MY_CLASS EFL_UI_ITEM_CONTAINER_CLASS
16
17#define MY_DATA_GET(obj, pd) \
18 Efl_Ui_Item_Container_Data *pd = efl_data_scope_get(obj, MY_CLASS);
19
20typedef struct { 15typedef struct {
21 Efl_Ui_Scroll_Manager *smanager; 16 Eina_Accessor acc;
22 Efl_Ui_Pan *pan; 17 unsigned int last_index;
23 Eina_List *selected; 18 const Eina_List *current;
24 Eina_List *items; 19 Eina_List **items;
25 Efl_Ui_Select_Mode mode; 20} Fast_Accessor;
26 Efl_Ui_Layout_Orientation dir;
27 Eina_Size2D content_min_size;
28 Efl_Ui_Position_Manager_Entity *pos_man;
29 struct {
30 Eina_Accessor pass_on;
31 unsigned int last_index;
32 const Eina_List *current;
33 } obj_accessor;
34 struct {
35 Eina_Bool w;
36 Eina_Bool h;
37 } match_content;
38 Eina_Accessor size_accessor;
39 Efl_Gfx_Entity *sizer;
40} Efl_Ui_Item_Container_Data;
41
42static Eina_Bool register_item(Eo *obj, Efl_Ui_Item_Container_Data *pd, Efl_Ui_Item *item);
43static Eina_Bool unregister_item(Eo *obj, Efl_Ui_Item_Container_Data *pd, Efl_Ui_Item *item);
44
45static void
46flush_min_size(Eo *obj, Efl_Ui_Item_Container_Data *pd)
47{
48 Eina_Size2D tmp = pd->content_min_size;
49
50 if (!pd->match_content.w)
51 tmp.w = -1;
52
53 if (!pd->match_content.h)
54 tmp.h = -1;
55
56 efl_gfx_hint_size_min_set(obj, tmp);
57}
58
59static int
60clamp_index(Efl_Ui_Item_Container_Data *pd, int index)
61{
62 if (index < ((int)eina_list_count(pd->items)) * -1)
63 return -1;
64 else if (index > (int)eina_list_count(pd->items) - 1)
65 return 1;
66 return 0;
67}
68
69static int
70index_adjust(Efl_Ui_Item_Container_Data *pd, int index)
71{
72 int c = eina_list_count(pd->items);
73 if (index < c * -1)
74 return 0;
75 else if (index > c - 1)
76 return c - 1;
77 else if (index < 0)
78 return index + c;
79 return index;
80}
81 21
82static Eina_Bool 22static Eina_Bool
83_obj_accessor_get_at(Eina_Accessor *accessor, unsigned int idx, void **data) 23_fast_accessor_get_at(Fast_Accessor *accessor, unsigned int idx, void **data)
84{ 24{
85 ptrdiff_t offset = offsetof(Efl_Ui_Item_Container_Data, obj_accessor);
86 Efl_Ui_Item_Container_Data *pd = (void*)accessor - offset;
87 const Eina_List *over; 25 const Eina_List *over;
88 unsigned int middle; 26 unsigned int middle;
89 unsigned int i; 27 unsigned int i;
90 28
91 if (idx >= eina_list_count(pd->items)) 29 if (idx >= eina_list_count(*accessor->items))
92 return EINA_FALSE; 30 return EINA_FALSE;
93 31
94 if (pd->obj_accessor.last_index == idx) 32 if (accessor->last_index == idx)
95 over = pd->obj_accessor.current; 33 over = accessor->current;
96 else if (idx > pd->obj_accessor.last_index) 34 else if (idx > accessor->last_index)
97 { 35 {
98 /* After current position. */ 36 /* After current position. */
99 middle = ((eina_list_count(pd->items) - pd->obj_accessor.last_index))/2; 37 middle = ((eina_list_count(*accessor->items) - accessor->last_index))/2;
100 38
101 if (idx > middle) 39 if (idx > middle)
102 /* Go backward from the end. */ 40 /* Go backward from the end. */
103 for (i = eina_list_count(pd->items) - 1, 41 for (i = eina_list_count(*accessor->items) - 1,
104 over = eina_list_last(pd->items); 42 over = eina_list_last(*accessor->items);
105 i > idx && over; 43 i > idx && over;
106 --i, over = eina_list_prev(over)) 44 --i, over = eina_list_prev(over))
107 ; 45 ;
108 else 46 else
109 /* Go forward from current. */ 47 /* Go forward from current. */
110 for (i = pd->obj_accessor.last_index, over = pd->obj_accessor.current; 48 for (i = accessor->last_index, over = accessor->current;
111 i < idx && over; 49 i < idx && over;
112 ++i, over = eina_list_next(over)) 50 ++i, over = eina_list_next(over))
113 ; 51 ;
@@ -115,17 +53,17 @@ _obj_accessor_get_at(Eina_Accessor *accessor, unsigned int idx, void **data)
115 else 53 else
116 { 54 {
117 /* Before current position. */ 55 /* Before current position. */
118 middle = pd->obj_accessor.last_index/2; 56 middle = accessor->last_index/2;
119 57
120 if (idx > middle) 58 if (idx > middle)
121 /* Go backward from current. */ 59 /* Go backward from current. */
122 for (i = pd->obj_accessor.last_index, over = pd->obj_accessor.current; 60 for (i = accessor->last_index, over = accessor->current;
123 i > idx && over; 61 i > idx && over;
124 --i, over = eina_list_prev(over)) 62 --i, over = eina_list_prev(over))
125 ; 63 ;
126 else 64 else
127 /* Go forward from start. */ 65 /* Go forward from start. */
128 for (i = 0, over = pd->items; 66 for (i = 0, over = *accessor->items;
129 i < idx && over; 67 i < idx && over;
130 ++i, over = eina_list_next(over)) 68 ++i, over = eina_list_next(over))
131 ; 69 ;
@@ -134,81 +72,140 @@ _obj_accessor_get_at(Eina_Accessor *accessor, unsigned int idx, void **data)
134 if (!over) 72 if (!over)
135 return EINA_FALSE; 73 return EINA_FALSE;
136 74
137 pd->obj_accessor.last_index = idx; 75 accessor->last_index = idx;
138 pd->obj_accessor.current = over; 76 accessor->current = over;
139 77
140 *data = eina_list_data_get(over); 78 *data = eina_list_data_get(over);
141 return EINA_TRUE; 79 return EINA_TRUE;
142} 80}
143 81
82
144static Eina_Accessor* 83static Eina_Accessor*
145_obj_clone(Eina_Accessor *accessor) 84_fast_accessor_clone(Fast_Accessor *accessor)
146{ 85{
147 ptrdiff_t offset = offsetof(Efl_Ui_Item_Container_Data, obj_accessor); 86 return eina_list_accessor_new(*accessor->items);
148 Efl_Ui_Item_Container_Data *pd = (void*)accessor - offset;
149
150 return eina_list_accessor_new(pd->items);
151} 87}
152 88
153static Eina_List * 89static Eina_List *
154_null_container(Eina_Accessor *accessor EINA_UNUSED) 90_fast_accessor_get_container(Fast_Accessor *accessor EINA_UNUSED)
155{ 91{
156 ERR("Not allowed to get a container!"); 92 ERR("Not allowed to get a container!");
157 return NULL; 93 return NULL;
158} 94}
159 95
160static void 96static void
161_free(Eina_Accessor *accessor EINA_UNUSED) 97_fast_accessor_free(Fast_Accessor *accessor EINA_UNUSED)
162{ 98{
163 ERR("Freeing this accessor is not supported"); 99 ERR("Freeing this accessor is not supported");
164} 100}
165 101
166static void 102static void
167_obj_accessor_init(Eina_Accessor *accessor) 103_fast_accessor_init(Fast_Accessor *accessor, Eina_List **items)
168{ 104{
169 //this is the accessor for accessing the items 105 //this is the accessor for accessing the items
170 //we have to workarround here the problem that 106 //we have to workarround here the problem that
171 //no accessor can be created for a not yet created list. 107 //no accessor can be created for a not yet created list.
172 accessor->version = EINA_ACCESSOR_VERSION; 108 accessor->acc.version = EINA_ACCESSOR_VERSION;
173 accessor->get_at = FUNC_ACCESSOR_GET_AT(_obj_accessor_get_at); 109 accessor->acc.get_at = FUNC_ACCESSOR_GET_AT(_fast_accessor_get_at);
174 accessor->clone = FUNC_ACCESSOR_CLONE(_obj_clone); 110 accessor->acc.clone = FUNC_ACCESSOR_CLONE(_fast_accessor_clone);
175 accessor->get_container = FUNC_ACCESSOR_GET_CONTAINER(_null_container); 111 accessor->acc.get_container = FUNC_ACCESSOR_GET_CONTAINER(_fast_accessor_get_container);
176 accessor->free = FUNC_ACCESSOR_FREE(_free); 112 accessor->acc.free = FUNC_ACCESSOR_FREE(_fast_accessor_free);
177 EINA_MAGIC_SET(accessor, EINA_MAGIC_ACCESSOR); 113 EINA_MAGIC_SET(&accessor->acc, EINA_MAGIC_ACCESSOR);
114 accessor->items = items;
178} 115}
179 116
180static Eina_Bool 117static void
181_size_accessor_get_at(Eina_Accessor *accessor, unsigned int idx, void **data) 118_fast_accessor_remove(Fast_Accessor *accessor, const Eina_List *removed_elem)
182{ 119{
183 Eina_Size2D *size = (Eina_Size2D*)data; 120 if (accessor->current == removed_elem)
184 ptrdiff_t offset = offsetof(Efl_Ui_Item_Container_Data, size_accessor); 121 {
185 Efl_Ui_Item_Container_Data *pd = (void*)accessor - offset; 122 Eina_List *next;
123 Eina_List *prev;
186 124
187 if (idx > eina_list_count(pd->items)) 125 next = eina_list_next(removed_elem);
188 return EINA_FALSE; 126 prev = eina_list_prev(removed_elem);
127 if (next)
128 {
129 accessor->current = next;
130 accessor->last_index ++;
131 }
132 else if (prev)
133 {
134 accessor->current = prev;
135 accessor->last_index --;
136 }
137 else
138 {
139 //everything >= length is invalid, and we need that.
140 accessor->last_index = eina_list_count(*accessor->items);
141 accessor->current = NULL;
142 }
189 143
190 Eo *subobj = eina_list_nth(pd->items, idx); 144 }
191 145
192 *size = efl_gfx_hint_size_combined_min_get(subobj); 146}
193 147
194 return EINA_TRUE; 148#define MY_CLASS EFL_UI_ITEM_CONTAINER_CLASS
149
150#define MY_DATA_GET(obj, pd) \
151 Efl_Ui_Item_Container_Data *pd = efl_data_scope_get(obj, MY_CLASS);
152
153typedef struct {
154 Efl_Ui_Scroll_Manager *smanager;
155 Efl_Ui_Pan *pan;
156 Eina_List *selected;
157 Eina_List *items;
158 Efl_Ui_Select_Mode mode;
159 Efl_Ui_Layout_Orientation dir;
160 Eina_Size2D content_min_size;
161 Efl_Ui_Position_Manager_Entity *pos_man;
162 struct {
163 Eina_Bool w;
164 Eina_Bool h;
165 } match_content;
166 Fast_Accessor obj_accessor;
167 Fast_Accessor size_accessor;
168 Efl_Gfx_Entity *sizer;
169} Efl_Ui_Item_Container_Data;
170
171static Eina_Bool register_item(Eo *obj, Efl_Ui_Item_Container_Data *pd, Efl_Ui_Item *item);
172static Eina_Bool unregister_item(Eo *obj, Efl_Ui_Item_Container_Data *pd, Efl_Ui_Item *item);
173
174static void
175flush_min_size(Eo *obj, Efl_Ui_Item_Container_Data *pd)
176{
177 Eina_Size2D tmp = pd->content_min_size;
178
179 if (!pd->match_content.w)
180 tmp.w = -1;
181
182 if (!pd->match_content.h)
183 tmp.h = -1;
184
185 efl_gfx_hint_size_min_set(obj, tmp);
195} 186}
196 187
197static Eina_Accessor* 188static int
198_size_clone(Eina_Accessor *accessor EINA_UNUSED) 189clamp_index(Efl_Ui_Item_Container_Data *pd, int index)
199{ 190{
200 return NULL; 191 if (index < ((int)eina_list_count(pd->items)) * -1)
192 return -1;
193 else if (index > (int)eina_list_count(pd->items) - 1)
194 return 1;
195 return 0;
201} 196}
202 197
203static void 198static int
204_size_accessor_init(Eina_Accessor *accessor) 199index_adjust(Efl_Ui_Item_Container_Data *pd, int index)
205{ 200{
206 accessor->version = EINA_ACCESSOR_VERSION; 201 int c = eina_list_count(pd->items);
207 accessor->get_at = FUNC_ACCESSOR_GET_AT(_size_accessor_get_at); 202 if (index < c * -1)
208 accessor->clone = FUNC_ACCESSOR_CLONE(_size_clone); 203 return 0;
209 accessor->get_container = FUNC_ACCESSOR_GET_CONTAINER(_null_container); 204 else if (index > c - 1)
210 accessor->free = FUNC_ACCESSOR_FREE(_free); 205 return c - 1;
211 EINA_MAGIC_SET(accessor, EINA_MAGIC_ACCESSOR); 206 else if (index < 0)
207 return index + c;
208 return index;
212} 209}
213 210
214static void 211static void
@@ -288,6 +285,23 @@ _efl_ui_item_container_selected_items_get(Eo *obj EINA_UNUSED, Efl_Ui_Item_Conta
288 return eina_list_iterator_new(pd->selected); 285 return eina_list_iterator_new(pd->selected);
289} 286}
290 287
288static Eina_Bool
289_size_accessor_get_at(Fast_Accessor *accessor, unsigned int idx, void **data)
290{
291 Eina_Bool res = EINA_FALSE;
292 Efl_Gfx_Entity *geom;
293 Eina_Size2D *size = (void*)data;
294
295 res = _fast_accessor_get_at(accessor, idx,(void*) &geom);
296
297 if (!res) return EINA_FALSE;
298
299 *size = efl_gfx_hint_size_min_get(geom);
300
301 return res;
302}
303
304
291EOLIAN static Efl_Object* 305EOLIAN static Efl_Object*
292_efl_ui_item_container_efl_object_constructor(Eo *obj, Efl_Ui_Item_Container_Data *pd EINA_UNUSED) 306_efl_ui_item_container_efl_object_constructor(Eo *obj, Efl_Ui_Item_Container_Data *pd EINA_UNUSED)
293{ 307{
@@ -295,8 +309,9 @@ _efl_ui_item_container_efl_object_constructor(Eo *obj, Efl_Ui_Item_Container_Dat
295 309
296 pd->dir = EFL_UI_LAYOUT_ORIENTATION_VERTICAL; 310 pd->dir = EFL_UI_LAYOUT_ORIENTATION_VERTICAL;
297 311
298 _obj_accessor_init(&pd->obj_accessor.pass_on); 312 _fast_accessor_init(&pd->obj_accessor, &pd->items);
299 _size_accessor_init(&pd->size_accessor); 313 _fast_accessor_init(&pd->size_accessor, &pd->items);
314 pd->size_accessor.acc.get_at = FUNC_ACCESSOR_GET_AT(_size_accessor_get_at);
300 315
301 if (!elm_widget_theme_klass_get(obj)) 316 if (!elm_widget_theme_klass_get(obj))
302 elm_widget_theme_klass_set(obj, "item_container"); 317 elm_widget_theme_klass_set(obj, "item_container");
@@ -553,25 +568,9 @@ unregister_item(Eo *obj, Efl_Ui_Item_Container_Data *pd, Efl_Ui_Item *item)
553 return EINA_FALSE; 568 return EINA_FALSE;
554 569
555 unsigned int id = eina_list_data_idx(pd->items, item); 570 unsigned int id = eina_list_data_idx(pd->items, item);
556 if (pd->obj_accessor.last_index == id)
557 {
558 if (eina_list_next(elem))
559 {
560 pd->obj_accessor.current = eina_list_next(elem);
561 }
562 else if (eina_list_prev(elem))
563 {
564 pd->obj_accessor.last_index = id-1;
565 pd->obj_accessor.current = eina_list_prev(elem);
566 }
567 else
568 {
569 //everything >= length is invalid, and we need that.
570 pd->obj_accessor.last_index = eina_list_count(pd->items);
571 pd->obj_accessor.current = NULL;
572 }
573 571
574 } 572 _fast_accessor_remove(&pd->obj_accessor, elem);
573 _fast_accessor_remove(&pd->size_accessor, elem);
575 574
576 pd->items = eina_list_remove(pd->items, item); 575 pd->items = eina_list_remove(pd->items, item);
577 pd->selected = eina_list_remove(pd->selected, item); 576 pd->selected = eina_list_remove(pd->selected, item);
@@ -589,6 +588,8 @@ update_pos_man(Eo *obj EINA_UNUSED, Efl_Ui_Item_Container_Data *pd, Efl_Gfx_Enti
589 { 588 {
590 pd->obj_accessor.last_index = id; 589 pd->obj_accessor.last_index = id;
591 pd->obj_accessor.current = pd->items; 590 pd->obj_accessor.current = pd->items;
591 pd->size_accessor.last_index = id;
592 pd->size_accessor.current = pd->items;
592 } 593 }
593 efl_ui_position_manager_entity_item_added(pd->pos_man, id, subobj); 594 efl_ui_position_manager_entity_item_added(pd->pos_man, id, subobj);
594} 595}
@@ -765,7 +766,7 @@ _efl_ui_item_container_position_manager_set(Eo *obj, Efl_Ui_Item_Container_Data
765 { 766 {
766 efl_parent_set(pd->pos_man, obj); 767 efl_parent_set(pd->pos_man, obj);
767 efl_event_callback_array_add(pd->pos_man, pos_manager_cbs(), obj); 768 efl_event_callback_array_add(pd->pos_man, pos_manager_cbs(), obj);
768 efl_ui_position_manager_entity_data_access_set(pd->pos_man, &pd->obj_accessor.pass_on, &pd->size_accessor, eina_list_count(pd->items)); 769 efl_ui_position_manager_entity_data_access_set(pd->pos_man, &pd->obj_accessor.acc, &pd->size_accessor.acc, eina_list_count(pd->items));
769 efl_ui_position_manager_entity_viewport_set(pd->pos_man, efl_ui_scrollable_viewport_geometry_get(obj)); 770 efl_ui_position_manager_entity_viewport_set(pd->pos_man, efl_ui_scrollable_viewport_geometry_get(obj));
770 efl_ui_layout_orientation_set(pd->pos_man, pd->dir); 771 efl_ui_layout_orientation_set(pd->pos_man, pd->dir);
771 } 772 }