srt, work_queue, mutex
This commit is contained in:
@@ -15,6 +15,7 @@ struct thread_ctx_t {
|
||||
void *te_ctx;
|
||||
|
||||
logger_t log;
|
||||
int thread_index;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -27,7 +27,7 @@ fn void log_basef(log_level_t level, s8_t file_and_line, const char *str, ...);
|
||||
|
||||
#if PLATFORM_DEBUG_ASSERT
|
||||
#define assert_expr(x) (!(x) && (os_error_box(FILE_AND_LINE ": assertion failed: " #x "\n"), debug_break()))
|
||||
#define assert(x) do { static int once = 1; for (;once;once=0) assert_expr(x); } while(0)
|
||||
#define assert(x) do { assert_expr(x); } while(0)
|
||||
#else
|
||||
#define assert_expr(x) (void)(x)
|
||||
#define assert(x) do { (void)(x); } while(0)
|
||||
|
||||
@@ -429,7 +429,14 @@ fn sb8_t s8_split(ma_arena_t *ma, s8_t string, s8_t find, s8_split_t flags) {
|
||||
s8_seek_t find_flag = flags & s8_split_ignore_case ? s8_seek_ignore_case : s8_seek_none;
|
||||
while (s8_seek(string, find, find_flag, &index)) {
|
||||
s8_t before_match = s8_make(string.str, index);
|
||||
sb8_append(&result, before_match);
|
||||
if (flags & s8_split_cleanup) {
|
||||
before_match = s8_trim(before_match);
|
||||
if (before_match.len) {
|
||||
sb8_append(&result, before_match);
|
||||
}
|
||||
} else {
|
||||
sb8_append(&result, before_match);
|
||||
}
|
||||
if (flags & s8_split_inclusive) {
|
||||
s8_t match = s8_make(string.str + index, find.len);
|
||||
sb8_append(&result, match);
|
||||
|
||||
@@ -35,6 +35,7 @@ enum {
|
||||
s8_split_none = 0,
|
||||
s8_split_ignore_case = 1,
|
||||
s8_split_inclusive = 2,
|
||||
s8_split_cleanup = 4,
|
||||
};
|
||||
|
||||
enum { s8_ignore_case = 1 };
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
fn_export b32 app_update(thread_ctx_t *thread_ctx, app_frame_t *frame) {
|
||||
tcx = thread_ctx;
|
||||
if (frame->first_event->kind == app_event_kind_init) {
|
||||
// run_all_tests();
|
||||
run_all_tests();
|
||||
|
||||
mt_tweak_f32(font_size, 30, 4, 200);
|
||||
mt_tweak_f32(_font_size, 30, 30, 30);
|
||||
|
||||
@@ -13,4 +13,5 @@ void run_all_tests(void) {
|
||||
test_array();
|
||||
ui_test_text_replace();
|
||||
buffer16_test();
|
||||
testing_out_things();
|
||||
}// run_all_tests()
|
||||
|
||||
@@ -92,3 +92,223 @@ fn void transcript_browser_update(app_frame_t *frame, mt_tweak_t *tweak_table, i
|
||||
rn_end();
|
||||
ui_end_frame();
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// work queue
|
||||
|
||||
#define WORK_FUNCTION(name) void name(void *data)
|
||||
typedef WORK_FUNCTION(work_queue_callback_t);
|
||||
|
||||
typedef struct {
|
||||
work_queue_callback_t *callback;
|
||||
void *data;
|
||||
} work_queue_entry_t;
|
||||
|
||||
typedef struct work_queue_t work_queue_t;
|
||||
struct work_queue_t {
|
||||
int32_t thread_count;
|
||||
work_queue_entry_t entries[256];
|
||||
int64_t volatile index_to_write;
|
||||
int64_t volatile index_to_read;
|
||||
int64_t volatile completion_index;
|
||||
int64_t volatile completion_goal;
|
||||
void *semaphore;
|
||||
};
|
||||
|
||||
typedef struct thread_startup_info_t thread_startup_info_t;
|
||||
struct thread_startup_info_t {
|
||||
uint32_t thread_id;
|
||||
int32_t thread_index;
|
||||
work_queue_t *queue;
|
||||
};
|
||||
|
||||
fn int64_t atomic_increment(volatile int64_t *i) {
|
||||
return InterlockedIncrement64(i);
|
||||
}
|
||||
|
||||
fn int64_t atomic_compare_and_swap(volatile int64_t *dst, int64_t exchange, int64_t comperand) {
|
||||
return InterlockedCompareExchange64(dst, exchange, comperand);
|
||||
}
|
||||
|
||||
fn void work_queue_push(work_queue_t *wq, void *data, work_queue_callback_t *callback) {
|
||||
uint32_t new_index = (wq->index_to_write + 1) % lengthof(wq->entries);
|
||||
assert(new_index != wq->index_to_read);
|
||||
|
||||
work_queue_entry_t *entry = wq->entries + wq->index_to_write;
|
||||
entry->data = data;
|
||||
entry->callback = callback;
|
||||
|
||||
wq->completion_goal += 1;
|
||||
_WriteBarrier();
|
||||
wq->index_to_write = new_index;
|
||||
ReleaseSemaphore(wq->semaphore, 1, 0);
|
||||
}
|
||||
|
||||
fn b8 work_queue_try_doing_work(work_queue_t *wq) {
|
||||
b8 should_sleep = false;
|
||||
int64_t original_index_to_read = wq->index_to_read;
|
||||
int64_t new_index_to_read = (original_index_to_read + 1) % lengthof(wq->entries);
|
||||
if (original_index_to_read != wq->index_to_write) {
|
||||
int64_t index = atomic_compare_and_swap(&wq->index_to_read, new_index_to_read, original_index_to_read);
|
||||
if (index == original_index_to_read) {
|
||||
work_queue_entry_t *entry = wq->entries + index;
|
||||
entry->callback(entry->data);
|
||||
atomic_increment(&wq->completion_index);
|
||||
}
|
||||
} else {
|
||||
should_sleep = true;
|
||||
}
|
||||
return should_sleep;
|
||||
}
|
||||
|
||||
fn DWORD WINAPI work_queue_thread_entry(LPVOID param) {
|
||||
thread_startup_info_t *ti = (thread_startup_info_t *)param;
|
||||
|
||||
os_core_init();
|
||||
tcx->thread_index = ti->thread_index;
|
||||
for (;;) {
|
||||
if (work_queue_try_doing_work(ti->queue)) {
|
||||
WaitForSingleObject(ti->queue->semaphore, INFINITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void work_queue_init(work_queue_t *queue, uint32_t thread_count, thread_startup_info_t *info) {
|
||||
queue->thread_count = thread_count;
|
||||
queue->index_to_read = 0;
|
||||
queue->index_to_write = 0;
|
||||
queue->completion_index = 0;
|
||||
queue->completion_goal = 0;
|
||||
queue->semaphore = CreateSemaphoreExA(0, 0, thread_count, 0, 0, SEMAPHORE_ALL_ACCESS);
|
||||
assert(queue->semaphore != INVALID_HANDLE_VALUE);
|
||||
|
||||
for (uint32_t i = 0; i < thread_count; i++) {
|
||||
thread_startup_info_t *ti = info + i;
|
||||
ti->thread_index = i;
|
||||
ti->queue = queue;
|
||||
|
||||
DWORD thread_id = 0;
|
||||
HANDLE thread_handle = CreateThread(0, 0, work_queue_thread_entry, ti, 0, &thread_id);
|
||||
assert(thread_handle != INVALID_HANDLE_VALUE);
|
||||
ti->thread_id = thread_id;
|
||||
CloseHandle(thread_handle);
|
||||
}
|
||||
}
|
||||
|
||||
fn b8 work_queue_is_complete(work_queue_t *wq) {
|
||||
b8 result = wq->completion_goal == wq->completion_index;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void work_queue_wait(work_queue_t *wq) {
|
||||
while (!work_queue_is_complete(wq)) {
|
||||
work_queue_try_doing_work(wq);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// mutex
|
||||
|
||||
typedef struct mutex_t mutex_t;
|
||||
struct mutex_t {
|
||||
void *platform;
|
||||
};
|
||||
|
||||
fn mutex_t mutex_create(void) {
|
||||
HANDLE handle = CreateMutex(NULL, FALSE, NULL);
|
||||
assert(handle);
|
||||
mutex_t result = (mutex_t){(void *)handle};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void mutex_destroy(mutex_t mutex) {
|
||||
BOOL result = CloseHandle(mutex.platform);
|
||||
assert(result != 0);
|
||||
unused(result);
|
||||
}
|
||||
|
||||
fn void mutex_lock(mutex_t mutex) {
|
||||
DWORD result = WaitForSingleObject(mutex.platform, INFINITE);
|
||||
assert(result == WAIT_OBJECT_0);
|
||||
unused(result);
|
||||
}
|
||||
|
||||
fn void mutex_unlock(mutex_t mutex) {
|
||||
BOOL result = ReleaseMutex(mutex.platform);
|
||||
assert(result != 0);
|
||||
unused(result);
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// parse srt
|
||||
|
||||
typedef struct srt_entry_t srt_entry_t;
|
||||
struct srt_entry_t {
|
||||
srt_entry_t *next;
|
||||
u16 hour, minute, second;
|
||||
s8_t string;
|
||||
};
|
||||
|
||||
typedef struct srt_result_t srt_result_t;
|
||||
struct srt_result_t {
|
||||
srt_entry_t *first;
|
||||
srt_entry_t *last;
|
||||
};
|
||||
|
||||
srt_result_t srt_parse(ma_arena_t *arena, s8_t filename) {
|
||||
s8_t content = os_read(arena, filename);
|
||||
sb8_t lines = s8_split(arena, content, s8("\n"), s8_split_cleanup);
|
||||
|
||||
// srt format looks like this:
|
||||
// 1
|
||||
// 00:00:01,000 --> 00:00:05,000
|
||||
// This is the first subtitle.
|
||||
//
|
||||
// or:
|
||||
// section number
|
||||
// time interval
|
||||
// text
|
||||
int section_number = 1;
|
||||
srt_result_t result = {0};
|
||||
for (sb8_node_t *it = lines.first; it;) {
|
||||
// parse section number
|
||||
long num = strtol(it->str, NULL, 10);
|
||||
assert(section_number == num);
|
||||
section_number += 1;
|
||||
it = it->next;
|
||||
|
||||
// parse start of time interval
|
||||
srt_entry_t entry = {0};
|
||||
entry.hour = (u16)strtol(it->str, NULL, 10);
|
||||
entry.minute = (u16)strtol(it->str + 3, NULL, 10);
|
||||
entry.second = (u16)strtol(it->str + 6, NULL, 10);
|
||||
it = it->next;
|
||||
|
||||
// parse text
|
||||
s8_t next_section_number = s8_printf(arena, "%d", section_number);
|
||||
while (it && !s8_are_equal(next_section_number, it->string)) {
|
||||
b8 duplicate = result.last && s8_are_equal(it->string, result.last->string);
|
||||
if (!duplicate) {
|
||||
srt_entry_t *entry_copy = ma_push_type(arena, srt_entry_t);
|
||||
entry_copy[0] = entry;
|
||||
entry_copy->string = it->string;
|
||||
SLLQ_APPEND(result.first, result.last, entry_copy);
|
||||
}
|
||||
it = it->next;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn_test void testing_out_things(void) {
|
||||
mutex_t mutex = mutex_create();
|
||||
mutex_lock(mutex);
|
||||
mutex_unlock(mutex);
|
||||
mutex_destroy(mutex);
|
||||
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
srt_result_t result = srt_parse(scratch.arena, s8("D:\\videos\\zizek\\‘Hegel and the Spirit of Distrust’ Sven-Olov Wallenstein & Slavoj Žižek in Conversation [a7gEN-Rxr4c].en.srt"));
|
||||
unused(result);
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
@@ -947,6 +947,4 @@ fn_test void buffer16_test(void) {
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -454,7 +454,9 @@ fn void ui_text_input_draw(ui_box_t *box) {
|
||||
r2f32_t caret_rect = r2f32(co.rect.min.x + size_front.x, co.rect.min.y, co.rect.min.x + size_front.x + 1, co.rect.min.y + ui_em(1));
|
||||
rn_draw_rect(caret_rect, co.text_color);
|
||||
}
|
||||
rn_draw_rect_border(co.rect, co.border_color, box->border_thickness);
|
||||
// rn_draw_rect_border(co.rect, co.border_color, 1);
|
||||
r2f32_t bottom = r2f32_cut_bottom(&co.rect, box->border_thickness);
|
||||
rn_draw_rect(bottom, co.text_color);
|
||||
}
|
||||
|
||||
fn void ui_default_draw_box(ui_box_t *box) {
|
||||
|
||||
Reference in New Issue
Block a user