Optimizing search, buggy BlockArena on emscripten, cleanup MergeSort, address sanitizer, compile web on linux

This commit is contained in:
Krzosa Karol
2025-12-30 11:59:20 +01:00
parent a57ebb49be
commit b140d9c3f1
15 changed files with 92 additions and 142 deletions

View File

@@ -20,6 +20,8 @@ Debug session:
- Should highlight main buffer when clicking on status?
- Report errorf - use coroutine dialogs
- Replace in render layer also
- BlockAllocator something is not working there which only showed after executing OpenCode on many files
- Some bad allocating happening in Clipboard for sure
New UI Session
- Move CommandWindow hooks to hooks

View File

@@ -268,7 +268,7 @@ void AddBlock(BlockArena *arena, size_t size = MiB(1)) {
if (arena->allocator.proc == NULL) {
arena->allocator = GetSystemAllocator();
}
BlockArenaNode *new_block = (BlockArenaNode *)AllocSize(arena->allocator, block_size + sizeof(BlockArenaNode) + 16);
BlockArenaNode *new_block = (BlockArenaNode *)AllocSize(arena->allocator, block_size + sizeof(BlockArenaNode));
Assert(GetAlignOffset((size_t)new_block->start, DEFAULT_ALIGNMENT) == 0);
arena->start = new_block->start;
new_block->end = arena->end = new_block->start + block_size;
@@ -294,9 +294,7 @@ API void Release(BlockArena *arena) {
next = it->next;
Dealloc(arena->allocator, it);
}
bool safe = arena->when_unwinding_make_sure_to_keep_last_block_alive;
MemoryZero(arena, sizeof(BlockArena));
arena->when_unwinding_make_sure_to_keep_last_block_alive = safe;
}
API void Unwind(BlockArena *arena, U8 *pos) {
@@ -307,16 +305,11 @@ API void Unwind(BlockArena *arena, U8 *pos) {
contains = true;
break;
} else {
bool keep = arena->when_unwinding_make_sure_to_keep_last_block_alive && arena->blocks->next == NULL;
if (keep) {
pos = arena->blocks->start;
} else {
arena->blocks = arena->blocks->next;
Dealloc(arena->allocator, it);
}
arena->blocks = arena->blocks->next;
Dealloc(arena->allocator, it);
}
}
Assert(contains || pos == NULL || (arena->when_unwinding_make_sure_to_keep_last_block_alive && pos == arena->blocks->start));
Assert(contains || pos == NULL);
arena->start = pos;
arena->end = arena->blocks ? arena->blocks->end : NULL;
}
@@ -332,8 +325,11 @@ API void *BlockArenaAllocatorProc(void *object, int kind, void *p, size_t size)
return NULL;
}
#if OS_WASM
API void InitScratch() {
}
#else
thread_local VirtualArena ScratchArenas[4];
API void InitScratch() {
for (int i = 0; i < 4; i += 1) {
InitArena(&ScratchArenas[i]);
@@ -362,6 +358,7 @@ API VirtualArena *GetScratchEx(VirtualArena **conflicts, int conflict_count) {
Assert(unoccupied);
return unoccupied;
}
#endif
void RunArenaTest() {
Allocator memory_tracking_allocator = GetTrackingAllocator();
@@ -380,7 +377,6 @@ void RunArenaTest() {
{
BlockArena arena = {};
U8 *start = arena.start;
arena.allocator = memory_tracking_allocator;
int *vals = (int *)PushSize(&arena, sizeof(int) * 32);
for (int i = 0; i < 32; i += 1) vals[i] = i;
@@ -402,7 +398,7 @@ void RunArenaTest() {
U8 *p = arena.start;
U8 *a = (U8 *)PushSize(&arena, KiB(32));
U8 *b = (U8 *)PushSize(&arena, KiB(1000));
PushSize(&arena, KiB(1000));
Assert(arena.blocks);
Assert(arena.blocks->next);
Assert(arena.blocks->next->next == NULL);
@@ -418,7 +414,7 @@ void RunArenaTest() {
{
BlockArena arena = {};
arena.allocator = memory_tracking_allocator;
U8 *a = (U8 *)PushSize(&arena, KiB(2000));
PushSize(&arena, KiB(2000));
Assert((size_t)(arena.blocks[0].end - arena.blocks[0].start) == KiB(2000));
Release(&arena);
Assert(MemoryTrackingRecord.len == 0);
@@ -427,15 +423,14 @@ void RunArenaTest() {
{
BlockArena arena = {};
arena.allocator = memory_tracking_allocator;
arena.when_unwinding_make_sure_to_keep_last_block_alive = true;
PushSize(&arena, KiB(2000));
Unwind(&arena, 0);
Assert(MemoryTrackingRecord.len == 1);
Assert(MemoryTrackingRecord.len == 0);
PushSize(&arena, MiB(1));
PushSize(&arena, MiB(3));
Assert(MemoryTrackingRecord.len == 2);
Unwind(&arena, 0);
Assert(MemoryTrackingRecord.len == 1);
Assert(MemoryTrackingRecord.len == 0);
Release(&arena);
Assert(MemoryTrackingRecord.len == 0);
}

View File

@@ -51,7 +51,6 @@ struct BlockArena {
U8 *end;
BlockArenaNode *blocks;
Allocator allocator;
bool when_unwinding_make_sure_to_keep_last_block_alive;
operator Allocator() { return {BlockArenaAllocatorProc, this}; }
};
@@ -96,9 +95,24 @@ API void Release(VirtualArena *arena);
///////////////////////////////
// Scratch
#if OS_WASM
struct Scratch {
BlockArena arena = {};
Scratch() {}
Scratch(BlockArena *conflict) {}
Scratch(BlockArena *c1, BlockArena *c2) {}
Scratch(Allocator conflict) {}
Scratch(Allocator c1, Allocator c2) {}
~Scratch() { Release(&arena); }
operator BlockArena *() { return &arena; }
operator Allocator() { return arena; }
private: // @Note: Disable copy constructors, cause its error prone
Scratch(Scratch &arena);
Scratch(Scratch &arena, Scratch &a2);
};
#else
extern thread_local VirtualArena ScratchArenas[4];
API VirtualArena *GetScratchEx(VirtualArena **conflicts, int conflict_count);
struct Scratch {
VirtualArena *arena;
U64 p;
@@ -131,6 +145,7 @@ struct Scratch {
Scratch(Scratch &arena);
Scratch(Scratch &arena, Scratch &a2);
};
#endif
const int PAGE_SIZE = 4096;
const int DEFAULT_ALIGNMENT = sizeof(void *);

View File

@@ -408,6 +408,7 @@ API bool IsValid(Process *process) {
int res = poll(&p, 1, 0);
if (res > 0) {
pid_t result = waitpid(plat->pid, &status, 0);
Assert(result != -1);
process->exit_code = WEXITSTATUS(status);
return false;
}
@@ -1104,9 +1105,9 @@ API void Advance(FileIter *it) {
const char *dir_char_ending = it->is_directory ? "/" : "";
const char *separator = it->path.data[it->path.len - 1] == '/' ? "" : "/";
it->relative_path = Format(it->allocator, "%.*s%s%s%s", FmtString(it->path), separator, file->d_name, dir_char_ending);
it->relative_path = Format(it->allocator, "%S%s%s%s", it->path, separator, file->d_name, dir_char_ending);
it->absolute_path = GetAbsolutePath(it->allocator, it->relative_path);
if (it->is_directory) it->absolute_path = Format(it->allocator, "%.*s/", FmtString(it->absolute_path));
if (it->is_directory) it->absolute_path = Format(it->allocator, "%S/", it->absolute_path);
it->is_valid = true;
return;
}

View File

@@ -539,8 +539,8 @@ static void mco_dealloc(void *ptr, size_t size, void *allocator_data) {
#define _MCO_USE_TSAN
#endif
#ifdef _MCO_USE_ASAN
void __sanitizer_start_switch_fiber(void **fake_stack_save, const void *bottom, size_t size);
void __sanitizer_finish_switch_fiber(void *fake_stack_save, const void **bottom_old, size_t *size_old);
extern "C" void __sanitizer_start_switch_fiber(void **fake_stack_save, const void *bottom, size_t size);
extern "C" void __sanitizer_finish_switch_fiber(void *fake_stack_save, const void **bottom_old, size_t *size_old);
#endif
#ifdef _MCO_USE_TSAN
void *__tsan_get_current_fiber(void);

View File

@@ -712,98 +712,52 @@ API void RawAppendf(Buffer *buffer, const char *fmt, ...) {
// multicursor
///////////////////////////////
void MergeSort(int64_t Count, Caret *First, Caret *Temp) {
ProfileFunction();
// SortKey = range.min
if (Count == 1) {
// NOTE(casey): No work to do.
} else if (Count == 2) {
Caret *EntryA = First;
Caret *EntryB = First + 1;
if (EntryA->range.min > EntryB->range.min) {
Swap(EntryA, EntryB);
}
} else {
int64_t Half0 = Count / 2;
int64_t Half1 = Count - Half0;
Assert(Half0 >= 1);
Assert(Half1 >= 1);
Caret *InHalf0 = First;
Caret *InHalf1 = First + Half0;
Caret *End = First + Count;
MergeSort(Half0, InHalf0, Temp);
MergeSort(Half1, InHalf1, Temp);
Caret *ReadHalf0 = InHalf0;
Caret *ReadHalf1 = InHalf1;
Caret *Out = Temp;
for (int64_t Index = 0;
Index < Count;
++Index) {
if (ReadHalf0 == InHalf1) {
*Out++ = *ReadHalf1++;
} else if (ReadHalf1 == End) {
*Out++ = *ReadHalf0++;
} else if (ReadHalf0->range.min < ReadHalf1->range.min) {
*Out++ = *ReadHalf0++;
} else {
*Out++ = *ReadHalf1++;
}
}
Assert(Out == (Temp + Count));
Assert(ReadHalf0 == InHalf1);
Assert(ReadHalf1 == End);
// TODO(casey): Not really necessary if we ping-pong
for (int64_t Index = 0;
Index < Count;
++Index) {
First[Index] = Temp[Index];
}
}
inline bool MergeSortCompare(Caret *EntryA, Caret *EntryB) {
bool result = EntryA->range.min > EntryB->range.min;
return result;
}
void MergeSort(int64_t Count, Edit *First, Edit *Temp) {
inline bool MergeSortCompare(Edit *EntryA, Edit *EntryB) {
bool result = EntryA->range.min > EntryB->range.min;
return result;
}
template<class T>
void MergeSort(int64_t Count, T *First, T *Temp) {
ProfileFunction();
// SortKey = range.min
if (Count == 1) {
// NOTE(casey): No work to do.
} else if (Count == 2) {
Edit *EntryA = First;
Edit *EntryB = First + 1;
if (EntryA->range.min > EntryB->range.min) {
T *EntryA = First;
T *EntryB = First + 1;
if (MergeSortCompare(EntryA, EntryB)) {
Swap(EntryA, EntryB);
}
} else {
int64_t Half0 = Count / 2;
int64_t Half1 = Count - Half0;
Int Half0 = Count / 2;
Int Half1 = Count - Half0;
Assert(Half0 >= 1);
Assert(Half1 >= 1);
Edit *InHalf0 = First;
Edit *InHalf1 = First + Half0;
Edit *End = First + Count;
T *InHalf0 = First;
T *InHalf1 = First + Half0;
T *End = First + Count;
MergeSort(Half0, InHalf0, Temp);
MergeSort(Half1, InHalf1, Temp);
Edit *ReadHalf0 = InHalf0;
Edit *ReadHalf1 = InHalf1;
T *ReadHalf0 = InHalf0;
T *ReadHalf1 = InHalf1;
Edit *Out = Temp;
for (int64_t Index = 0;
Index < Count;
++Index) {
T *Out = Temp;
for (Int Index = 0; Index < Count; ++Index) {
if (ReadHalf0 == InHalf1) {
*Out++ = *ReadHalf1++;
} else if (ReadHalf1 == End) {
*Out++ = *ReadHalf0++;
} else if (ReadHalf0->range.min < ReadHalf1->range.min) {
} else if (!MergeSortCompare(ReadHalf0, ReadHalf1)) {
*Out++ = *ReadHalf0++;
} else {
*Out++ = *ReadHalf1++;
@@ -814,9 +768,7 @@ void MergeSort(int64_t Count, Edit *First, Edit *Temp) {
Assert(ReadHalf1 == End);
// TODO(casey): Not really necessary if we ping-pong
for (int64_t Index = 0;
Index < Count;
++Index) {
for (Int Index = 0; Index < Count; ++Index) {
First[Index] = Temp[Index];
}
}

View File

@@ -48,8 +48,8 @@ struct Buffer {
};
struct FuzzyPair {
Int index;
Int rating;
int32_t index;
int32_t rating;
};
enum {
@@ -130,9 +130,7 @@ API Int GetLineIndent(Buffer *buffer, Int line);
API Int GetIndentAtPos(Buffer *buffer, Int pos);
API Range GetIndentRangeAtPos(Buffer *buffer, Int pos);
API Int FuzzyRate(String16 string, String16 with);
API Array<FuzzyPair> FuzzySearchLines(Allocator allocator, Buffer *buffer, Int line_min, Int line_max, String16 needle);
API Int FindRangeByPos(Array<Range> *ranges, Int pos);
API Int FindRangeByPos(Array<Range> *ranges, Int pos);
// These don't handle history, just raw operations on buffer memory
API void RawReplaceText(Buffer *buffer, Range range, String16 string);

View File

@@ -669,7 +669,6 @@ String Coro_OpenCodeDir;
void Coro_OpenCode(mco_coro *co) {
Array<String> dirs = {CoCurr->arena};
Add(&dirs, Coro_OpenCodeDir);
int i = 0;
for (int diri = 0; diri < dirs.len; diri += 1) {
for (FileIter it = IterateFiles(CoCurr->arena, dirs[diri]); IsValid(it); Advance(&it)) {
bool match = false;

View File

@@ -134,7 +134,6 @@ Trigger *ParseKeyChord(Lexer *lex) {
Trigger *left = ParseKeyAtom(lex);
EatWhitespace(lex);
while (IsAlphanumeric(At(lex))) {
int op = At(lex);
left = TriggerBinary(lex, left, ParseKeyChord(lex), ' ');
EatWhitespace(lex);
}

View File

@@ -294,7 +294,7 @@ void DrawWindow(Window *window, Event &event) {
}
// darken the inactive windows
if (!is_active) {
if (!is_active && !active_layed_out_doc) {
ProfileScope(DarkenInactiveRect);
SetScissor(screen_rect);
DrawRect(window->total_rect, ColorInactiveWindow);

View File

@@ -27,13 +27,13 @@ void CommandWindowLayout(Rect2I *rect, Int wx, Int wy) {
n->document_rect = n->total_rect = CutBottom(rect, barsize);
}
Int FuzzyRate(String16 string, String16 with) {
int32_t FuzzyRate(String16 string, String16 with) {
ProfileFunction();
if (with.len == 0) return 0;
Int points = 0;
Int consecutive = 0;
Int with_i = 0;
for (Int i = 0; i < string.len; i++) {
int32_t points = 0;
int32_t consecutive = 0;
int32_t with_i = 0;
for (int32_t i = 0; i < string.len; i++) {
if (ToLowerCase(string.data[i]) == ToLowerCase(with[with_i])) {
consecutive += 1;
with_i += 1;
@@ -49,33 +49,25 @@ Int FuzzyRate(String16 string, String16 with) {
return points;
}
inline bool MergeSortCompare(FuzzyPair *a, FuzzyPair *b) {
bool result = a->rating > b->rating;
return result;
}
Array<FuzzyPair> FuzzySearchLines(Allocator allocator, Buffer *buffer, Int line_min, Int line_max, String16 needle) {
ProfileFunction();
if (line_min < 0 || line_min >= buffer->line_starts.len) return {};
if (line_max < 0 || line_min > buffer->line_starts.len) return {};
Array<FuzzyPair> ratings = {allocator};
Reserve(&ratings, line_max - line_min + 4);
for (Int i = line_min; i < line_max; i += 1) {
String16 s = GetLineStringWithoutNL(buffer, i);
Int idx = 0;
if (Seek(s, u" || ", &idx)) {
s.len = idx;
}
s = Trim(s);
Int rating = FuzzyRate(s, needle);
Add(&ratings, {i, rating});
}
// bubble sort
for (Int i = 0; i < ratings.len - 1; i++) {
for (Int j = 0; j < ratings.len - 1; j++) {
if (ratings[j].rating > ratings[j + 1].rating) {
FuzzyPair temp = ratings[j];
ratings[j] = ratings[j + 1];
ratings[j + 1] = temp;
}
}
int32_t rating = FuzzyRate(s, needle);
Add(&ratings, {(int32_t)i, rating});
}
Array<FuzzyPair> temp = Copy(allocator, ratings);
MergeSort(ratings.len, ratings.data, temp.data);
return ratings;
}

View File

@@ -97,7 +97,7 @@ void StatusWindowUpdate() {
String16 string_to_replace = GetString(title.buffer, replace_range);
if (string_to_replace != string) {
SelectRange(title.view, replace_range);
Array<Edit> edits = ReplaceEx(scratch, title.view, string);
ReplaceEx(scratch, title.view, string);
}
SelectRange(title.view, MakeRange(0));