From 9cf94d5dd6b178ecf579263fea0750d4547be26c Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 12 Oct 2018 12:34:47 +0200 Subject: [PATCH] RenderText(), InputTextMultiline(): Optimization for large text by using memchr, wmemchr, wcschr when appropriate. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 5 ++--- imgui_draw.cpp | 16 ++++++++-------- imgui_widgets.cpp | 20 +++++++++----------- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b9af2ce3..0c3de1aa 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -59,6 +59,7 @@ Other Changes: introduced in 1.50 and broken in 1.60. (#1698, #894, #713). - TextUnformatted(): Fixed a case where large-text path would read bytes past the text_end marker depending on the position of new lines in the buffer (it wasn't affecting the output but still not the right thing to do!) +- InputTextMultiline(), RenderText(): Some optimization for very large text buffers, useful for non-optimized builds. - BeginMenu(): Fixed menu popup horizontal offset being off the item in the menu bar when WindowPadding=0.0f. - ArrowButton(): Fixed arrow shape being horizontally misaligned by (FramePadding.y-FramePadding.x) if they are different. - Drag and Drop: Added GetDragDropPayload() to peek directly into the payload (if any) from anywhere. (#143) diff --git a/imgui.cpp b/imgui.cpp index 9ddc63a8..1ef7669d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -850,6 +850,7 @@ CODE #include // toupper, isprint #include // vsnprintf, sscanf, printf +#include // wcslen #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier #include // intptr_t #else @@ -1210,9 +1211,7 @@ const char* ImStrchrRange(const char* str, const char* str_end, char c) int ImStrlenW(const ImWchar* str) { - int n = 0; - while (*str++) n++; - return n; + return (int)wcslen((const wchar_t*)str); } // Find end-of-line. Return pointer will point to either first \n, either str_end. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 658aab0c..3faa9b01 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2646,11 +2646,11 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col // Fast-forward to first visible line const char* s = text_begin; if (y + line_height < clip_rect.y && !word_wrap_enabled) - while (y + line_height < clip_rect.y) + while (y + line_height < clip_rect.y && s < text_end) { - while (s < text_end) - if (*s++ == '\n') - break; + s = (const char*)memchr(s, '\n', text_end - s) + 1; + if (s == NULL) + s = text_end; y += line_height; } @@ -2660,15 +2660,15 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col { const char* s_end = s; float y_end = y; - while (y_end < clip_rect.w) + while (y_end < clip_rect.w && s_end < text_end) { - while (s_end < text_end) - if (*s_end++ == '\n') - break; + s_end = (const char*)memchr(s_end, '\n', text_end - s_end) + 1; y_end += line_height; } text_end = s_end; } + if (s == text_end) + return; // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) const int vtx_count_max = (int)(text_end - s) * 4; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 5cfad55d..df83a1d8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -36,6 +36,7 @@ Index of this file: #include "imgui_internal.h" #include // toupper, isprint +#include // wmemchr #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier #include // intptr_t #else @@ -2906,7 +2907,7 @@ static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n); obj->CurLenW -= n; - // Offset remaining text + // Offset remaining text (FIXME-OPT: Use memmove) const ImWchar* src = obj->TextW.Data + pos + n; while (ImWchar c = *src++) *dst++ = c; @@ -3617,13 +3618,12 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // 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 != 0; s++) - if (*s == '\n') - { - line_count++; - if (searches_result_line_number[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_number[0] = line_count; if (--searches_remaining <= 0) break; } - if (searches_result_line_number[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_number[1] = line_count; if (--searches_remaining <= 0) break; } - } + for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) + { + line_count++; + if (searches_result_line_number[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_number[0] = line_count; if (--searches_remaining <= 0) break; } + if (searches_result_line_number[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_number[1] = line_count; if (--searches_remaining <= 0) break; } + } line_count++; if (searches_result_line_number[0] == -1) searches_result_line_number[0] = line_count; if (searches_result_line_number[1] == -1) searches_result_line_number[1] = line_count; @@ -3691,9 +3691,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 break; if (rect_pos.y < clip_rect.y) { - while (p < text_selected_end) - if (*p++ == '\n') - break; + p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p) + 1; } else {