From 22828c9d233d63ad2d90a237c3f66951e7474906 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sat, 6 Jul 2024 09:51:39 +0200 Subject: [PATCH] Print loaded files and errors, enable loading and searching --- src/basic/basic.h | 6 +- src/basic/thread_queue.h | 5 +- src/basic/win32_thread.cpp | 1 + src/transcript_browser/_main.cpp | 2 +- src/transcript_browser/loading_thread.cpp | 68 ++++++-- src/transcript_browser/main.cpp | 167 ++++++++++++-------- src/transcript_browser/searching_thread.cpp | 18 ++- 7 files changed, 173 insertions(+), 94 deletions(-) diff --git a/src/basic/basic.h b/src/basic/basic.h index d37c2f1..b1e9ec2 100644 --- a/src/basic/basic.h +++ b/src/basic/basic.h @@ -401,9 +401,9 @@ struct Array { } void bounded_add(T item) { - Assert(len + 1 <= cap); - try_growing(); // in case of error - data[len++] = item; + if (len + 1 <= cap) { + data[len++] = item; + } } T *alloc(const T &item) { diff --git a/src/basic/thread_queue.h b/src/basic/thread_queue.h index f4854c5..f37b553 100644 --- a/src/basic/thread_queue.h +++ b/src/basic/thread_queue.h @@ -11,6 +11,7 @@ struct ThreadCtx { }; struct WorkQueue { + int32_t thread_count; WorkQueueEntry entries[256]; int64_t volatile index_to_write; int64_t volatile index_to_read; @@ -27,4 +28,6 @@ struct ThreadStartupInfo { void PushWork(WorkQueue *wq, void *data, WorkQueueCallback *callback); void InitWorkQueue(WorkQueue *queue, uint32_t thread_count, ThreadStartupInfo *info); -void WaitUntilCompletion(WorkQueue *wq); \ No newline at end of file +void WaitUntilCompletion(WorkQueue *wq); + +int64_t AtomicIncrement(volatile int64_t *i); \ No newline at end of file diff --git a/src/basic/win32_thread.cpp b/src/basic/win32_thread.cpp index a39c49e..d51bc4a 100644 --- a/src/basic/win32_thread.cpp +++ b/src/basic/win32_thread.cpp @@ -51,6 +51,7 @@ DWORD WINAPI WorkQueueThreadEntry(LPVOID param) { } void InitWorkQueue(WorkQueue *queue, uint32_t thread_count, ThreadStartupInfo *info) { + queue->thread_count = thread_count; queue->index_to_read = 0; queue->index_to_write = 0; queue->completion_index = 0; diff --git a/src/transcript_browser/_main.cpp b/src/transcript_browser/_main.cpp index 4622f86..aa32c01 100644 --- a/src/transcript_browser/_main.cpp +++ b/src/transcript_browser/_main.cpp @@ -40,7 +40,7 @@ Array ParseSrtFile(Arena *arena, String filename) { for (int i = 0; i < lines.len;) { String it0 = lines[i++]; long num = strtol(it0.data, NULL, 10); - Assert(section_number == num); + Assert(section_number == num); // @todo: error section_number += 1; TimeString item = {}; diff --git a/src/transcript_browser/loading_thread.cpp b/src/transcript_browser/loading_thread.cpp index d86084f..512efd5 100644 --- a/src/transcript_browser/loading_thread.cpp +++ b/src/transcript_browser/loading_thread.cpp @@ -65,9 +65,24 @@ struct XToTimeString { String filepath; }; -Arena XArena; -std::mutex XArenaAddMutex; -Array XToTime; +struct FileLoadResult { + String filename; + String error; +}; + +Arena XArena; +std::mutex XArenaAddMutex; +Array XToTime; +Array XFileLoadResults; +int64_t XLoadThreadComplete; + +void XInitLoading() { + InitArena(&XArena); + XArena.align = 0; + + XToTime.reserve(1000000); + XFileLoadResults.reserve(10000); +} WORK_FUNCTION(ParseFilesWork) { ParseThreadIO *io = (ParseThreadIO *)data; @@ -82,12 +97,27 @@ WORK_FUNCTION(ParseFilesWork) { XToTime.add({s, it.hour, it.minute, it.second, it_time_file}); } XArenaAddMutex.unlock(); + XFileLoadResults.bounded_add({it_time_file}); } + AtomicIncrement(&XLoadThreadComplete); +} + +String XGetArenaString() { + XArenaAddMutex.lock(); + String buffer = {(char *)XArena.data, (int64_t)XArena.len}; + XArenaAddMutex.unlock(); + return buffer; +} + +Array XLockFileLoadResults() { + return XFileLoadResults; +} + +void XUnlockFileResults() { } void XAddFolder(String folder, Array *filenames) { - Scratch scratch; - + Scratch scratch; Array srt_files = {scratch}; for (FileIter iter = IterateFiles(scratch, folder); IsValid(iter); Advance(&iter)) { String file = Copy(Perm, iter.absolute_path); @@ -97,15 +127,20 @@ void XAddFolder(String folder, Array *filenames) { } } - int64_t thread_count = 16; + if (srt_files.len == 0) { + XFileLoadResults.add({Copy(Perm, folder), "no files found"}); + return; + } + + int64_t thread_count = MainWorkQueue.thread_count; int64_t files_per_thread = srt_files.len / thread_count; int64_t remainder = srt_files.len % thread_count; int64_t fi = 0; - Array io = {scratch}; + Array io = {Perm}; io.reserve(thread_count); for (int ti = 0; ti < thread_count; ti += 1) { - Array files = {scratch}; + Array files = {Perm}; for (int i = 0; fi < srt_files.len && i < files_per_thread + remainder; fi += 1, i += 1) { files.add(srt_files[fi]); } @@ -115,18 +150,27 @@ void XAddFolder(String folder, Array *filenames) { i->input_files = files; PushWork(&MainWorkQueue, (void *)i, ParseFilesWork); } - - WaitUntilCompletion(&MainWorkQueue); } XToTimeString *XFindItem(String string) { + XToTimeString *result = NULL; + + XArenaAddMutex.lock(); For(XToTime) { uintptr_t begin = (uintptr_t)(it.string.data); uintptr_t end = (uintptr_t)(it.string.data + it.string.len); uintptr_t needle = (uintptr_t)string.data; if (needle >= begin && needle < end) { - return ⁢ + result = ⁢ + break; } } - return NULL; + XArenaAddMutex.unlock(); + + return result; } + +bool XLoadingComplete() { + bool result = MainWorkQueue.thread_count == XLoadThreadComplete; + return result; +} \ No newline at end of file diff --git a/src/transcript_browser/main.cpp b/src/transcript_browser/main.cpp index 111badc..5365e95 100644 --- a/src/transcript_browser/main.cpp +++ b/src/transcript_browser/main.cpp @@ -3,8 +3,6 @@ #include "../basic/filesystem.h" #include "../basic/thread_queue.h" -#include -#include #include #include @@ -20,25 +18,98 @@ WorkQueue MainWorkQueue; #include "loading_thread.cpp" #include "searching_thread.cpp" -/* +void UISearchResults(Array filenames) { + Scratch scratch; + Array matches = LockSearchResults(); + defer { UnlockSearchResults(); }; -TODO: -- New threading model idea: I could just spin up a bunch of threads and then don't kill them. Just use them for searching! Each one would have it's own xarena and so on. -*/ + float font_size = ImGui::GetFontSize(); + ImFont *font = ImGui::GetFont(); + const ImGuiViewport *main_viewport = ImGui::GetMainViewport(); -// -// Searching thread -// + int64_t chars_per_line = (int64_t)(main_viewport->WorkSize.x / 2) / (int64_t)font->GetCharAdvance('_') - strlen(Prompt) * 2; + + ImGuiListClipper clipper; + clipper.Begin((int)matches.len); + while (clipper.Step()) { + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { + ImGui::PushID(i); + defer { ImGui::PopID(); }; + auto &it = matches[i]; + uintptr_t begin_region = (uintptr_t)XArena.data; + uintptr_t end_region = (uintptr_t)XArena.data + XArena.len; + + uint64_t begin = (uintptr_t)(it.data - chars_per_line / 2); + uint64_t end = (uintptr_t)(it.data + it.len + chars_per_line / 2); + + uint64_t a = Clamp(begin, begin_region, end_region); + uint64_t b = Clamp((uintptr_t)it.data, begin_region, end_region); + String left = {(char *)a, (int64_t)(b - a)}; + + uint64_t c = Clamp((uintptr_t)(it.data + it.len), begin_region, end_region); + uint64_t d = Clamp(end, begin_region, end_region); + String right = {(char *)c, (int64_t)(d - c)}; + + String middle = it; + String string = Format(scratch, "%.*s**%.*s**%.*s", + FmtString(left), FmtString(middle), FmtString(right)); + + XToTimeString *item = XFindItem(middle); + if (ImGui::Button(string.data)) { + String base = ChopLastPeriod(item->filepath); // .srt + base = ChopLastPeriod(base); // .en + + For(filenames) { + if (StartsWith(it, base)) { + if (EndsWith(it, ".mkv") || EndsWith(it, ".webm") || EndsWith(it, ".mp4")) { + int seconds = item->hour * 60 * 60 + item->minute * 60 + item->second; + String copy = Copy(scratch, it); + for (int i = 0; i < copy.len; i += 1) + if (copy.data[i] == '/') copy.data[i] = '\\'; + String args = Format(scratch, "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe --start-time %d \"%.*s\"", seconds, FmtString(copy)); + RunEx(args); + } + } + } + } + ImGui::SameLine(); + ImGui::Text(SkipToLastSlash(item->filepath).data); + } + } +} + +void UILoadedFiles() { + Scratch scratch; + Array file_load_results = XLockFileLoadResults(); + defer { XUnlockFileResults(); }; + + ImGuiListClipper clipper; + clipper.Begin((int)file_load_results.len); + while (clipper.Step()) { + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { + FileLoadResult file = file_load_results[file_load_results.len - 1 - i]; + if (file.error.len) { + ImGui::PushStyleColor(ImGuiCol_Text, (ImVec4)ImColor::HSV(7.0f, 0.6f, 0.6f)); + String string = Format(scratch, "%.*s error: %.*s", FmtString(file.filename), FmtString(file.error)); + ImGui::Text(string.data); + ImGui::PopStyleColor(); + } else { + String string = Format(scratch, "%.*s loaded", FmtString(file.filename)); + ImGui::Text(string.data); + } + } + } +} int main(int, char **) { InitOS(); InitScratch(); InitArena(&Perm); - InitArena(&XArena); - XArena.align = 0; + XInitLoading(); + InitSearch(); ThreadStartupInfo infos[16] = {}; - InitWorkQueue(&MainWorkQueue, 16, infos); + InitWorkQueue(&MainWorkQueue, Lengthof(infos), infos); memcpy(Prompt, "read=D:/zizek", sizeof("read=D:/zizek")); @@ -93,11 +164,9 @@ int main(int, char **) { ImGui_ImplOpenGL3_Init(glsl_version); io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - // Our state - bool show_demo_window = true; - bool show_another_window = false; - ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + bool show_loaded_files = false; bool set_focus_to_input = true; int64_t frame = -1; @@ -111,6 +180,7 @@ int main(int, char **) { bool set_focus_to_list = false; bool tab_press = false; bool enter_press = false; + bool f1_press = false; SDL_Event event; #if 1 while (SDL_PollEvent(&event)) { @@ -127,6 +197,8 @@ int main(int, char **) { set_focus_to_input = true; } else if (event.key.keysym.sym == SDLK_TAB) { tab_press = true; + } else if (event.key.keysym.sym == SDLK_F1) { + f1_press = true; } } else if (event.type == SDL_KEYUP) { @@ -151,11 +223,16 @@ int main(int, char **) { ImGui::SetNextWindowSize(ImVec2(main_viewport->Size.x, 20), ImGuiCond_Always); ImGui::Begin("input", NULL, window_flags); + if (ImGui::Button("Show loaded files") || f1_press) { + show_loaded_files = !show_loaded_files; + } + ImGui::SameLine(); if (set_focus_to_input) ImGui::SetKeyboardFocusHere(0); if (tab_press && ImGui::IsWindowFocused()) set_focus_to_list = true; if (ImGui::InputText("Input your query", Prompt, sizeof(Prompt))) { StartSearchingForMatches(); } + ImGui::End(); if (enter_press) { @@ -175,60 +252,10 @@ int main(int, char **) { ImGui::Begin("result", NULL, window_flags); if (!ImGui::IsWindowFocused() && set_focus_to_list) ImGui::SetKeyboardFocusHere(0); - - Array matches = LockSearchResults(); - defer { UnlockSearchResults(); }; - - float font_size = ImGui::GetFontSize(); - ImFont *font = ImGui::GetFont(); - int64_t chars_per_line = (int64_t)(main_viewport->WorkSize.x / 2) / (int64_t)font->GetCharAdvance('_') - strlen(Prompt) * 2; - - ImGuiListClipper clipper; - clipper.Begin((int)matches.len); - while (clipper.Step()) { - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - ImGui::PushID(i); - defer { ImGui::PopID(); }; - auto &it = matches[i]; - uintptr_t begin_region = (uintptr_t)XArena.data; - uintptr_t end_region = (uintptr_t)XArena.data + XArena.len; - - uint64_t begin = (uintptr_t)(it.data - chars_per_line / 2); - uint64_t end = (uintptr_t)(it.data + it.len + chars_per_line / 2); - - uint64_t a = Clamp(begin, begin_region, end_region); - uint64_t b = Clamp((uintptr_t)it.data, begin_region, end_region); - String left = {(char *)a, (int64_t)(b - a)}; - - uint64_t c = Clamp((uintptr_t)(it.data + it.len), begin_region, end_region); - uint64_t d = Clamp(end, begin_region, end_region); - String right = {(char *)c, (int64_t)(d - c)}; - - String middle = it; - String string = Format(frame_arena, "%.*s**%.*s**%.*s", - FmtString(left), FmtString(middle), FmtString(right)); - - XToTimeString *item = XFindItem(middle); - if (ImGui::Button(string.data)) { - String base = ChopLastPeriod(item->filepath); // .srt - base = ChopLastPeriod(base); // .en - - For(filenames) { - if (StartsWith(it, base)) { - if (EndsWith(it, ".mkv") || EndsWith(it, ".webm") || EndsWith(it, ".mp4")) { - int seconds = item->hour * 60 * 60 + item->minute * 60 + item->second; - String copy = Copy(*frame_arena, it); - for (int i = 0; i < copy.len; i += 1) - if (copy.data[i] == '/') copy.data[i] = '\\'; - String args = Format(*frame_arena, "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe --start-time %d \"%.*s\"", seconds, FmtString(copy)); - RunEx(args); - } - } - } - } - ImGui::SameLine(); - ImGui::Text(SkipToLastSlash(item->filepath).data); - } + if (show_loaded_files) { + UILoadedFiles(); + } else { + UISearchResults(filenames); } ImGui::End(); } diff --git a/src/transcript_browser/searching_thread.cpp b/src/transcript_browser/searching_thread.cpp index 1a9c83a..38284d7 100644 --- a/src/transcript_browser/searching_thread.cpp +++ b/src/transcript_browser/searching_thread.cpp @@ -1,30 +1,30 @@ Array Matches = {}; char Prompt[256]; std::mutex SearchThreadArrayMutex; -bool SearchThreadStopSearching; +int64_t SearchThreadStopSearching; WORK_FUNCTION(SearchForMatchesWork) { if (Prompt[0] == 0) return; + int64_t search_thread_stop_searching = SearchThreadStopSearching; + SearchThreadArrayMutex.lock(); Matches.clear(); SearchThreadArrayMutex.unlock(); - String buffer = {(char *)XArena.data, (int64_t)XArena.len}; + String buffer = XGetArenaString(); String find = Prompt; int64_t index = 0; while (Seek(buffer, find, &index, SeekFlag_IgnoreCase)) { String found = {buffer.data + index, find.len}; - Matches.add(found); + Matches.bounded_add(found); buffer = buffer.skip(index + find.len); - if (SearchThreadStopSearching) return; + if (search_thread_stop_searching != SearchThreadStopSearching) break; } } void StartSearchingForMatches() { - SearchThreadStopSearching = true; - WaitUntilCompletion(&MainWorkQueue); - SearchThreadStopSearching = false; + SearchThreadStopSearching += 1; PushWork(&MainWorkQueue, NULL, SearchForMatchesWork); } @@ -37,3 +37,7 @@ Array LockSearchResults() { void UnlockSearchResults() { SearchThreadArrayMutex.unlock(); } + +void InitSearch() { + Matches.reserve(100000); +} \ No newline at end of file