From dc83e09f43c3793603220681520e0c8f90a17878 Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Tue, 25 Apr 2023 17:50:44 +0300 Subject: [PATCH] improve performance by caching the index of the last component node --- Makefile | 2 +- src/main.c | 4 +++- src/node.c | 34 ++++++++++++++++++++++++++++++---- src/node.h | 3 +++ 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 7d816e8..7838424 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ OBJS=$(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SRCS)) DEPS=$(OBJS:%.o=%.d) -all: CFLAGS+=-fsanitize=address -Og -ggdb +all: CFLAGS+=-Og -ggdb -DNDEBUG all: $(BUILD) $(BIN) release: CFLAGS+=-O2 -flto=auto -DNDEBUG diff --git a/src/main.c b/src/main.c index db5c41a..b6860af 100644 --- a/src/main.c +++ b/src/main.c @@ -130,13 +130,15 @@ int app_handle(struct UINode *node, void *data, int event_type, size_t d, void * box_layout_new(buttons, UI_DIRECTION_VERTICAL); - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 10000; i++) { UINode *button = node_new(buttons, "button"); state_background_node_new(button, UIPurple600, UIPurple700, UIPurple800, 6.0); text_node_new(button, state->font, UINeutral50, "button"); dispatcher_new(button, UI_EVENT_UNPRESSED, INCREMENT_COUNT, state, app_handle); button->width_policy = UI_SIZE_POLICY_GROW; } + + printf("%d\n", buttons->last_component_index); } break; diff --git a/src/node.c b/src/node.c index 1969803..2b6e68d 100644 --- a/src/node.c +++ b/src/node.c @@ -28,14 +28,25 @@ int node_dispatch(UINode *node, enum UIEvent ev, size_t d, void *p) return 0; } + int result = 0; + int component_index = UI_NODE_LAST_COMPONENT_INDEX_NONE; for (int i = 0; i < node->nodes_count; i++) { + if (node->last_component_index == UI_NODE_LAST_COMPONENT_INDEX_NONE || (node->last_component_index >= 0 && i > node->last_component_index)) { + break; + } if (node->nodes[i]->flags & UI_NODE_COMPONENT) { - int result = node_dispatch(node->nodes[i], ev, d, p); - if (result) return result; + component_index = i; + result = node_dispatch(node->nodes[i], ev, d, p); + if (result) break; } } + if (node->last_component_index < 0) { + node->last_component_index = component_index; + } + if (result) return result; + if (node->handle) { - int result = (node->handle)(node, ev, d, p); + result = (node->handle)(node, ev, d, p); if (result) return result; } if (node->handle_proto) { @@ -71,12 +82,20 @@ void node_init(UINode *node) node->height_policy = UI_SIZE_POLICY_DYNAMIC; node->handle = NULL; node->handle_proto = NULL; + node->last_component_index = UI_NODE_LAST_COMPONENT_INDEX_NONE; } void node_free(UINode *node) { if (!node) return; + // TODO: properly handle removing this node from its parent + + // Invalidate component index cache + if ((node->flags & UI_NODE_COMPONENT) && node->parent) { + node->parent->last_component_index = UI_NODE_LAST_COMPONENT_INDEX_INVALIDATED; + } + node_dispatch(node, UI_EVENT_DESTROY, 0, NULL); for (int i = 0; i < node->nodes_count; i++) { @@ -135,7 +154,14 @@ UINode *node_attach(UINode *parent, UINode *node) return NULL; } } - parent->nodes[parent->nodes_count++] = node; + int index = parent->nodes_count++; + parent->nodes[index] = node; + + // Let's save the index of the last component so that we can exit the loop early + // if there's no components left when we're in node_dispatch() + if ((node->flags & UI_NODE_COMPONENT) && index > parent->last_component_index) { + parent->last_component_index = index; + } } return node; diff --git a/src/node.h b/src/node.h index dd788fa..aa8e0a7 100644 --- a/src/node.h +++ b/src/node.h @@ -41,6 +41,8 @@ enum UIDirection { #define UI_NODE_RETAINS_PRESS (1 << 1) #define UI_NODE_DISABLED (1 << 2) +#define UI_NODE_LAST_COMPONENT_INDEX_INVALIDATED (-1) +#define UI_NODE_LAST_COMPONENT_INDEX_NONE (-2) typedef struct UINode { const char *text; UIRect rect; @@ -53,6 +55,7 @@ typedef struct UINode { uint32_t flags; enum UISizePolicy width_policy; enum UISizePolicy height_policy; + int last_component_index; int (*handle)(struct UINode *node, enum UIEvent ev, size_t d, void *p); int (*handle_proto)(struct UINode *node, enum UIEvent ev, size_t d, void *p);