diff --git a/buffer/4coder_buffer_abstract.cpp b/buffer/4coder_buffer_abstract.cpp index d55ee6c5..a7174603 100644 --- a/buffer/4coder_buffer_abstract.cpp +++ b/buffer/4coder_buffer_abstract.cpp @@ -985,6 +985,23 @@ buffer_cursor_from_pos(Buffer_Type *buffer, int pos, float *wraps, return(result); } +internal_4tech Full_Cursor +buffer_cursor_from_line_character(Buffer_Type *buffer, int line, int character, float *wraps, + float max_width, float font_height, float *advance_data){ + Full_Cursor result; + int line_index; + + line_index = line - 1; + if (line_index >= buffer->line_count) line_index = buffer->line_count - 1; + if (line_index < 0) line_index = 0; + + result = make_cursor_hint(line_index, buffer->line_starts, wraps, font_height); + result = buffer_cursor_seek(buffer, seek_line_char(line, character), + max_width, font_height, advance_data, result); + + return(result); +} + internal_4tech Full_Cursor buffer_cursor_from_unwrapped_xy(Buffer_Type *buffer, float x, float y, int round_down, float *wraps, float max_width, float font_height, float *advance_data){ @@ -996,8 +1013,8 @@ buffer_cursor_from_unwrapped_xy(Buffer_Type *buffer, float x, float y, int round if (line_index < 0) line_index = 0; result = make_cursor_hint(line_index, buffer->line_starts, wraps, font_height); - result = buffer_cursor_seek(buffer, seek_unwrapped_xy(x, y, round_down), max_width, font_height, - advance_data, result); + result = buffer_cursor_seek(buffer, seek_unwrapped_xy(x, y, round_down), + max_width, font_height, advance_data, result); return(result); } @@ -1010,8 +1027,8 @@ buffer_cursor_from_wrapped_xy(Buffer_Type *buffer, float x, float y, int round_d line_index = buffer_get_line_index_from_wrapped_y(wraps, y, font_height, 0, buffer->line_count); result = make_cursor_hint(line_index, buffer->line_starts, wraps, font_height); - result = buffer_cursor_seek(buffer, seek_wrapped_xy(x, y, round_down), max_width, font_height, - advance_data, result); + result = buffer_cursor_seek(buffer, seek_wrapped_xy(x, y, round_down), + max_width, font_height, advance_data, result); return(result); } diff --git a/buffer/4coder_external_name.h b/buffer/4coder_external_name.h new file mode 100644 index 00000000..afb40263 --- /dev/null +++ b/buffer/4coder_external_name.h @@ -0,0 +1 @@ +#define external_name "awebster_windows" diff --git a/buffer/4coder_test_abstract.cpp b/buffer/4coder_test_abstract.cpp index e0e43fa8..39801040 100644 --- a/buffer/4coder_test_abstract.cpp +++ b/buffer/4coder_test_abstract.cpp @@ -1,67 +1,67 @@ -/* - * Mr. 4th Dimention - Allen Webster - * Four Tech - * - * public domain -- no warranty is offered or implied; use this code at your own risk - * - * 08.11.2015 - * - * Buffer experiment testing layer, abstract portion - * - */ - -// TOP - -#define Buffer_Init_Type cat_4tech(Buffer_Type, _Init) -#define Buffer_Stringify_Type cat_4tech(Buffer_Type, _Stringify_Loop) -#define Buffer_Backify_Type cat_4tech(Buffer_Type, _Backify_Loop) - -void -init_buffer(Buffer_Type *buffer, File_Data file, void *scratch, int scratch_size){ - memzero_4tech(*buffer); - Buffer_Init_Type init; - for (init = buffer_begin_init(buffer, file.data, file.size); - buffer_init_need_more(&init);){ - int page_size = buffer_init_page_size(&init); - void *page = malloc(page_size); - buffer_init_provide_page(&init, page, page_size); - } - debug_4tech(int result =) - buffer_end_init(&init, scratch, scratch_size); - assert_4tech(result); -} - -void -measure_starts_widths(Buffer_Type *buffer, float *font_widths){ - int max = 1 << 10; - buffer->line_starts = (int*)malloc(max*sizeof(int)); - buffer->line_max = max; - buffer->line_widths = (float*)malloc(max*sizeof(float)); - buffer->widths_max = max; - - Buffer_Measure_Starts state; - memzero_4tech(state); - for (;buffer_measure_starts_widths(&state, buffer, font_widths);){ - int max = buffer->line_max; - int count = state.count; - int target = count + 1; - - max = target*2; - int *new_lines = (int*)malloc(max*sizeof(int)); - memcpy_4tech(new_lines, buffer->line_starts, count*sizeof(int)); - free(buffer->line_starts); - buffer->line_starts = new_lines; - buffer->line_max = max; - - float *new_widths = (float*)malloc(max*sizeof(float)); - memcpy_4tech(new_widths, buffer->line_widths, count*sizeof(int)); - free(buffer->line_widths); - buffer->line_widths = new_widths; - buffer->widths_max = max; - } - buffer->line_count = state.count; - buffer->widths_count = state.count; -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * Four Tech + * + * public domain -- no warranty is offered or implied; use this code at your own risk + * + * 08.11.2015 + * + * Buffer experiment testing layer, abstract portion + * + */ + +// TOP + +#define Buffer_Init_Type cat_4tech(Buffer_Type, _Init) +#define Buffer_Stringify_Type cat_4tech(Buffer_Type, _Stringify_Loop) +#define Buffer_Backify_Type cat_4tech(Buffer_Type, _Backify_Loop) + +void +init_buffer(Buffer_Type *buffer, File_Data file, void *scratch, int scratch_size){ + memzero_4tech(*buffer); + Buffer_Init_Type init; + for (init = buffer_begin_init(buffer, file.data, file.size); + buffer_init_need_more(&init);){ + int page_size = buffer_init_page_size(&init); + void *page = malloc(page_size); + buffer_init_provide_page(&init, page, page_size); + } + debug_4tech(int result =) + buffer_end_init(&init, scratch, scratch_size); + assert_4tech(result); +} + +void +measure_starts_widths(Buffer_Type *buffer, float *font_widths){ + int max = 1 << 10; + buffer->line_starts = (int*)malloc(max*sizeof(int)); + buffer->line_max = max; + buffer->line_widths = (float*)malloc(max*sizeof(float)); + buffer->widths_max = max; + + Buffer_Measure_Starts state; + memzero_4tech(state); + for (;buffer_measure_starts_widths(&state, buffer, font_widths);){ + int max = buffer->line_max; + int count = state.count; + int target = count + 1; + + max = target*2; + int *new_lines = (int*)malloc(max*sizeof(int)); + memcpy_4tech(new_lines, buffer->line_starts, count*sizeof(int)); + free(buffer->line_starts); + buffer->line_starts = new_lines; + buffer->line_max = max; + + float *new_widths = (float*)malloc(max*sizeof(float)); + memcpy_4tech(new_widths, buffer->line_widths, count*sizeof(int)); + free(buffer->line_widths); + buffer->line_widths = new_widths; + buffer->widths_max = max; + } + buffer->line_count = state.count; + buffer->widths_count = state.count; +} + +// BOTTOM + diff --git a/buffer/4coder_test_main.cpp b/buffer/4coder_test_main.cpp index 802d1c5e..9c41399e 100644 --- a/buffer/4coder_test_main.cpp +++ b/buffer/4coder_test_main.cpp @@ -12,6 +12,8 @@ // TOP +#include "4coder_external_name.h" + #include #include #include @@ -78,6 +80,51 @@ ROUNDPOT32(unsigned int v){ #include "4coder_buffer_abstract.cpp" #undef Buffer_Type +int int_into_str(char *out, int *rem, unsigned int x){ + char *start = out; + int size = *rem; + int result; + char t; + + if (x == 0 && size > 1){ + *out = '0'; + ++out; + --size; + } + else{ + for (;x > 0 && size > 1;--size, ++out){ + *out = (x%10 + '0'); + x /= 10; + } + } + + *rem = size; + *out = 0; + + result = (int)(out - start); + + --out; + for (; start < out; ++start, --out){ + t = *out; + *out = *start; + *start = t; + } + + return(result); +} + +int uscore_into_str(char *out, int *rem){ + int result; + result = 0; + if (*rem > 1){ + --*rem; + *out++ = '_'; + *out = 0; + result = 1; + } + return(result); +} + #if defined(_WIN32) #include @@ -110,6 +157,33 @@ time_int get_time(){ return(result); } +void time_into_str(char *out, int max){ + SYSTEMTIME systime; + int pos; + + GetSystemTime(&systime); + pos = uscore_into_str(out, &max); + pos += int_into_str(out + pos, &max, systime.wYear); + + pos += uscore_into_str(out + pos, &max); + pos += int_into_str(out + pos, &max, systime.wMonth); + + pos += uscore_into_str(out + pos, &max); + pos += int_into_str(out + pos, &max, systime.wDay); + + pos += uscore_into_str(out + pos, &max); + pos += int_into_str(out + pos, &max, systime.wHour); + + pos += uscore_into_str(out + pos, &max); + pos += int_into_str(out + pos, &max, systime.wMinute); + + pos += uscore_into_str(out + pos, &max); + pos += int_into_str(out + pos, &max, systime.wSecond); + + pos += uscore_into_str(out + pos, &max); + pos += int_into_str(out + pos, &max, systime.wMilliseconds); +} + #elif defined(__linux__) #include @@ -184,36 +258,40 @@ void free_file(File_Data file){ #define STB_TRUETYPE_IMPLEMENTATION #include "stb_truetype.h" -float* get_font_data(const char *font_file){ +float* get_font_data(const char *font_file, float *font_height){ float *data = 0; stbtt_bakedchar *baked; File_Data file = get_file(font_file); - int stride, offset; if (file.data){ int size = sizeof(*baked)*256; baked = (stbtt_bakedchar*)malloc(size); memset_4tech(baked, 0, sizeof(*baked)*256); - - offset = (int)((char*)&baked->xadvance - (char*)baked); - stride = sizeof(*baked); - int w, h; - w = 10*256; - h = 25; - unsigned char *pixels = (unsigned char*)malloc(w * h); - stbtt_BakeFontBitmap((unsigned char*)file.data, 0, 17.f, pixels, w, h, 0, 128, baked); - free(pixels); - free_file(file); + stbtt_fontinfo font; + if (stbtt_InitFont(&font, (unsigned char*)file.data, 0)){ + float scale; + int a,d,g; + + scale = stbtt_ScaleForPixelHeight(&font, 17.f); + stbtt_GetFontVMetrics(&font, &a, &d, &g); + *font_height = scale*(a - d + g); + + int w, h; + w = 10*256; + h = 25; + unsigned char *pixels = (unsigned char*)malloc(w * h); + stbtt_BakeFontBitmap((unsigned char*)file.data, 0, 17.f, pixels, w, h, 0, 128, baked); + free(pixels); + free_file(file); - data = (float*)malloc(sizeof(float)*256); - memset_4tech(data, 0, sizeof(float)*256); - - char *pos = (char*)baked; - pos += offset; - for (int i = 0; i < 128; ++i){ - data[i] = *(float*)pos; - pos += stride; + data = (float*)malloc(sizeof(float)*256); + memset_4tech(data, 0, sizeof(float)*256); + + stbtt_bakedchar *baked_ptr = baked; + for (int i = 0; i < 128; ++i, ++baked_ptr){ + data[i] = baked_ptr->xadvance; + } } free(baked); } @@ -249,6 +327,187 @@ typedef struct Record_Statistics{ int count; } Record_Statistics; +typedef struct Log_Section{ + int *counter; +} Log_Section; + +typedef struct Stats_Log{ + char *out; + int size, max; + + Log_Section *sections; + int sec_top, sec_max; + + unsigned int error; +} Stats_Log; + +#define log_er_buffer_overflow 0x1 +#define log_er_stack_overflow 0x2 +#define log_er_stack_underflow 0x4 +#define log_er_time_too_large 0x8 + +#define logid_begin_section 0 +#define logid_data_item 1 + +#if fast_test +#define use_stats_log 1 +#else +#define use_stats_log 0 +#endif + +void +log_write_int(Stats_Log *log, int x){ +#if use_stats_log + if (log->error == 0){ + if (log->size+4 <= log->max){ + *(int*)(log->out + log->size) = x; + log->size += 4; + } + else{ + log->error |= log_er_buffer_overflow; + } + } +#endif +} + +void +log_write_time(Stats_Log *log, time_int x){ +#if use_stats_log + if (log->error == 0){ + if (x < 0x7FFFFFFF){ + if (log->size+4 <= log->max){ + *(int*)(log->out + log->size) = (int)x; + log->size += 4; + } + else{ + log->error |= log_er_buffer_overflow; + } + } + else{ + log->error |= log_er_time_too_large; + } + } +#endif +} + +void +log_write_str(Stats_Log *log, char *str, int len){ +#if use_stats_log + int up = (len + 3) & ~3; + if (log->error == 0){ + if (log->size+4+up <= log->max){ + *(int*)(log->out + log->size) = up; + memcpy_4tech(log->out + log->size + 4, str, len); + log->size += 4+up; + } + else{ + log->error |= log_er_buffer_overflow; + } + } +#endif +} + +void +log_begin_section(Stats_Log *log, char *name, int name_len){ +#if use_stats_log + Log_Section *section; + if (log->error == 0){ + if (log->sec_top < log->sec_max){ + if (log->sec_top > 0){ + section = log->sections + log->sec_top - 1; + ++section->counter; + } + + section = log->sections + (log->sec_top++); + + log_write_int(log, logid_begin_section); + log_write_str(log, name, name_len); + + section->counter = (int*)(log->out + log->size); + log_write_int(log, 0); + } + else{ + log->error |= log_er_stack_overflow; + } + } +#endif +} + +void +log_end_section(Stats_Log *log){ +#if use_stats_log + if (log->error == 0){ + if (log->sec_top > 0){ + --log->sec_top; + } + else{ + log->error |= log_er_stack_underflow; + } + } +#endif +} + +void +log_data_item(Stats_Log *log, char *name, int name_len, time_int t){ +#if use_stats_log + Log_Section *section; + if (log->error == 0){ + if (log->sec_top > 0){ + section = log->sections + log->sec_top - 1; + ++section->counter; + } + + log_write_int(log, logid_data_item); + log_write_str(log, name, name_len); + log_write_time(log, t); + } +#endif +} + +void +log_finish(Stats_Log *log){ +#if use_stats_log + assert_4tech(sizeof(external_name) < 512); + if (log->error == 0){ + char fname[1024]; + memcpy_4tech(fname, "out/", 4); + memcpy_4tech(fname + 4, external_name, sizeof(external_name)-1); + time_into_str(fname + 4 + sizeof(external_name) - 1, 1023 - sizeof(external_name) + 1); + + FILE *log_out = fopen(fname, "wb"); + if (log_out){ + fwrite(log->out, 1, log->size, log_out); + fclose(log_out); + } + else{ + printf("log error: could not open %s\n", fname); + } + } + else{ + printf("\n"); + if (log->error & log_er_buffer_overflow) + printf("log error: buffer overflow\n"); + if (log->error & log_er_stack_overflow) + printf("log error: stack overflow\n"); + if (log->error & log_er_stack_underflow) + printf("log error: stack underflow\n"); + printf("there were log error so the log was not saved\n\n"); + } +#endif +} + +#define litstr(s) (char*)(s), (sizeof(s)-1) + +void +log_time_record(Stats_Log *log, char *name, int name_len, Time_Record record){ + log_begin_section(log, name, name_len); + log_data_item(log, litstr("golden-array"), record.buffer); + log_data_item(log, litstr("gap-buffer"), record.gap_buffer); + log_data_item(log, litstr("multi-gap-buffer"), record.multi_gap_buffer); + log_data_item(log, litstr("rope"), record.rope_buffer); + log_end_section(log); +} + Time_Record operator+(const Time_Record &a, const Time_Record &b){ Time_Record r; @@ -259,6 +518,16 @@ operator+(const Time_Record &a, const Time_Record &b){ return r; } +Time_Record& +operator/=(Time_Record &r, int x){ + r.buffer /= x; + r.gap_buffer /= x; + r.multi_gap_buffer /= x; + r.rope_buffer /= x; + + return(r); +} + #define minify(a,b) if ((a)>(b)) (a) = (b) #define maxify(a,b) if ((a)<(b)) (a) = (b) @@ -286,10 +555,7 @@ get_record_statistics(Record_Statistics *stats_out, Time_Record *records, int co maxify(stats.max.rope_buffer, record->rope_buffer); } - stats.expected.buffer /= count; - stats.expected.gap_buffer /= count; - stats.expected.multi_gap_buffer /= count; - stats.expected.rope_buffer /= count; + stats.expected /= count; *stats_out = stats; } @@ -350,38 +616,82 @@ typedef struct Buffer_Set{ #include "4coder_test_abstract.cpp" #undef Buffer_Type -#define print_name() printf("%s:\n", __FUNCTION__) +void +log_sample_set(Stats_Log *log, char *name, int name_len, Record_Statistics *stats, + Time_Record *samples, int sample_count){ + log_begin_section(log, name, name_len); + + log_data_item(log, litstr("sample-count"), sample_count); + log_time_record(log, litstr("max"), stats->max); + log_time_record(log, litstr("min"), stats->min); + log_time_record(log, litstr("average"), stats->expected); + + for (int i = 0; i < sample_count; ++i){ + log_time_record(log, litstr("item"), samples[i]); + } + + log_end_section(log); +} + +typedef struct Sample_Machine{ + time_int tstart, tend; + Time_Record *samples; + int count; +} Sample_Machine; + +Sample_Machine +begin_machine(int count, void **data, int *max){ + Sample_Machine result; + + result.count = count; + result.samples = (Time_Record*)*data; + *data = result.samples + count; + assert_4tech(count*sizeof(*result.samples) < *max); + *max -= count*sizeof(*result.samples); + + return(result); +} void -initialization_test(Buffer_Set *set, File_Data file, int test_repitions, +end_machine(Sample_Machine *machine, Record_Statistics *stats_out, char *func_name){ + if (!test_is_silenced) printf("%s\n", func_name); + print_statistics(machine->samples, machine->count, stats_out); + if (!test_is_silenced) printf("\n"); + test_is_silenced = 0; +} + +void start(Sample_Machine *machine){ + machine->tstart = get_time(); +} + +time_int stop(Sample_Machine *machine){ + machine->tend = get_time(); + return machine->tend - machine->tstart; +} + +void +initialization_test(Stats_Log *log, Buffer_Set *set, File_Data file, int test_repitions, void *scratch, int scratch_size, Record_Statistics *stats_out){ - time_int tstart, tend; - Time_Record *init_time = (Time_Record*)scratch; - scratch = init_time + test_repitions; - assert_4tech(test_repitions*sizeof(*init_time) < scratch_size); - scratch_size -= test_repitions*sizeof(*init_time); + Sample_Machine machine; + machine = begin_machine(test_repitions, &scratch, &scratch_size); for (int i = 0; i < test_repitions; ++i){ - tstart = get_time(); + start(&machine); init_buffer(&set->buffer, file, scratch, scratch_size); - tend = get_time(); - init_time[i].buffer = tend - tstart; - - tstart = get_time(); - init_buffer(&set->gap_buffer, file, scratch, scratch_size); - tend = get_time(); - init_time[i].gap_buffer = tend - tstart; - - tstart = get_time(); - init_buffer(&set->multi_gap_buffer, file, scratch, scratch_size); - tend = get_time(); - init_time[i].multi_gap_buffer = tend - tstart; - - tstart = get_time(); - init_buffer(&set->rope_buffer, file, scratch, scratch_size); - tend = get_time(); - init_time[i].rope_buffer = tend - tstart; + machine.samples[i].buffer = stop(&machine); + start(&machine); + init_buffer(&set->gap_buffer, file, scratch, scratch_size); + machine.samples[i].gap_buffer = stop(&machine); + + start(&machine); + init_buffer(&set->multi_gap_buffer, file, scratch, scratch_size); + machine.samples[i].multi_gap_buffer = stop(&machine); + + start(&machine); + init_buffer(&set->rope_buffer, file, scratch, scratch_size); + machine.samples[i].rope_buffer = stop(&machine); + if (i+1 != test_repitions){ free(set->buffer.data); free(set->gap_buffer.data); @@ -394,42 +704,33 @@ initialization_test(Buffer_Set *set, File_Data file, int test_repitions, } } - if (!test_is_silenced) print_name(); - print_statistics(init_time, test_repitions, stats_out); - if (!test_is_silenced) printf("\n"); - test_is_silenced = 0; + end_machine(&machine, stats_out, __FUNCTION__); + + log_sample_set(log, litstr("initialization"), stats_out, machine.samples, machine.count); } void -measure_starts_widths_test(Buffer_Set *set, int test_repitions, - void *scratch, int scratch_size, Record_Statistics *stats_out, - float *font_widths){ - time_int tstart, tend; - Time_Record *measure_time = (Time_Record*)scratch; - scratch = measure_time + test_repitions; - assert_4tech(test_repitions*sizeof(*measure_time) < scratch_size); - scratch_size -= test_repitions*sizeof(*measure_time); +measure_starts_widths_test(Stats_Log *log, Buffer_Set *set, int test_repitions, void *scratch, + int scratch_size, Record_Statistics *stats_out, float *font_widths){ + Sample_Machine machine; + machine = begin_machine(test_repitions, &scratch, &scratch_size); for (int i = 0; i < test_repitions; ++i){ - tstart = get_time(); + start(&machine); measure_starts_widths(&set->buffer, font_widths); - tend = get_time(); - measure_time[i].buffer = tend - tstart; + machine.samples[i].buffer = stop(&machine); - tstart = get_time(); + start(&machine); measure_starts_widths(&set->gap_buffer, font_widths); - tend = get_time(); - measure_time[i].gap_buffer = tend - tstart; - - tstart = get_time(); + machine.samples[i].gap_buffer = stop(&machine); + + start(&machine); measure_starts_widths(&set->multi_gap_buffer, font_widths); - tend = get_time(); - measure_time[i].multi_gap_buffer = tend - tstart; + machine.samples[i].multi_gap_buffer = stop(&machine); - tstart = get_time(); + start(&machine); measure_starts_widths(&set->rope_buffer, font_widths); - tend = get_time(); - measure_time[i].rope_buffer = tend - tstart; + machine.samples[i].rope_buffer = stop(&machine); if (i+1 != test_repitions){ free(set->buffer.line_starts); @@ -444,14 +745,15 @@ measure_starts_widths_test(Buffer_Set *set, int test_repitions, } } - if (!test_is_silenced) print_name(); - print_statistics(measure_time, test_repitions, stats_out); - if (!test_is_silenced) printf("\n"); - test_is_silenced = 0; + end_machine(&machine, stats_out, __FUNCTION__); + + log_sample_set(log, litstr("measure_starts_widths"), stats_out, machine.samples, machine.count); } int -page_compare(char *page_1, char *page_2, int page_size){ +page_compare(void *page_1_, void *page_2_, int page_size){ + char *page_1 = (char*)page_1_; + char *page_2 = (char*)page_2_; int result = 1; for (int i = 0; i < page_size; ++i){ hard_assert_4tech(page_1[i] == page_2[i]); @@ -459,6 +761,173 @@ page_compare(char *page_1, char *page_2, int page_size){ return result; } +float* +measure_wraps_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, void *scratch, + int scratch_size, Record_Statistics *stats_out, float font_height, float max_width){ + Sample_Machine machine; + machine = begin_machine(test_repitions, &scratch, &scratch_size); + + float *wrap_ys, *wrap_ys2; + wrap_ys = (float*)malloc(sizeof(float)*buffers->buffer.line_count); + wrap_ys2 = (float*)malloc(sizeof(float)*buffers->buffer.line_count); + + for (int i = 0; i < test_repitions; ++i){ + start(&machine); + buffer_measure_wrap_y(&buffers->buffer, wrap_ys, font_height, max_width); + machine.samples[i].buffer = stop(&machine); + + start(&machine); + buffer_measure_wrap_y(&buffers->gap_buffer, wrap_ys2, font_height, max_width); + machine.samples[i].gap_buffer = stop(&machine); + if (i == 0) + page_compare((char*)wrap_ys, (char*)wrap_ys2, sizeof(float)*buffers->buffer.line_count); + + start(&machine); + buffer_measure_wrap_y(&buffers->multi_gap_buffer, wrap_ys2, font_height, max_width); + machine.samples[i].multi_gap_buffer = stop(&machine); + if (i == 0) + page_compare((char*)wrap_ys, (char*)wrap_ys2, sizeof(float)*buffers->buffer.line_count); + + start(&machine); + buffer_measure_wrap_y(&buffers->rope_buffer, wrap_ys2, font_height, max_width); + machine.samples[i].rope_buffer = stop(&machine); + if (i == 0) + page_compare((char*)wrap_ys, (char*)wrap_ys2, sizeof(float)*buffers->buffer.line_count); + } + + free(wrap_ys2); + + end_machine(&machine, stats_out, __FUNCTION__); + + log_sample_set(log, litstr("measure-wrap-ys"), stats_out, machine.samples, machine.count); + + return wrap_ys; +} + +int +cursor_eq(Full_Cursor c1, Full_Cursor c2){ + int result = 0; + if (c1.pos == c2.pos && c1.line == c2.line && c1.character == c2.character && + c1.wrapped_x == c2.wrapped_x && c1.wrapped_y == c2.wrapped_y && + c1.unwrapped_x == c2.unwrapped_x && c1.unwrapped_y == c2.unwrapped_y){ + result = 1; + } + return(result); +} + +void +full_cursor_test(Stats_Log *log, Buffer_Set *buffers, int pos, + float *wrap_ys, float *advance_data, float font_height, float max_width, + int test_repitions, void *scratch, int scratch_size, Record_Statistics *stats_out){ + Sample_Machine machine; + machine = begin_machine(test_repitions, &scratch, &scratch_size); + + Full_Cursor cursor, cursor2; + + for (int i = 0; i < test_repitions; ++i){ + start(&machine); + cursor = buffer_cursor_from_pos(&buffers->buffer, pos, wrap_ys, max_width, font_height, advance_data); + machine.samples[i].buffer = stop(&machine); + + start(&machine); + cursor2 = buffer_cursor_from_pos(&buffers->gap_buffer, pos, wrap_ys, max_width, font_height, advance_data); + machine.samples[i].gap_buffer = stop(&machine); + if (i == 0) assert_4tech(cursor_eq(cursor, cursor2)); + + start(&machine); + cursor2 = buffer_cursor_from_pos(&buffers->multi_gap_buffer, pos, wrap_ys, max_width, font_height, advance_data); + machine.samples[i].multi_gap_buffer = stop(&machine); + if (i == 0) assert_4tech(cursor_eq(cursor, cursor2)); + + start(&machine); + cursor2 = buffer_cursor_from_pos(&buffers->rope_buffer, pos, wrap_ys, max_width, font_height, advance_data); + machine.samples[i].rope_buffer = stop(&machine); + if (i == 0) assert_4tech(cursor_eq(cursor, cursor2)); + } + + end_machine(&machine, stats_out, __FUNCTION__); + + log_sample_set(log, litstr("full-cursor-seek"), stats_out, machine.samples, machine.count); +} + +void +full_cursor_line_test(Stats_Log *log, Buffer_Set *buffers, int line, int character, + float *wrap_ys, float *advance_data, float font_height, float max_width, + int test_repitions, void *scratch, int scratch_size, Record_Statistics *stats_out){ + Sample_Machine machine; + machine = begin_machine(test_repitions, &scratch, &scratch_size); + + Full_Cursor cursor, cursor2; + + for (int i = 0; i < test_repitions; ++i){ + start(&machine); + cursor = buffer_cursor_from_line_character(&buffers->buffer, line, character, + wrap_ys, max_width, font_height, advance_data); + machine.samples[i].buffer = stop(&machine); + + start(&machine); + cursor2 = buffer_cursor_from_line_character(&buffers->gap_buffer, line, character, + wrap_ys, max_width, font_height, advance_data); + machine.samples[i].gap_buffer = stop(&machine); + if (i == 0) assert_4tech(cursor_eq(cursor, cursor2)); + + start(&machine); + cursor2 = buffer_cursor_from_line_character(&buffers->multi_gap_buffer, line, character, + wrap_ys, max_width, font_height, advance_data); + machine.samples[i].multi_gap_buffer = stop(&machine); + if (i == 0) assert_4tech(cursor_eq(cursor, cursor2)); + + start(&machine); + cursor2 = buffer_cursor_from_line_character(&buffers->rope_buffer, line, character, + wrap_ys, max_width, font_height, advance_data); + machine.samples[i].rope_buffer = stop(&machine); + if (i == 0) assert_4tech(cursor_eq(cursor, cursor2)); + } + + end_machine(&machine, stats_out, __FUNCTION__); + + log_sample_set(log, litstr("full-cursor-seek"), stats_out, machine.samples, machine.count); +} + +void +full_cursor_xy_test(Stats_Log *log, Buffer_Set *buffers, float x, float y, int round_down, + float *wrap_ys, float *advance_data, float font_height, float max_width, + int test_repitions, void *scratch, int scratch_size, Record_Statistics *stats_out){ + Sample_Machine machine; + machine = begin_machine(test_repitions, &scratch, &scratch_size); + + Full_Cursor cursor, cursor2; + + for (int i = 0; i < test_repitions; ++i){ + start(&machine); + cursor = buffer_cursor_from_unwrapped_xy(&buffers->buffer, x, y, round_down, + wrap_ys, max_width, font_height, advance_data); + machine.samples[i].buffer = stop(&machine); + + start(&machine); + cursor2 = buffer_cursor_from_unwrapped_xy(&buffers->gap_buffer, x, y, round_down, + wrap_ys, max_width, font_height, advance_data); + machine.samples[i].gap_buffer = stop(&machine); + if (i == 0) assert_4tech(cursor_eq(cursor, cursor2)); + + start(&machine); + cursor2 = buffer_cursor_from_unwrapped_xy(&buffers->multi_gap_buffer, x, y, round_down, + wrap_ys, max_width, font_height, advance_data); + machine.samples[i].multi_gap_buffer = stop(&machine); + if (i == 0) assert_4tech(cursor_eq(cursor, cursor2)); + + start(&machine); + cursor2 = buffer_cursor_from_unwrapped_xy(&buffers->rope_buffer, x, y, round_down, + wrap_ys, max_width, font_height, advance_data); + machine.samples[i].rope_buffer = stop(&machine); + if (i == 0) assert_4tech(cursor_eq(cursor, cursor2)); + } + + end_machine(&machine, stats_out, __FUNCTION__); + + log_sample_set(log, litstr("full-cursor-seek"), stats_out, machine.samples, machine.count); +} + void stream_check_test(Buffer_Set *buffers, void *scratch, int scratch_size){ int i, page_size, size; @@ -514,39 +983,161 @@ stream_check_test(Buffer_Set *buffers, void *scratch, int scratch_size){ } } +void +measure_check_test(Buffer_Set *buffers){ + int count; + count = buffers->buffer.line_count; + assert_4tech(count == buffers->buffer.widths_count); + + assert_4tech(count == buffers->gap_buffer.line_count); + assert_4tech(count == buffers->multi_gap_buffer.line_count); + assert_4tech(count == buffers->rope_buffer.line_count); + + assert_4tech(count == buffers->gap_buffer.widths_count); + assert_4tech(count == buffers->multi_gap_buffer.widths_count); + assert_4tech(count == buffers->rope_buffer.widths_count); + + page_compare(buffers->buffer.line_starts, buffers->gap_buffer.line_starts, sizeof(int)*count); + page_compare(buffers->buffer.line_starts, buffers->multi_gap_buffer.line_starts, sizeof(int)*count); + page_compare(buffers->buffer.line_starts, buffers->rope_buffer.line_starts, sizeof(int)*count); + + page_compare(buffers->buffer.line_widths, buffers->gap_buffer.line_widths, sizeof(float)*count); + page_compare(buffers->buffer.line_widths, buffers->multi_gap_buffer.line_widths, sizeof(float)*count); + page_compare(buffers->buffer.line_widths, buffers->rope_buffer.line_widths, sizeof(float)*count); +} + int main(int argc, char **argv){ Buffer_Set buffers; File_Data file; float *widths_data; + float *wrap_ys; + float font_height; + float max_width; void *scratch; int scratch_size; + Stats_Log log; + if (argc < 2){ printf("usage: buffer_test \n"); exit(1); } setup(); + + log.max = 1 << 20; + log.size = 0; + log.out = (char*)malloc(log.max); + + log.sec_max = 32; + log.sec_top = 0; + log.sections = (Log_Section*)malloc(sizeof(Log_Section)*log.sec_max); + + log.error = 0; scratch_size = 1 << 20; scratch = malloc(scratch_size); file = get_file(argv[1]); - widths_data = get_font_data("LiberationSans-Regular.ttf"); + widths_data = get_font_data("LiberationSans-Regular.ttf", &font_height); + max_width = 500.f; - Record_Statistics init_rec, starts_widths_rec; + log_begin_section(&log, litstr("which-test")); + { + log_write_str(&log, argv[1], (int)strlen(argv[1])); + log_write_int(&log, file.size); + } + log_end_section(&log); - initialization_test(&buffers, file, 100, scratch, scratch_size, &init_rec); - stream_check_test(&buffers, scratch, scratch_size); + log_begin_section(&log, litstr("file-open")); + { + Record_Statistics init_rec, starts_widths_rec, wraps_rec; - measure_starts_widths_test(&buffers, 100, scratch, scratch_size, &starts_widths_rec, widths_data); + initialization_test(&log, &buffers, file, 25, scratch, scratch_size, &init_rec); + stream_check_test(&buffers, scratch, scratch_size); - Time_Record expected_file_open; - expected_file_open = init_rec.expected + starts_widths_rec.expected; + measure_starts_widths_test(&log, &buffers, 25, scratch, scratch_size, &starts_widths_rec, widths_data); + measure_check_test(&buffers); + + wrap_ys = measure_wraps_test(&log, &buffers, 25, scratch, scratch_size, &wraps_rec, font_height, max_width); - printf("average file open:\n"); - print_record(expected_file_open); + Time_Record expected_file_open; + expected_file_open = init_rec.expected + starts_widths_rec.expected + wraps_rec.expected; + + printf("average file open:\n"); + print_record(expected_file_open); + printf("\n"); + log_time_record(&log, litstr("average"), expected_file_open); + } + log_end_section(&log); + + log_begin_section(&log, litstr("cursor-seek")); + { + Record_Statistics full_cursor; + Time_Record full_cursor_average; + + log_begin_section(&log, litstr("to-pos")); + { + memzero_4tech(full_cursor_average); + for (int i = 0; i < 5; ++i){ + silence_test(); + int pos = (file.size*i) / 5; + full_cursor_test(&log, &buffers, pos, + wrap_ys, widths_data, font_height, max_width, + 5, scratch, scratch_size, &full_cursor); + full_cursor_average = full_cursor_average + full_cursor.expected; + } + full_cursor_average /= 5; + printf("average cursor from position:\n"); + print_record(full_cursor_average); + printf("\n"); + log_time_record(&log, litstr("average"), full_cursor_average); + } + log_end_section(&log); + + log_begin_section(&log, litstr("to-line-character")); + { + memzero_4tech(full_cursor_average); + for (int i = 0; i < 5; ++i){ + silence_test(); + int line = (buffers.buffer.line_count*i) / 5; + full_cursor_line_test(&log, &buffers, line, 20, + wrap_ys, widths_data, font_height, max_width, + 5, scratch, scratch_size, &full_cursor); + full_cursor_average = full_cursor_average + full_cursor.expected; + } + full_cursor_average /= 5; + printf("average cursor from line & character:\n"); + print_record(full_cursor_average); + printf("\n"); + log_time_record(&log, litstr("average"), full_cursor_average); + } + log_end_section(&log); + + log_begin_section(&log, litstr("to-unwrapped-x-y")); + { + memzero_4tech(full_cursor_average); + for (int i = 0; i < 5; ++i){ + silence_test(); + float y = font_height * (buffers.buffer.line_count*i) / 4.f; + full_cursor_xy_test(&log, &buffers, y, 37.f, 0, + wrap_ys, widths_data, font_height, max_width, + 5, scratch, scratch_size, &full_cursor); + full_cursor_average = full_cursor_average + full_cursor.expected; + } + full_cursor_average /= 5; + printf("average cursor from line & character:\n"); + print_record(full_cursor_average); + printf("\n"); + log_time_record(&log, litstr("average"), full_cursor_average); + } + log_end_section(&log); + + } + log_end_section(&log); + + log_finish(&log); return(0); }