From 0008f3dd399f4257b3ca9c8c431a37c284a4ae9d Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Sep 2024 14:15:23 +0200 Subject: [PATCH] InputText: amends: now can use memchr()/strchr() for line counting. Much faster! (#7925) --- docs/CHANGELOG.txt | 4 ++++ docs/TODO.txt | 1 - imgui_widgets.cpp | 24 ++++++++++-------------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 35c4c6743d34..1611bf59b9a8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -63,6 +63,10 @@ Other changes: #6223, #6364, #6387, #6567, #6692, #6724, #6939, #6984, #7246, #7270, #7375, #7421, #7434, #7472, #7581, #7724, #7926, #7937 and probably more..) - Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439) +- InputText: internal refactoring to simplify and optimize the code. The ImWchar buffer has been + removed. Simplifications allowed to implement new optimizations for handling very large text buffers + (e.g. in our testing, handling of a 1 MB text buffer is now 3 times faster in VS2022 Debug build). + This is the first step toward more refactorig. (#7925) [@alektron, @ocornut] - InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow. - TextLinkOpenURL(): modified tooltip to display a verb "Open 'xxxx'". (#7885, #7660) - Backends: SDL2: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) [@scribam] diff --git a/docs/TODO.txt b/docs/TODO.txt index 84a00bc6e92b..ddceb3b3d9bb 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -65,7 +65,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - selectable: generic BeginSelectable()/EndSelectable() mechanism. (work out alongside range-select branch) - selectable: a way to visualize partial/mixed selection (e.g. parent tree node has children with mixed selection) - - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile. (WIP branch) - input text: preserve scrolling when unfocused? - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541) - input text: expose CursorPos in char filter event (#816) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b5c69e73eb06..94e1abff6028 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5119,14 +5119,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter. searches_remaining += is_multiline ? 1 : 0; int line_count = 0; - //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bit - for (const char* s = text_begin; *s != 0; s++) - if (*s == '\n') - { - line_count++; - if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; } - if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; } - } + for (const char* s = text_begin; (s = strchr(s, '\n')) != NULL; s++) // FIXME-OPT: memchr() would be faster? + { + line_count++; + if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; } + if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; } + } line_count++; if (searches_result_line_no[0] == -1) searches_result_line_no[0] = line_count; @@ -5199,11 +5197,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ break; if (rect_pos.y < clip_rect.y) { - //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bit - //p = p ? p + 1 : text_selected_end; - while (p < text_selected_end) - if (*p++ == '\n') - break; + p = (const char*)memchr((void*)p, '\n', text_selected_end - p); + p = p ? p + 1 : text_selected_end; } else { @@ -5213,13 +5208,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ rect.ClipWith(clip_rect); if (rect.Overlaps(clip_rect)) draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); + rect_pos.x = draw_pos.x - draw_scroll.x; } - rect_pos.x = draw_pos.x - draw_scroll.x; rect_pos.y += g.FontSize; } } // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash. + // FIXME-OPT: Multiline could submit a smaller amount of contents to AddText() since we already iterated through it. if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) { ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);