From ee86bdef1fc6c825f77822e7bf0f509493137679 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Wed, 11 Nov 2015 18:31:45 -0500 Subject: [PATCH] replay and natural edits --- 4ed.cpp | 14 +- 4ed_file_view.cpp | 153 +++++++++++++--- 4ed_rendering.cpp | 7 +- 4ed_rendering.h | 1 + buffer/4coder_test_abstract.cpp | 16 ++ buffer/4coder_test_main.cpp | 259 ++++++++++++-------------- buffer/history_to_replay.cpp | 316 ++++++++++++++++++++++++++++++++ buffer/shared_test_config.cpp | 58 ++++++ buffer/shared_test_utils.cpp | 154 ++++++++++++++++ win32_4ed.cpp | 2 +- 10 files changed, 807 insertions(+), 173 deletions(-) create mode 100644 buffer/history_to_replay.cpp create mode 100644 buffer/shared_test_config.cpp create mode 100644 buffer/shared_test_utils.cpp diff --git a/4ed.cpp b/4ed.cpp index 873e8e29..5334ca95 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -655,6 +655,15 @@ COMMAND_DECL(history_forward){ view_history_step(mem, layout, view, hist_forward); } +COMMAND_DECL(save_history){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_MEM(mem); + + file_dump_history(mem, file, "history_data.hst"); +} + COMMAND_DECL(interactive_new){ ProfileMomentFunction(); USE_VARS(vars); @@ -1613,6 +1622,7 @@ update_command_data(App_Vars *vars, Command_Data *cmd){ *cmd = command_data; } + COMPOSE_DECL(compose_write_auto_tab_line){ command_write_character(command, binding); update_command_data(command->vars, command); @@ -1784,6 +1794,8 @@ setup_file_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Co map_add(commands, 'O', MDFR_CTRL, command_reopen); map_add(commands, 's', MDFR_CTRL, command_save); map_add(commands, 'w', MDFR_CTRL, command_interactive_save_as); + + map_add(commands, 'h', MDFR_ALT, command_save_history); } internal void @@ -3199,7 +3211,7 @@ app_step(Thread_Context *thread, Key_Codes *codes, Editing_File *file = vars->working_set.files; for (i32 i = vars->working_set.file_index_count; i > 0; --i, ++file){ if (buffer_good(&file->buffer) && !file->is_dummy){ - file_measure_widths(&vars->mem.general, &file->buffer, vars->style.font); + file_measure_starts_widths(&vars->mem.general, &file->buffer, vars->style.font); } } diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 09461b68..6672029e 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -1221,6 +1221,56 @@ file_grow_starts_as_needed(General_Memory *general, Buffer_Type *buffer, i32 add return result; } +internal void +file_measure_starts_widths(General_Memory *general, Buffer_Type *buffer, Font *font){ + ProfileMomentFunction(); + if (!buffer->line_starts){ + i32 max = buffer->line_max = Kbytes(1); + buffer->line_starts = (i32*)general_memory_allocate(general, max*sizeof(i32), BUBBLE_STARTS); + TentativeAssert(buffer->line_starts); + // TODO(allen): when unable to allocate? + } + if (!buffer->line_widths){ + i32 max = buffer->widths_max = Kbytes(1); + buffer->line_widths = (f32*)general_memory_allocate(general, max*sizeof(f32), BUBBLE_STARTS); + TentativeAssert(buffer->line_starts); + // TODO(allen): when unable to allocate? + } + + Buffer_Measure_Starts state = {}; + while (buffer_measure_starts_widths(&state, buffer, font->advance_data)){ + i32 count = state.count; + i32 max = buffer->line_max; + max = ((max + 1) << 1); + + { + i32 *new_lines = (i32*) + general_memory_reallocate(general, buffer->line_starts, + sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); + + // TODO(allen): when unable to grow? + TentativeAssert(new_lines); + buffer->line_starts = new_lines; + buffer->line_max = max; + } + + { + f32 *new_lines = (f32*) + general_memory_reallocate(general, buffer->line_widths, + sizeof(f32)*count, sizeof(f32)*max, BUBBLE_WIDTHS); + + // TODO(allen): when unable to grow? + TentativeAssert(new_lines); + buffer->line_widths = new_lines; + buffer->widths_max = max; + } + + } + buffer->line_count = state.count; + buffer->widths_count = state.count; +} + +#if 0 internal void file_measure_starts(General_Memory *general, Buffer_Type *buffer){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 @@ -1251,6 +1301,7 @@ file_measure_starts(General_Memory *general, Buffer_Type *buffer){ buffer->line_count = state.count; #endif } +#endif internal void file_remeasure_starts(General_Memory *general, Buffer_Type *buffer, @@ -1298,6 +1349,7 @@ file_grow_widths_as_needed(General_Memory *general, Buffer_Type *buffer){ #endif } +#if 0 internal void file_measure_widths(General_Memory *general, Buffer_Type *buffer, Font *font){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 @@ -1307,6 +1359,7 @@ file_measure_widths(General_Memory *general, Buffer_Type *buffer, Font *font){ buffer_measure_widths(buffer, opad.data, opad.stride); #endif } +#endif internal void file_remeasure_widths(General_Memory *general, Buffer_Type *buffer, Font *font, @@ -1314,8 +1367,7 @@ file_remeasure_widths(General_Memory *general, Buffer_Type *buffer, Font *font, #if BUFFER_EXPERIMENT_SCALPEL <= 3 ProfileMomentFunction(); file_grow_widths_as_needed(general, buffer); - Opaque_Font_Advance opad = get_opaque_font_advance(font); - buffer_remeasure_widths(buffer, opad.data, opad.stride, line_start, line_end, line_shift); + buffer_remeasure_widths(buffer, font->advance_data, line_start, line_end, line_shift); #endif } @@ -1418,9 +1470,8 @@ file_create_from_string(Mem_Options *mem, Editing_File *file, u8 *filename, Font file->font = font; file_synchronize_times(file, filename); - - file_measure_starts(general, &file->buffer); - file_measure_widths(general, &file->buffer, font); + + file_measure_starts_widths(general, &file->buffer, font); file->super_locked = super_locked; if (!super_locked){ @@ -1536,6 +1587,9 @@ file_close(General_Memory *general, Editing_File *file){ general_memory_free(general, file->undo.history.strings); general_memory_free(general, file->undo.history.edits); + + general_memory_free(general, file->undo.children.strings); + general_memory_free(general, file->undo.children.edits); } } @@ -1948,7 +2002,7 @@ file_unpost_history_block(Editing_File *file){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 internal Edit_Step* file_post_history(General_Memory *general, Editing_File *file, - Edit_Step step, bool32 do_merge, bool32 can_merge){ + Edit_Step step, b32 do_merge, b32 can_merge){ Edit_Stack *history = &file->undo.history; Edit_Step *result = 0; @@ -2025,10 +2079,9 @@ view_compute_cursor_from_pos(File_View *view, i32 pos){ Font *font = style->font; real32 max_width = view_compute_width(view); - Opaque_Font_Advance opad = get_opaque_font_advance(font); return buffer_cursor_from_pos(&file->buffer, pos, view->line_wrap_y, - max_width, (real32)font->height, opad.data, opad.stride); + max_width, (real32)font->height, font->advance_data); #else return view->cursor; #endif @@ -2043,10 +2096,9 @@ view_compute_cursor_from_unwrapped_xy(File_View *view, real32 seek_x, real32 see Font *font = style->font; real32 max_width = view_compute_width(view); - Opaque_Font_Advance opad = get_opaque_font_advance(font); return buffer_cursor_from_unwrapped_xy(&file->buffer, seek_x, seek_y, round_down, view->line_wrap_y, - max_width, (real32)font->height, opad.data, opad.stride); + max_width, (real32)font->height, font->advance_data); #else return view->cursor; #endif @@ -2061,10 +2113,9 @@ view_compute_cursor_from_wrapped_xy(File_View *view, real32 seek_x, real32 seek_ Font *font = style->font; real32 max_width = view_compute_width(view); - Opaque_Font_Advance opad = get_opaque_font_advance(font); return buffer_cursor_from_wrapped_xy(&file->buffer, seek_x, seek_y, round_down, view->line_wrap_y, - max_width, (real32)font->height, opad.data, opad.stride); + max_width, (real32)font->height, font->advance_data); #else return view->cursor; #endif @@ -2314,7 +2365,7 @@ file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step } #endif - bool32 can_merge = 0, do_merge = 0; + b32 can_merge = 0, do_merge = 0; switch (step.type){ case ED_NORMAL: { @@ -2334,7 +2385,7 @@ file_update_history_before_edit(Mem_Options *mem, Editing_File *file, Edit_Step undo_stack_pop(&file->undo.undo); - bool32 restore_redos = 0; + b32 restore_redos = 0; Edit_Step *redo_end = 0; if (history_mode == hist_backward && file->undo.edit_history_cursor > 0){ @@ -2502,8 +2553,6 @@ file_do_single_edit(Mem_Options *mem, Editing_File *file, i32 str_len = spec.step.edit.len; i32 scratch_size = partition_remaining(part); - - buffer_rope_check(&file->buffer, part->base + part->pos, scratch_size); Assert(scratch_size > 0); i32 request_amount = 0; @@ -2656,10 +2705,7 @@ view_do_white_batch_edit(Mem_Options *mem, File_View *view, Editing_File *file, // NOTE(allen): meta data { Buffer_Measure_Starts state = {}; - if (buffer_measure_starts(&state, &file->buffer)) Assert(0); - - Opaque_Font_Advance opad = get_opaque_font_advance(file->font); - buffer_measure_widths(&file->buffer, opad.data, opad.stride); + buffer_measure_starts_widths(&state, &file->buffer, file->font->advance_data); } // NOTE(allen): cursor fixing @@ -2769,6 +2815,66 @@ view_redo(Mem_Options *mem, Editing_Layout *layout, File_View *view){ view_undo_redo(mem, layout, view, file, &file->undo.redo, ED_REDO); } +inline u8* +write_data(u8 *ptr, void *x, i32 size){ + memcpy(ptr, x, size); + return (ptr + size); +} + +internal void +file_dump_history(Mem_Options *mem, Editing_File *file, char *filename){ + if (!file->undo.undo.edits) return; + + i32 size = 0; + + size += sizeof(i32); + size += file->undo.undo.edit_count*sizeof(Edit_Step); + size += sizeof(i32); + size += file->undo.redo.edit_count*sizeof(Edit_Step); + size += sizeof(i32); + size += file->undo.history.edit_count*sizeof(Edit_Step); + size += sizeof(i32); + size += file->undo.children.edit_count*sizeof(Buffer_Edit); + + size += sizeof(i32); + size += file->undo.undo.size; + size += sizeof(i32); + size += file->undo.redo.size; + size += sizeof(i32); + size += file->undo.history.size; + size += sizeof(i32); + size += file->undo.children.size; + + Partition *part = &mem->part; + i32 remaining = partition_remaining(part); + if (size < remaining){ + u8 *data, *curs; + data = (u8*)part->base + part->pos; + curs = data; + curs = write_data(curs, &file->undo.undo.edit_count, 4); + curs = write_data(curs, &file->undo.redo.edit_count, 4); + curs = write_data(curs, &file->undo.history.edit_count, 4); + curs = write_data(curs, &file->undo.children.edit_count, 4); + curs = write_data(curs, &file->undo.undo.size, 4); + curs = write_data(curs, &file->undo.redo.size, 4); + curs = write_data(curs, &file->undo.history.size, 4); + curs = write_data(curs, &file->undo.children.size, 4); + + curs = write_data(curs, file->undo.undo.edits, sizeof(Edit_Step)*file->undo.undo.edit_count); + curs = write_data(curs, file->undo.redo.edits, sizeof(Edit_Step)*file->undo.redo.edit_count); + curs = write_data(curs, file->undo.history.edits, sizeof(Edit_Step)*file->undo.history.edit_count); + curs = write_data(curs, file->undo.children.edits, sizeof(Buffer_Edit)*file->undo.children.edit_count); + + curs = write_data(curs, file->undo.undo.strings, file->undo.undo.size); + curs = write_data(curs, file->undo.redo.strings, file->undo.redo.size); + curs = write_data(curs, file->undo.history.strings, file->undo.history.size); + curs = write_data(curs, file->undo.children.strings, file->undo.children.size); + + Assert((i32)(curs - data) == size); + system_save_file((u8*)filename, data, size); + } +} + internal void view_history_step(Mem_Options *mem, Editing_Layout *layout, File_View *view, History_Mode history_mode){ if (view->locked) return; @@ -3838,7 +3944,6 @@ draw_file_view(Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_act Assert(file && !file->is_dummy && buffer_good(&file->buffer)); - Opaque_Font_Advance opad = get_opaque_font_advance(font); b32 tokens_use = 0; Cpp_Token_Stack token_stack = {}; if (file){ @@ -3858,9 +3963,7 @@ draw_file_view(Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_act } Partition *part = &view_->mem->part; - - buffer_rope_check(&file->buffer, part->base + part->pos, partition_remaining(part)); - + Temp_Memory temp = begin_temp_memory(part); partition_align(part, 4); @@ -3870,7 +3973,7 @@ draw_file_view(Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_act i32 count; buffer_get_render_data(&file->buffer, view->line_wrap_y, items, max, &count, (real32)rect.x0, (real32)rect.y0, view->scroll_x, view->scroll_y, !view->unwrapped_lines, - (real32)max_x, (real32)max_y, opad.data, opad.stride, (real32)font->height); + (real32)max_x, (real32)max_y, font->advance_data, (real32)font->height); Assert(count > 0); i32 cursor_begin, cursor_end; diff --git a/4ed_rendering.cpp b/4ed_rendering.cpp index d90a29cd..a3c272f6 100644 --- a/4ed_rendering.cpp +++ b/4ed_rendering.cpp @@ -1,4 +1,4 @@ - /* +/* * Mr. 4th Dimention - Allen Webster * * 12.17.2014 @@ -743,9 +743,8 @@ font_load(Font *font_out, char *filename, i32 pt_size, if (stbtt_FindGlyphIndex(&font, code_point) != 0){ font_out->glyphs[code_point].exists = 1; i32 advance = CEIL32(font_out->chardata[code_point].xadvance); - if (max_advance < advance){ - max_advance = advance; - } + if (max_advance < advance) max_advance = advance; + font_out->advance_data[code_point] = font_out->chardata[code_point].xadvance; } } font_out->advance = max_advance - 1; diff --git a/4ed_rendering.h b/4ed_rendering.h index f2580852..572279e5 100644 --- a/4ed_rendering.h +++ b/4ed_rendering.h @@ -44,6 +44,7 @@ struct Font{ Glyph_Data glyphs[256]; stbtt_bakedchar chardata[256]; + float advance_data[256]; i32 height, ascent, descent, line_skip; i32 advance; u32 tex; diff --git a/buffer/4coder_test_abstract.cpp b/buffer/4coder_test_abstract.cpp index 671ab18b..f7a1fcec 100644 --- a/buffer/4coder_test_abstract.cpp +++ b/buffer/4coder_test_abstract.cpp @@ -138,5 +138,21 @@ delete_top(Buffer_Type *buffer, int len, float *advance_data, void *scratch, int edit(buffer, 0, len, 0, 0, advance_data, scratch, scratch_size); } +void +natural_edits(Buffer_Type *buffer, float *advance_data, Replay *replay, int pos, void *scratch, int scratch_size){ + Edit_Step *steps = replay->replay.edits; + char *base_str = replay->replay.strings; + int edit_count = replay->replay.count; + + for (int i = 0; i < edit_count; ++i){ + Edit_Step step = steps[i]; + + if (step.child_count == 0 && step.edit.end <= buffer_size(buffer)){ + edit(buffer, pos + step.edit.start, pos + step.edit.end, base_str + step.edit.str_start, step.edit.len, + advance_data, scratch, scratch_size); + } + } +} + // BOTTOM diff --git a/buffer/4coder_test_main.cpp b/buffer/4coder_test_main.cpp index c46093ad..46b77b12 100644 --- a/buffer/4coder_test_main.cpp +++ b/buffer/4coder_test_main.cpp @@ -14,39 +14,7 @@ #include "4coder_external_name.h" -#include -#include -#include -#include - -#define inline_4tech inline - -inline_4tech int -CEIL32(float x){ - int extra; - extra = ((x!=(int)(x) && x>0)?1:0); - extra += (int)(x); - return(extra); -} - -inline_4tech int -DIVCEIL32(int n, int d) { - int q = (n/d); - q += (q*d < n); - return(q); -} - -inline_4tech unsigned int -ROUNDPOT32(unsigned int v){ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return(v); -} +#include "shared_test_config.cpp" #ifdef fast_test #define debug_4tech(x) @@ -54,10 +22,6 @@ ROUNDPOT32(unsigned int v){ #endif #define hard_assert_4tech(x) assert(x) -#ifdef __linux__ -#define memzero_4tech(x) memset_4tech(&(x), 0, sizeof(x)) -#endif - #include "4coder_shared.cpp" #include "4coder_golden_array.cpp" #include "4coder_gap_buffer.cpp" @@ -80,6 +44,8 @@ ROUNDPOT32(unsigned int v){ #include "4coder_buffer_abstract.cpp" #undef Buffer_Type +#include "shared_test_utils.cpp" + int int_into_str(char *out, int *rem, unsigned int x){ char *start = out; int size = *rem; @@ -219,42 +185,6 @@ time_int get_time(){ #error Timer not supported on this platform #endif -typedef struct File_Data{ - char *data; - int size; -} File_Data; - -File_Data get_file(const char *filename){ - FILE *file; - File_Data result; - - file = fopen(filename, "rb"); - if (!file){ - printf("error: could not find file %s\n", filename); - exit(1); - } - - fseek(file, 0, SEEK_END); - result.size = ftell(file); - fseek(file, 0, SEEK_SET); - - if (result.size == 0){ - printf("error: file %s was empty\n", filename); - exit(1); - } - - result.data = (char*)malloc(result.size); - fread(result.data, result.size, 1, file); - - fclose(file); - - return(result); -} - -void free_file(File_Data file){ - free(file.data); -} - #define STB_TRUETYPE_IMPLEMENTATION #include "stb_truetype.h" @@ -262,6 +192,7 @@ float* get_font_data(const char *font_file, float *font_height){ float *data = 0; stbtt_bakedchar *baked; File_Data file = get_file(font_file); + if (!file.data) exit(1); if (file.data){ int size = sizeof(*baked)*256; @@ -355,8 +286,7 @@ typedef struct Stats_Log{ #define use_stats_log 0 #endif -void -log_write_int(Stats_Log *log, int x){ +void log_write_int(Stats_Log *log, int x){ #if use_stats_log if (log->error == 0){ if (log->size+4 <= log->max){ @@ -370,8 +300,7 @@ log_write_int(Stats_Log *log, int x){ #endif } -void -log_write_time(Stats_Log *log, time_int x){ +void log_write_time(Stats_Log *log, time_int x){ #if use_stats_log if (log->error == 0){ if (x < 0x7FFFFFFF){ @@ -390,8 +319,7 @@ log_write_time(Stats_Log *log, time_int x){ #endif } -void -log_write_str(Stats_Log *log, char *str, int len){ +void log_write_str(Stats_Log *log, char *str, int len){ #if use_stats_log int up = (len + 3) & ~3; if (log->error == 0){ @@ -407,8 +335,7 @@ log_write_str(Stats_Log *log, char *str, int len){ #endif } -void -log_begin_section(Stats_Log *log, char *name, int name_len){ +void log_begin_section(Stats_Log *log, char *name, int name_len){ #if use_stats_log Log_Section *section; if (log->error == 0){ @@ -433,8 +360,7 @@ log_begin_section(Stats_Log *log, char *name, int name_len){ #endif } -void -log_end_section(Stats_Log *log){ +void log_end_section(Stats_Log *log){ #if use_stats_log if (log->error == 0){ if (log->sec_top > 0){ @@ -447,8 +373,7 @@ log_end_section(Stats_Log *log){ #endif } -void -log_data_item(Stats_Log *log, char *name, int name_len, time_int t){ +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){ @@ -464,8 +389,7 @@ log_data_item(Stats_Log *log, char *name, int name_len, time_int t){ #endif } -void -log_finish(Stats_Log *log){ +void log_finish(Stats_Log *log){ #if use_stats_log assert_4tech(sizeof(external_name) < 512); if (log->error == 0){ @@ -473,15 +397,12 @@ log_finish(Stats_Log *log){ 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_Data log_file; + log_file.data = log->out; + log_file.size = log->size; - 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); - } + save_file(fname, log_file); } else{ printf("\n"); @@ -498,8 +419,7 @@ log_finish(Stats_Log *log){ #define litstr(s) (char*)(s), (sizeof(s)-1) -void -log_time_record(Stats_Log *log, char *name, int name_len, Time_Record record){ +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); @@ -531,8 +451,7 @@ operator/=(Time_Record &r, int x){ #define minify(a,b) if ((a)>(b)) (a) = (b) #define maxify(a,b) if ((a)<(b)) (a) = (b) -void -get_record_statistics(Record_Statistics *stats_out, Time_Record *records, int count){ +void get_record_statistics(Record_Statistics *stats_out, Time_Record *records, int count){ Record_Statistics stats; stats.max = records[0]; stats.min = records[0]; @@ -562,13 +481,11 @@ get_record_statistics(Record_Statistics *stats_out, Time_Record *records, int co int test_is_silenced; -void -silence_test(){ +void silence_test(){ test_is_silenced = 1; } -void -print_record(Time_Record record){ +void print_record(Time_Record record){ printf("%-16s - %25lluus\n%-16s - %25lluus\n%-16s - %25lluus\n%-16s - %25lluus\n", "Golden Array", record.buffer, "Gap Buffer", record.gap_buffer, @@ -576,8 +493,7 @@ print_record(Time_Record record){ "Rope", record.rope_buffer); } -void -print_statistics(Time_Record *records, int count, Record_Statistics *stats_out){ +void print_statistics(Time_Record *records, int count, Record_Statistics *stats_out){ Record_Statistics stats; get_record_statistics(&stats, records, count); if (!test_is_silenced){ @@ -616,8 +532,7 @@ typedef struct Buffer_Set{ #include "4coder_test_abstract.cpp" #undef Buffer_Type -void -log_sample_set(Stats_Log *log, char *name, int name_len, Record_Statistics *stats, +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); @@ -639,8 +554,7 @@ typedef struct Sample_Machine{ int count; } Sample_Machine; -Sample_Machine -begin_machine(int count, void **data, int *max){ +Sample_Machine begin_machine(int count, void **data, int *max){ Sample_Machine result; result.count = count; @@ -652,8 +566,7 @@ begin_machine(int count, void **data, int *max){ return(result); } -void -end_machine(Sample_Machine *machine, Record_Statistics *stats_out, char *func_name){ +void 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"); @@ -669,8 +582,7 @@ time_int stop(Sample_Machine *machine){ return machine->tend - machine->tstart; } -void -initialization_test(Stats_Log *log, Buffer_Set *set, File_Data file, int test_repitions, +void initialization_test(Stats_Log *log, Buffer_Set *set, File_Data file, int test_repitions, void *scratch, int scratch_size, Record_Statistics *stats_out){ Sample_Machine machine; machine = begin_machine(test_repitions, &scratch, &scratch_size); @@ -709,8 +621,7 @@ initialization_test(Stats_Log *log, Buffer_Set *set, File_Data file, int test_re log_sample_set(log, litstr("initialization"), stats_out, machine.samples, machine.count); } -void -measure_starts_widths_test(Stats_Log *log, Buffer_Set *set, int test_repitions, void *scratch, +void 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); @@ -750,8 +661,7 @@ measure_starts_widths_test(Stats_Log *log, Buffer_Set *set, int test_repitions, log_sample_set(log, litstr("measure_starts_widths"), stats_out, machine.samples, machine.count); } -int -page_compare(void *page_1_, void *page_2_, int page_size){ +int 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; @@ -761,8 +671,7 @@ page_compare(void *page_1_, void *page_2_, int page_size){ return result; } -float* -measure_wraps_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, void *scratch, +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); @@ -804,8 +713,7 @@ measure_wraps_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, void return wrap_ys; } -int -cursor_eq(Full_Cursor c1, Full_Cursor c2){ +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 && @@ -815,8 +723,7 @@ cursor_eq(Full_Cursor c1, Full_Cursor c2){ return(result); } -void -full_cursor_test(Stats_Log *log, Buffer_Set *buffers, int pos, +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; @@ -850,8 +757,7 @@ full_cursor_test(Stats_Log *log, Buffer_Set *buffers, int pos, 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, +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; @@ -889,8 +795,7 @@ full_cursor_line_test(Stats_Log *log, Buffer_Set *buffers, int line, int charact 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, +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; @@ -928,8 +833,7 @@ full_cursor_xy_test(Stats_Log *log, Buffer_Set *buffers, float x, float y, int r log_sample_set(log, litstr("full-cursor-seek"), stats_out, machine.samples, machine.count); } -void -word_seek_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, +void word_seek_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, int incremental_position, char *word, int len, void *scratch, int scratch_size, Record_Statistics *stats_out){ Sample_Machine machine; @@ -967,8 +871,7 @@ word_seek_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, log_sample_set(log, litstr("word-seek"), stats_out, machine.samples, machine.count); } -void -stream_check_test(Buffer_Set *buffers, void *scratch, int scratch_size){ +void stream_check_test(Buffer_Set *buffers, void *scratch, int scratch_size){ int i, page_size, size; size = buffer_size(&buffers->buffer); @@ -1022,8 +925,7 @@ stream_check_test(Buffer_Set *buffers, void *scratch, int scratch_size){ } } -void -insert_bottom_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float *advance_data, +void insert_bottom_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float *advance_data, int edit_count, void *scratch, int scratch_size, Record_Statistics *stats_out){ Sample_Machine machine; machine = begin_machine(test_repitions, &scratch, &scratch_size); @@ -1071,8 +973,7 @@ insert_bottom_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, floa log_sample_set(log, litstr("insert-bottom"), stats_out, machine.samples, machine.count); } -void -insert_top_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float *advance_data, +void insert_top_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float *advance_data, int edit_count, void *scratch, int scratch_size, Record_Statistics *stats_out){ Sample_Machine machine; machine = begin_machine(test_repitions, &scratch, &scratch_size); @@ -1120,8 +1021,7 @@ insert_top_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float * log_sample_set(log, litstr("insert-top"), stats_out, machine.samples, machine.count); } -void -delete_bottom_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float *advance_data, +void delete_bottom_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float *advance_data, int edit_count, void *scratch, int scratch_size, Record_Statistics *stats_out){ Sample_Machine machine; machine = begin_machine(test_repitions, &scratch, &scratch_size); @@ -1168,8 +1068,7 @@ delete_bottom_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, floa log_sample_set(log, litstr("delete-bottom"), stats_out, machine.samples, machine.count); } -void -delete_top_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float *advance_data, +void delete_top_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float *advance_data, int edit_count, void *scratch, int scratch_size, Record_Statistics *stats_out){ Sample_Machine machine; machine = begin_machine(test_repitions, &scratch, &scratch_size); @@ -1216,8 +1115,42 @@ delete_top_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float * log_sample_set(log, litstr("delete-top"), stats_out, machine.samples, machine.count); } -void -measure_check_test(Buffer_Set *buffers){ +void natural_edits_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, float *advance_data, + Replay *replay, void *scratch, int scratch_size, Record_Statistics *stats_out){ + Sample_Machine machine; + machine = begin_machine(test_repitions, &scratch, &scratch_size); + + int i, j; + for (i = 0; i < test_repitions; ++i){ + j = i*buffer_size(&buffers->buffer) / (1+test_repitions); + + start(&machine); + natural_edits(&buffers->buffer, advance_data, replay, j, scratch, scratch_size); + machine.samples[i].buffer = stop(&machine); + + start(&machine); + natural_edits(&buffers->gap_buffer, advance_data, replay, j, scratch, scratch_size); + machine.samples[i].gap_buffer = stop(&machine); + + start(&machine); + natural_edits(&buffers->multi_gap_buffer, advance_data, replay, j, scratch, scratch_size); + machine.samples[i].multi_gap_buffer = stop(&machine); + + start(&machine); + natural_edits(&buffers->rope_buffer, advance_data, replay, j, scratch, scratch_size); + machine.samples[i].rope_buffer = stop(&machine); + + if (i == 0){ + stream_check_test(buffers, scratch, scratch_size); + } + } + + end_machine(&machine, stats_out, __FUNCTION__); + + log_sample_set(log, litstr("natural-edits"), stats_out, machine.samples, machine.count); +} + +void measure_check_test(Buffer_Set *buffers){ int count; count = buffers->buffer.line_count; assert_4tech(count == buffers->buffer.widths_count); @@ -1252,13 +1185,33 @@ int main(int argc, char **argv){ Stats_Log log; + int do_replay = 0; + char *replay_filename = 0; + if (argc < 2){ - printf("usage: buffer_test \n"); + printf("usage: buffer_test [-h <.hst file>]\n"); exit(1); } setup(); + for (int i = 3; i < argc; ++i){ + if (do_replay){ + replay_filename = argv[i]; + do_replay = 0; + } + if (strcmp(argv[i], "-h") == 0){ + if (replay_filename != 0){ + printf("found -h twice, ignoring duplicates\n"); + } + else{ + do_replay = 1; + } + } + } + + do_replay = (replay_filename != 0); + log.max = 1 << 20; log.size = 0; log.out = (char*)malloc(log.max); @@ -1273,6 +1226,7 @@ int main(int argc, char **argv){ scratch = malloc(scratch_size); file = get_file(argv[1]); + if (!file.data) exit(1); widths_data = get_font_data("LiberationSans-Regular.ttf", &font_height); max_width = 500.f; @@ -1280,6 +1234,7 @@ int main(int argc, char **argv){ { log_write_str(&log, argv[1], (int)strlen(argv[1])); log_write_int(&log, file.size); + log_write_str(&log, argv[2], (int)strlen(argv[2])); } log_end_section(&log); @@ -1405,6 +1360,26 @@ int main(int argc, char **argv){ } log_end_section(&log); + File_Data replay_file = {}; + Replay replay; + + if (do_replay){ + replay_file = get_file(replay_filename); + prepare_replay(replay_file, &replay); + } + + if (replay_file.data){ + log_begin_section(&log, litstr("natural-edits")); + { + Record_Statistics edits; + natural_edits_test(&log, &buffers, 25, widths_data, &replay, scratch, scratch_size, &edits); + } + log_end_section(&log); + } + else{ + printf("skipped natural-edits test\n"); + } + log_finish(&log); return(0); diff --git a/buffer/history_to_replay.cpp b/buffer/history_to_replay.cpp new file mode 100644 index 00000000..c5f64205 --- /dev/null +++ b/buffer/history_to_replay.cpp @@ -0,0 +1,316 @@ +/* + * Mr. 4th Dimention - Allen Webster + * Four Tech + * + * public domain -- no warranty is offered or implied; use this code at your own risk + * + * 11.11.2015 + * + * Converts code file and saved history from 4coder + * into replay file for the test system. + * + */ + +// TOP + +#include "shared_test_config.cpp" + +#include "4coder_shared.cpp" +#include "4coder_golden_array.cpp" + +#define Buffer_Type Buffer +#include "4coder_buffer_abstract.cpp" + +#include "shared_test_utils.cpp" + +void do_single_edit(Replay *replay, Buffer *buffer, Edit_Step step, char *str, void *scratch, int scratch_size){ + { + Edit_Stack *stack; + char *new_data; + Edit_Step inv_step; + int size, new_max, new_size; + + stack = &replay->replay; + + memzero_4tech(inv_step); + size = 0; + buffer_invert_edit(buffer, step.edit, &inv_step.edit, (char*)scratch, &size, scratch_size); + + assert_4tech(stack->count < replay->ed_max); + stack = &replay->replay; + stack->edits[replay->ed_max - (++stack->count)] = inv_step; + + new_size = stack->size + size; + + if (new_size > replay->str_max){ + new_max = (replay->str_max + size) * 2; + new_data = (char*)malloc(new_max); + memcpy_4tech(new_data + new_max - stack->size, stack->strings + replay->str_max - stack->size, stack->size); + free(stack->strings); + stack->strings = new_data; + replay->str_max = new_max; + } + + memcpy_4tech(stack->strings + replay->str_max - new_size, scratch, size); + stack->size = new_size; + + printf("just wrote: [[ %.*s ]]\n", size, scratch); + } + + int start = step.edit.start; + int end = step.edit.end; + int str_start = step.edit.str_start; + int len = step.edit.len; + + int shift_amount; + int request_amount; + + for (;buffer_replace_range(buffer, start, end, str + str_start, len, &shift_amount, + scratch, scratch_size, &request_amount);){ + void *new_data = 0; + if (request_amount > 0) new_data = malloc(request_amount); + void *old_data = buffer_edit_provide_memory(buffer, new_data, request_amount); + if (old_data) free(old_data); + } +} + +void do_batch_edit(Replay *replay, Buffer *buffer, Edit_Step step, void *scratch, int scratch_size){ + { + Edit_Stack *stack; + Edit_Step inv_step; + + stack = &replay->replay; + + memzero_4tech(inv_step); + inv_step.first_child = step.inverse_first_child; + inv_step.inverse_first_child = step.first_child; + inv_step.child_count = step.inverse_child_count; + inv_step.inverse_child_count = step.child_count; + + assert_4tech(stack->count < replay->ed_max); + stack = &replay->replay; + stack->edits[replay->ed_max - (++stack->count)] = inv_step; + } + + char *str; + Buffer_Edit *batch; + int batch_size; + + int request_amount; + Buffer_Batch_State state; + + str = replay->children.strings; + batch = replay->children.edits + step.first_child; + batch_size = step.child_count; + + memzero_4tech(state); + for (;buffer_batch_edit_step(&state, buffer, batch, str, batch_size, + scratch, scratch_size, &request_amount);){ + void *new_data = 0; + if (request_amount > 0) new_data = malloc(request_amount); + void *old_data = buffer_edit_provide_memory(buffer, new_data, request_amount); + if (old_data) free(old_data); + } +} + +#if 0 + +int main(int argc, char **argv){ + if (argc < 3){ + printf("usage: hst_to_rply \n"); + exit(1); + } + + File_Data history_file, code_file; + history_file = get_file(argv[1]); + code_file = get_file(argv[2]); + + if (!history_file.data || !code_file.data) exit(1); + + History history; + char *curs = history_file.data; + + history.undo.count = read_int(&curs); + history.redo.count = read_int(&curs); + history.history.count = read_int(&curs); + history.children.count = read_int(&curs); + + history.undo.size = read_int(&curs); + history.redo.size = read_int(&curs); + history.history.size = read_int(&curs); + history.children.size = read_int(&curs); + + + history.undo.edits = (Edit_Step*)curs; + curs += sizeof(Edit_Step)*history.undo.count; + + history.redo.edits = (Edit_Step*)curs; + curs += sizeof(Edit_Step)*history.redo.count; + + history.history.edits = (Edit_Step*)curs; + curs += sizeof(Edit_Step)*history.history.count; + + history.children.edits = (Buffer_Edit*)curs; + curs += sizeof(Buffer_Edit)*history.children.count; + + + history.undo.strings = (char*)curs; + curs += history.undo.size; + + history.redo.strings = (char*)curs; + curs += history.redo.size; + + history.history.strings = (char*)curs; + curs += history.history.size; + + history.children.strings = (char*)curs; + curs += history.children.size; + + + void *scratch; + int scratch_size; + scratch_size = 1 << 20; + scratch = malloc(scratch_size); + + + Buffer buffer; + Buffer_Init_Type init; + + memzero_4tech(buffer); + memzero_4tech(init); + for (init = buffer_begin_init(&buffer, code_file.data, code_file.size); + buffer_init_need_more(&init);){ + int page_size = buffer_init_page_size(&init); + page_size = round_up_4tech(page_size, 4 << 10); + void *data = malloc(page_size); + buffer_init_provide_page(&init, data, page_size); + } + buffer_end_init(&init, scratch, scratch_size); + + + Replay replay; + + replay.children = history.children; + replay.ed_max = history.history.count; + replay.replay.edits = (Edit_Step*)malloc(sizeof(Edit_Step)*replay.ed_max); + replay.replay.count = 0; + + replay.str_max = history.history. size * 4; + replay.replay.strings = (char*)malloc(replay.str_max); + replay.replay.size = 0; + + + for (int i = history.history.count - 1; i >= 0; --i){ + Edit_Step step = history.history.edits[i]; + if (step.child_count == 0){ + do_single_edit(&replay, &buffer, step, history.history.strings, scratch, scratch_size); + } + else{ + assert(step.special_type == 1); + do_batch_edit(&replay, &buffer, step, scratch, scratch_size); + } + } + + assert(history.history.count == replay.replay.count); + + int str_start = 0; + for (int i = 0; i < history.history.count; ++i){ + replay.replay.edits[i].edit.str_start = str_start; + str_start += replay.replay.edits[i].edit.len; + } + + File_Data out_file; + out_file.size = 0; + out_file.size += replay.replay.count*sizeof(Edit_Step) + sizeof(int); + out_file.size += replay.replay.size + sizeof(int); + out_file.size += replay.children.count*sizeof(Buffer_Edit) + sizeof(int); + out_file.size += replay.children.size + sizeof(int); + + out_file.data = (char*)malloc(out_file.size); + + curs = out_file.data; + curs = write_int(curs, replay.replay.count); + curs = write_int(curs, replay.children.count); + + curs = write_int(curs, replay.replay.size); + curs = write_int(curs, replay.children.size); + + memcpy(curs, replay.replay.edits, replay.replay.count*sizeof(Edit_Step)); + curs += replay.replay.count*sizeof(Edit_Step); + + memcpy(curs, replay.children.edits, replay.children.count*sizeof(Buffer_Edit)); + curs += replay.children.count*sizeof(Buffer_Edit); + + memcpy(curs, replay.replay.strings + replay.str_max - replay.replay.size, replay.replay.size); + curs += replay.replay.size; + + memcpy(curs, replay.children.strings, replay.children.size); + curs += replay.children.size; + + assert((int)(curs - out_file.data) == out_file.size); + + save_file(argv[3], out_file); + + return(0); +} + +#else + +int main(int argc, char **argv){ + if (argc < 2){ + printf("usage: \n"); + exit(1); + } + + File_Data file = get_file(argv[1]); + //char *curs = file.data; + + Replay replay; + prepare_replay(file, &replay); +#if 0 + replay.replay.count = read_int(&curs); + replay.children.count = read_int(&curs); + replay.replay.size = read_int(&curs); + replay.children.size = read_int(&curs); + + replay.replay.edits = (Edit_Step*)curs; + curs += sizeof(Edit_Step)*replay.replay.count; + + replay.children.edits = (Buffer_Edit*)curs; + curs += sizeof(Buffer_Edit)*replay.children.count; + + replay.replay.strings = curs; + curs += replay.replay.size; + + replay.children.strings = curs; + curs += replay.children.size; + + assert_4tech((int)(curs - file.data) == file.size); +#endif + + for (int i = 0; i < replay.replay.count; ++i){ + Edit_Step step = replay.replay.edits[i]; + if (step.first_child == 0){ + if (step.edit.len > 0 && step.edit.str_start >= 0 && step.edit.str_start < replay.replay.size){ + printf("replace [%d,%d] with %.*s\n", step.edit.start, step.edit.end, + step.edit.len, replay.replay.strings + step.edit.str_start); + } + else if (step.edit.len > 0){ + printf("str_start out of bounds!\n"); + } + else{ + printf("replace [%d,%d] with ~~empty string~~\n", step.edit.start, step.edit.end); + } + } + else{ + printf("batch edit\n"); + } + } + + printf("string section:\n%.*s\n", replay.replay.size, replay.replay.strings); +} + +#endif + +// BOTTOM + diff --git a/buffer/shared_test_config.cpp b/buffer/shared_test_config.cpp new file mode 100644 index 00000000..672a2a5f --- /dev/null +++ b/buffer/shared_test_config.cpp @@ -0,0 +1,58 @@ +/* + * Mr. 4th Dimention - Allen Webster + * Four Tech + * + * public domain -- no warranty is offered or implied; use this code at your own risk + * + * 11.11.2015 + * + * Code shared between history_to_replay.cpp and 4coder_test_main.cpp + * + */ + +// TOP + +#include +#include +#include +#include + +#define inline_4tech inline + +inline_4tech int +CEIL32(float x){ + int extra; + extra = ((x!=(int)(x) && x>0)?1:0); + extra += (int)(x); + return(extra); +} + +inline_4tech int +DIVCEIL32(int n, int d) { + int q = (n/d); + q += (q*d < n); + return(q); +} + +inline_4tech unsigned int +ROUNDPOT32(unsigned int v){ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return(v); +} + +// TODO(allen): this should actually be compiler specific, it doesn't +// have anything to do with platform +#if defined(__linux__) +#define memzero_4tech(x) memset_4tech(&(x), 0, sizeof(x)) +#else +#define memzero_4tech(x) (x = {}) +#endif + +// BOTTOM + diff --git a/buffer/shared_test_utils.cpp b/buffer/shared_test_utils.cpp new file mode 100644 index 00000000..d6e54c56 --- /dev/null +++ b/buffer/shared_test_utils.cpp @@ -0,0 +1,154 @@ +/* + * Mr. 4th Dimention - Allen Webster + * Four Tech + * + * public domain -- no warranty is offered or implied; use this code at your own risk + * + * 11.11.2015 + * + * Code shared between history_to_replay.cpp and 4coder_test_main.cpp + * + */ + +// TOP + +typedef struct File_Data{ + char *data; + int size; +} File_Data; + +File_Data get_file(const char *filename){ + FILE *file; + File_Data result; + + memzero_4tech(result); + + file = fopen(filename, "rb"); + if (!file){ + printf("error: could not find file %s\n", filename); + } + else{ + fseek(file, 0, SEEK_END); + result.size = ftell(file); + fseek(file, 0, SEEK_SET); + + if (result.size == 0){ + printf("error: file %s was empty\n", filename); + } + else{ + result.data = (char*)malloc(result.size); + fread(result.data, result.size, 1, file); + } + + fclose(file); + } + + return(result); +} + +void save_file(const char *fname, File_Data file){ + FILE *f = fopen(fname, "wb"); + if (f){ + fwrite(file.data, 1, file.size, f); + fclose(f); + } + else{ + printf("error: could not open %s\n", fname); + } +} + +void free_file(File_Data file){ + free(file.data); +} + +typedef struct Edit_Step{ + int type; + union{ + struct{ + int can_merge; + Buffer_Edit edit; + int pre_pos; + int post_pos; + int next_block, prev_block; + }; + struct{ + int first_child; + int inverse_first_child; + int inverse_child_count; + int special_type; + }; + }; + int child_count; +} Edit_Step; + +typedef struct Edit_Stack{ + char *strings; + int size; + + Edit_Step *edits; + int count; +} Edit_Stack; + +typedef struct Small_Edit_Stack{ + char *strings; + int size; + + Buffer_Edit *edits; + int count; +} Small_Edit_Stack; + +typedef struct History{ + Edit_Stack undo; + Edit_Stack redo; + Edit_Stack history; + Small_Edit_Stack children; +} History; + +typedef struct Replay{ + Edit_Stack replay; + Small_Edit_Stack children; + + int str_max; + int ed_max; +} Replay; + +int read_int(char **curs){ + int result; + result = *(int*)(*curs); + *curs += 4; + return(result); +} + +char* write_int(char *curs, int x){ + *(int*)(curs) = x; + curs += 4; + return(curs); +} + +void prepare_replay(File_Data file, Replay *replay){ + char *curs = file.data; + + replay->replay.count = read_int(&curs); + replay->children.count = read_int(&curs); + replay->replay.size = read_int(&curs); + replay->children.size = read_int(&curs); + + replay->replay.edits = (Edit_Step*)curs; + curs += sizeof(Edit_Step)*replay->replay.count; + + replay->children.edits = (Buffer_Edit*)curs; + curs += sizeof(Buffer_Edit)*replay->children.count; + + replay->replay.strings = curs; + curs += replay->replay.size; + + replay->children.strings = curs; + curs += replay->children.size; + + assert_4tech((int)(curs - file.data) == file.size); +} + +// BOTTOM + + + diff --git a/win32_4ed.cpp b/win32_4ed.cpp index df08cf5f..01f488e1 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -58,7 +58,7 @@ #define FPS 30 #define FRAME_TIME (1000000 / FPS) -#define BUFFER_EXPERIMENT_SCALPEL 3 +#define BUFFER_EXPERIMENT_SCALPEL 0 #include "4ed_meta.h"