/* * Mr. 4th Dimention - Allen Webster * Four Tech * * public domain -- no warranty is offered or implied; use this code at your own risk * * 03.11.2015 * * Buffer data object * type - Rope * */ // TOP typedef struct Rope_Node{ int left, right, parent; int left_weight, weight; int str_start; } Rope_Node; typedef struct Rope_String{ int next_free; } Rope_String; #define rope_string_full_size 256 #define rope_string_width (rope_string_full_size-sizeof(Rope_String)) typedef struct Rope_Buffer_Edit_State{ int left, right, throw_away, middle; } Rope_Buffer_Edit_State; typedef struct Rope_Buffer{ void *data; int free_rope_string; int string_count; Rope_Node *nodes; int free_rope_node; int node_count; float *line_widths; int *line_starts; int line_count; int widths_count; int line_max; int widths_max; int grow_string_memory; int edit_stage; Rope_Buffer_Edit_State edit_state; } Rope_Buffer; inline_4tech int buffer_good(Rope_Buffer *buffer){ int good; good = (buffer->data != 0); return(good); } inline_4tech int buffer_size(Rope_Buffer *buffer){ int size; size = buffer->nodes->left_weight; return(size); } typedef struct{ Rope_Buffer *buffer; char *data; int size; int rope_string_count; int node_count; } Rope_Buffer_Init; internal_4tech Rope_Buffer_Init buffer_begin_init(Rope_Buffer *buffer, char *data, int size){ Rope_Buffer_Init init; init.buffer = buffer; init.data = data; init.size = eol_in_place_convert_in(data, size); init.node_count = div_ceil_4tech(size, rope_string_width); if (init.node_count < 4){ init.node_count = 7; init.rope_string_count = 4; } else{ init.rope_string_count = round_pot_4tech(init.node_count); init.node_count = init.rope_string_count*2; } return(init); } internal_4tech int buffer_init_need_more(Rope_Buffer_Init *init){ Rope_Buffer *buffer; int result; buffer = init->buffer; result = 1; if (buffer->data != 0 && buffer->nodes != 0) result = 0; return(result); } inline_4tech int buffer_init_page_size(Rope_Buffer_Init *init){ Rope_Buffer *buffer; int result; buffer = init->buffer; if (buffer->data) result = init->node_count*sizeof(Rope_Node); else result = init->rope_string_count*rope_string_full_size; return(result); } internal_4tech void buffer_init_provide_page(Rope_Buffer_Init *init, void *page, int page_size){ Rope_Buffer *buffer; buffer = init->buffer; if (buffer->data){ assert_4tech(buffer->nodes == 0); assert_4tech(page_size >= init->node_count*sizeof(Rope_Node)); buffer->nodes = (Rope_Node*)page; init->node_count = page_size / sizeof(Rope_Node); } else{ assert_4tech(page_size >= init->rope_string_count*rope_string_full_size); buffer->data = page; init->rope_string_count = page_size / rope_string_full_size; } } internal_4tech int buffer_alloc_rope_string(Rope_Buffer *buffer, int *result){ Rope_String *rope_string; int success; success = 0; if (buffer->free_rope_string >= 0){ success = 1; *result = buffer->free_rope_string; rope_string = (Rope_String*)((char*)buffer->data + *result); buffer->free_rope_string = rope_string->next_free; *result += sizeof(Rope_String); } return(success); } internal_4tech void buffer_free_rope_string(Rope_Buffer *buffer, int str_start){ Rope_String *rope_string; str_start -= sizeof(Rope_String); rope_string = (Rope_String*)((char*)buffer->data + str_start); rope_string->next_free = buffer->free_rope_string; buffer->free_rope_string = str_start; } internal_4tech int buffer_alloc_rope_node(Rope_Buffer *buffer, int *result){ Rope_Node *node; int success; success = 0; if (buffer->free_rope_node > 0){ success = 1; *result = buffer->free_rope_node; node = buffer->nodes + *result; buffer->free_rope_node = node->parent; } return(success); } internal_4tech void buffer_free_rope_node(Rope_Buffer *buffer, int node_index){ Rope_Node *node; node = buffer->nodes + node_index; node->parent = buffer->free_rope_node; buffer->free_rope_node = node_index; } inline_4tech void buffer_node_check(Rope_Buffer *buffer, int node_index){ Rope_Node *nodes, *node; nodes = buffer->nodes; node = nodes + node_index; assert_4tech(node->left == 0 || nodes[node->left].parent == node_index); assert_4tech(node->right == 0 || nodes[node->right].parent == node_index); assert_4tech((node->left == 0 && node->right == 0) || (node->left != 0 && node->right != 0)); } internal_4tech void buffer_cheap_check(Rope_Buffer *buffer){ Rope_Node *nodes; nodes = buffer->nodes; assert_4tech(nodes->parent == 0); assert_4tech(nodes->right == 0); assert_4tech(nodes->left != 0); assert_4tech(nodes->weight == nodes->left_weight); } internal_4tech void buffer_rope_check(Rope_Buffer *buffer, void *scratch, int scratch_size){ int *int_stack; Rope_Node *node, *l, *r, *nodes; int top, max_stack; int node_index; nodes = buffer->nodes; int_stack = (int*)scratch; top = 0; max_stack = scratch_size / sizeof(int); buffer_cheap_check(buffer); int_stack[top++] = nodes->left; for (;top > 0;){ node_index = int_stack[--top]; node = nodes + node_index; if (node->left || node->right){ assert_4tech(node->left && node->right); int_stack[top++] = node->left; int_stack[top++] = node->right; l = nodes + node->left; assert_4tech(l->parent == node_index); r = nodes + node->right; assert_4tech(r->parent == node_index); assert_4tech(l->weight + r->weight == node->weight); assert_4tech(l->weight == node->left_weight); } } } typedef struct Rope_Construct_Stage{ int parent_index; int is_right_side; int weight; } Rope_Construct_Stage; inline_4tech Rope_Construct_Stage buffer_construct_stage(int parent, int right, int weight){ Rope_Construct_Stage result; result.parent_index = parent; result.is_right_side = right; result.weight = weight; return(result); } internal_4tech void buffer_free_tree(Rope_Buffer *buffer, int node_index, void *scratch, int scratch_size){ Rope_Node *nodes, *node; int *int_stack; int top, stack_max; int_stack = (int*)scratch; stack_max = scratch_size / sizeof(int); top = 0; nodes = buffer->nodes; int_stack[top++] = node_index; for (;top > 0;){ node_index = int_stack[--top]; node = nodes + node_index; assert_4tech(top < stack_max); if (node->left) int_stack[top++] = node->left; assert_4tech(top < stack_max); if (node->right) int_stack[top++] = node->right; if (node->str_start) buffer_free_rope_string(buffer, node->str_start); buffer_free_rope_node(buffer, node_index); } } internal_4tech int buffer_build_tree(Rope_Buffer *buffer, char *str, int len, int root, void *scratch, int scratch_size, int *request_amount){ Rope_Construct_Stage *stack, *stage; Rope_Node *node, *nodes, *parent; char *dest; int top, stack_max; int result; int node_index; int is_right_side; int read_pos; nodes = buffer->nodes; stack = (Rope_Construct_Stage*)scratch; stack_max = scratch_size / sizeof(Rope_Construct_Stage); top = 0; result = 1; read_pos = 0; stack[top++] = buffer_construct_stage(root, 0, len); for (;top > 0;){ stage = stack + (--top); if (buffer_alloc_rope_node(buffer, &node_index)){ node = nodes + node_index; node->parent = stage->parent_index; node->weight = stage->weight; node->left = 0; node->right = 0; node->str_start = 0; is_right_side = stage->is_right_side; parent = nodes + node->parent; if (is_right_side) parent->right = node_index; else parent->left = node_index; if (stage->weight > rope_string_width){ node->str_start = 0; node->left_weight = stage->weight / 2; assert_4tech(top < stack_max); stack[top++] = buffer_construct_stage(node_index, 1, node->weight - node->left_weight); assert_4tech(top < stack_max); stack[top++] = buffer_construct_stage(node_index, 0, node->left_weight); } else{ node->left_weight = 0; if (buffer_alloc_rope_string(buffer, &node->str_start)){ dest = (char*)buffer->data + node->str_start; assert_4tech(read_pos <= len); memcpy_4tech(dest, str + read_pos, node->weight); read_pos += node->weight; } else{ result = 0; if (request_amount){ buffer->grow_string_memory = 1; *request_amount = buffer->string_count*rope_string_full_size*2; } break; } } } else{ result = 0; if (request_amount){ buffer->grow_string_memory = 0; *request_amount = buffer->node_count*sizeof(Rope_Node)*2; } break; } } if (!result && request_amount){ node = nodes + root; if (node->left){ buffer_free_tree(buffer, node->left, scratch, scratch_size); } } return(result); } internal_4tech int buffer_end_init(Rope_Buffer_Init *init, void *scratch, int scratch_size){ Rope_Buffer *buffer; Rope_String *rope_string; Rope_Node *node; int i; int result; int count; result = 0; buffer = init->buffer; if (buffer->nodes && buffer->data){ buffer->string_count = init->rope_string_count; buffer->free_rope_string = 0; rope_string = (Rope_String*)buffer->data; count = init->rope_string_count; for (i = 0; i < count-1; ++i){ rope_string->next_free = rope_string_full_size*(i+1); rope_string = (Rope_String*)((char*)rope_string + rope_string_full_size); } rope_string->next_free = -1; buffer->node_count = init->node_count; buffer->free_rope_node = 1; node = buffer->nodes + 1; count = init->node_count; for (i = 1; i < count-1; ++i, ++node){ node->parent = i+1; } node->parent = 0; result = 1; node = buffer->nodes; memzero_4tech(*node); node->weight = init->size; node->left_weight = init->size; result = buffer_build_tree(buffer, init->data, init->size, 0, scratch, scratch_size, 0); } return(result); } internal_4tech int buffer_find_node(Rope_Buffer *buffer, int pos, int *node_start){ Rope_Node *nodes, *node; *node_start = 0; nodes = buffer->nodes; node = nodes + nodes->left; for (;node->str_start == 0;){ if (pos < node->left_weight){ node = nodes + node->left; } else{ *node_start += node->left_weight; pos -= node->left_weight; node = nodes + node->right; } } return (int)(node - nodes); } typedef struct Rope_Buffer_Stringify_Loop{ Rope_Buffer *buffer; char *data; int absolute_pos; int next_absolute_pos; int size; int pos, end_pos; int node, node_end; } Rope_Buffer_Stringify_Loop; internal_4tech Rope_Buffer_Stringify_Loop buffer_stringify_loop(Rope_Buffer *buffer, int start, int end){ Rope_Buffer_Stringify_Loop result; Rope_Node *node; int size, node_start_pos, temp_end; size = buffer_size(buffer); if (0 <= start && start < end && end <= size){ result.buffer = buffer; result.absolute_pos = start; result.node = buffer_find_node(buffer, start, &node_start_pos); result.pos = start - node_start_pos; result.node_end = buffer_find_node(buffer, end, &node_start_pos); result.end_pos = end - node_start_pos; node = buffer->nodes + result.node; temp_end = node->weight; if (result.node == result.node_end) temp_end = result.end_pos; result.data = (char*)buffer->data + node->str_start + result.pos; result.size = temp_end - result.pos; } else result.buffer = 0; return(result); } inline_4tech int buffer_stringify_good(Rope_Buffer_Stringify_Loop *loop){ int result; result = (loop->buffer != 0); return(result); } internal_4tech void buffer_stringify_next(Rope_Buffer_Stringify_Loop *loop){ Rope_Node *node, *child, *nodes; int temp_end; if (loop->node == loop->node_end && loop->pos + loop->size == loop->end_pos){ loop->buffer = 0; } else{ nodes = loop->buffer->nodes; node = nodes + loop->node; for (;;){ assert_4tech(node->parent != 0); child = node; node = nodes + node->parent; if (nodes + node->left == child){ break; } else{ assert_4tech(nodes + node->right == child); } } node = nodes + node->right; for (;node->left;){ node = nodes + node->left; } loop->pos = 0; loop->node = (int)(node - nodes); loop->absolute_pos += loop->size; temp_end = node->weight; if (loop->node == loop->node_end) temp_end = loop->end_pos; loop->size = temp_end; loop->data = (char*)loop->buffer->data + node->str_start; } } typedef struct Rope_Buffer_Backify_Loop{ Rope_Buffer *buffer; char *data; int absolute_pos; int size; int pos, end_pos; int node, node_end; } Rope_Buffer_Backify_Loop; internal_4tech Rope_Buffer_Backify_Loop buffer_backify_loop(Rope_Buffer *buffer, int start, int end){ Rope_Buffer_Backify_Loop result; int size, node_start_pos, temp_end; size = buffer_size(buffer); ++start; if (0 <= end && end < start && start <= size){ result.buffer = buffer; result.node_end = buffer_find_node(buffer, end, &node_start_pos); result.end_pos = end - node_start_pos; result.node = buffer_find_node(buffer, start, &node_start_pos); temp_end = start - node_start_pos; if (result.node_end == result.node){ result.pos = result.end_pos; result.absolute_pos = end; } else{ result.pos = 0; result.absolute_pos = node_start_pos; } result.size = temp_end - result.pos; result.data = (char*)buffer->data + buffer->nodes[result.node].str_start + result.pos; } else result.buffer = 0; return(result); } inline_4tech int buffer_backify_good(Rope_Buffer_Backify_Loop *loop){ int result; result = (loop->buffer != 0); return(result); } internal_4tech void buffer_backify_next(Rope_Buffer_Backify_Loop *loop){ Rope_Node *node, *child, *nodes; int temp_start; if (loop->node == loop->node_end && loop->pos == loop->end_pos){ loop->buffer = 0; } else{ nodes = loop->buffer->nodes; node = nodes + loop->node; for (;;){ assert_4tech(node->parent != 0); child = node; node = nodes + node->parent; if (nodes + node->right == child){ break; } else{ assert_4tech(nodes + node->left == child); } } node = nodes + node->left; for (;node->right;){ node = nodes + node->right; } loop->pos = 0; loop->node = (int)(node - nodes); loop->absolute_pos -= node->weight; temp_start = 0; if (loop->node == loop->node_end) temp_start = loop->end_pos; loop->size = node->weight - temp_start; loop->data = (char*)loop->buffer->data + node->str_start; } } internal_4tech void buffer_rotate_right(Rope_Buffer *buffer, int *node_index){ Rope_Node *nodes, *r, *l, *b; int ri, li, bi; nodes = buffer->nodes; ri = *node_index; r = nodes + ri; li = r->left; l = nodes + li; bi = l->right; b = nodes + bi; assert_4tech(bi != 0); assert_4tech(ri != 0); assert_4tech(li != 0); r->parent = li; l->right = ri; b->parent = ri; r->left = bi; r->weight = nodes[r->right].weight + nodes[r->left].weight; r->left_weight = nodes[r->left].weight; l->weight = nodes[l->right].weight + nodes[l->left].weight; l->left_weight = nodes[l->left].weight; *node_index = li; } internal_4tech void buffer_rotate_left(Rope_Buffer *buffer, int *node_index){ Rope_Node *nodes, *r, *l, *b; int ri, li, bi; nodes = buffer->nodes; li = *node_index; l = nodes + li; ri = l->right; r = nodes + ri; bi = r->left; b = nodes + bi; assert_4tech(bi != 0); assert_4tech(ri != 0); assert_4tech(li != 0); l->parent = ri; r->left = li; b->parent = li; l->right = bi; l->weight = nodes[l->right].weight + nodes[l->left].weight; l->left_weight = nodes[l->left].weight; r->weight = nodes[r->right].weight + nodes[r->left].weight; r->left_weight = nodes[r->left].weight; *node_index = ri; } internal_4tech int buffer_merge(Rope_Buffer *buffer, int node_index){ Rope_Node *nodes, *node, *node_a, *node_b; int a, b; int did_merge; assert_4tech(node_index != 0); nodes = buffer->nodes; node = nodes + node_index; did_merge = 0; if (node->weight <= rope_string_width && node->left != 0){ assert_4tech(node->right != 0); a = node->left; b = node->right; node_a = nodes + a; node_b = nodes + b; if (node_a->str_start == 0) buffer_merge(buffer, a); if (node_b->str_start == 0) buffer_merge(buffer, b); did_merge = 1; memcpy_4tech((char*)buffer->data + node_a->str_start + node_a->weight, (char*)buffer->data + node_b->str_start, node_b->weight); node->weight = node_a->weight + node_b->weight; node->left_weight = 0; node->left = node->right = 0; node->str_start = node_a->str_start; buffer_free_rope_node(buffer, a); buffer_free_rope_node(buffer, b); } return(did_merge); } internal_4tech int buffer_balance(Rope_Buffer *buffer, int *root){ Rope_Node *node, *a, *nodes; int wa, wb, wp, wdif, wdifp, left; int node_a; int improved; nodes = buffer->nodes; node = nodes + *root; improved = 0; if (node->left != 0){ assert_4tech(node->right); if (!buffer_merge(buffer, *root)){ wa = node->left_weight; wb = node->weight - wa; assert_4tech(wa + wb > rope_string_width); if (wa < wb){ wp = wa; wa = wb; wb = wp; left = 0; node_a = node->right; } else{ left = 1; node_a = node->left; } wdif = wa - wb; a = nodes + node_a; if (a->left != 0){ assert_4tech(a->right != 0); wp = a->left_weight; if (left) wp = a->weight - wp; wdifp = wdif - 2*wp; if (wdifp < 0) wdifp = -wdifp; if (wdifp < wdif){ improved = 1; if (left){ if (a->weight - a->left_weight > a->left_weight && a->right != 0 && nodes[a->right].left != 0){ buffer_rotate_left(buffer, &node_a); a = nodes + node_a; a->parent = *root; node->left = node_a; } buffer_rotate_right(buffer, root); } else{ if (a->left_weight > a->weight - a->left_weight && a->left != 0 && nodes[a->left].right != 0){ buffer_rotate_right(buffer, &node_a); a = nodes + node_a; a->parent = *root; node->right = node_a; } buffer_rotate_left(buffer, root); } } } } } return(improved); } internal_4tech int buffer_concat(Rope_Buffer *buffer, int node_a, int node_b, int *root, int *request_amount){ Rope_Node *r, *a, *b, *nodes; int result; result = 0; nodes = buffer->nodes; a = nodes + node_a; b = nodes + node_b; if (a->weight == 0){ assert_4tech(a->left == 0 && a->right == 0); *root = node_b; buffer_free_rope_node(buffer, node_a); } else if (b->weight == 0){ assert_4tech(b->left == 0 && b->right == 0); *root = node_a; buffer_free_rope_node(buffer, node_b); } else if (buffer_alloc_rope_node(buffer, root)){ r = nodes + *root; r->left = node_a; r->right = node_b; r->weight = a->weight + b->weight; r->left_weight = a->weight; r->str_start = 0; r->parent = 0; a->parent = *root; b->parent = *root; buffer_node_check(buffer, node_a); buffer_node_check(buffer, node_b); } else{ result = 1; buffer->grow_string_memory = 0; *request_amount = buffer->node_count*sizeof(Rope_Node)*2; } return(result); } internal_4tech int buffer_string_split(Rope_Buffer *buffer, int *node_index, int pos, int *request_amount){ Rope_Node *node, *a, *b; int node_a, node_b; int new_string_start, string_start; int result; result = 0; if (pos > 0){ if (buffer_alloc_rope_string(buffer, &new_string_start)){ if (buffer_alloc_rope_node(buffer, &node_a)){ if (buffer_alloc_rope_node(buffer, &node_b)){ node = buffer->nodes + *node_index; string_start = node->str_start; memcpy_4tech((char*)buffer->data + new_string_start, (char*)buffer->data + string_start + pos, node->weight - pos); node->str_start = 0; node->left_weight = pos; node->left = node_a; node->right = node_b; a = buffer->nodes + node_a; b = buffer->nodes + node_b; a->parent = *node_index; a->left = 0; a->right = 0; a->left_weight = 0; a->weight = pos; a->str_start = string_start; b->parent = *node_index;; b->left = 0; b->right = 0; b->left_weight = 0; b->weight = node->weight - pos; b->str_start = new_string_start; *node_index = node_b; } else{ buffer_free_rope_string(buffer, new_string_start); buffer_free_rope_node(buffer, node_a); result = 1; buffer->grow_string_memory = 0; *request_amount = buffer->node_count*sizeof(Rope_Node)*2; } } else{ buffer_free_rope_string(buffer, new_string_start); result = 1; buffer->grow_string_memory = 0; *request_amount = buffer->node_count*sizeof(Rope_Node)*2; } } else{ result = 1; buffer->grow_string_memory = 1; *request_amount = buffer->string_count*rope_string_full_size*2; } } return(result); } internal_4tech void buffer_reduce_node(Rope_Buffer *buffer, int node_index){ Rope_Node *parent, *child, *node, *nodes; int child_index; nodes = buffer->nodes; node = nodes + node_index; parent = nodes + node->parent; child_index = node->left; if (child_index == 0) child_index = node->right; assert_4tech(child_index != 0); child = nodes + child_index; if (parent->left == node_index) parent->left = child_index; else parent->right = child_index; child->parent = node->parent; for (;parent != nodes;){ parent->weight = nodes[parent->left].weight + nodes[parent->right].weight; parent->left_weight = nodes[parent->left].weight; parent = nodes + parent->parent; } parent->weight = parent->left_weight = nodes[parent->left].weight; buffer_free_rope_node(buffer, node_index); } internal_4tech int buffer_split(Rope_Buffer *buffer, int pos, int *node_a, int *node_b, int *request_amount){ Rope_Node *node, *nodes, *child; int node_index, node_start_pos, split_root; int result; debug_4tech(int dbg_check); nodes = buffer->nodes; result = 0; assert_4tech(pos != 0); node_index = buffer_find_node(buffer, pos, &node_start_pos); if (node_start_pos < pos){ if (buffer_string_split(buffer, &node_index, pos - node_start_pos, request_amount)){ result = 1; goto buffer_split_end; } } split_root = 0; node = nodes + node_index; for (;;){ child = node; node = nodes + node->parent; if (child == nodes + node->right){ break; } else{ assert_4tech(child == nodes + node->left); } } assert_4tech(node != nodes); for (;;){ if (split_root == 0){ split_root = node->right; } else{ debug_4tech(dbg_check =) buffer_concat(buffer, split_root, node->right, &split_root, request_amount); assert_4tech(!dbg_check); } node_index = (int)(node - nodes); node->right = 0; node = nodes + node->left; buffer_reduce_node(buffer, node_index); for (;;){ child = node; node = nodes + child->parent; if (nodes + node->left == child){ break; } else{ assert_4tech(nodes + node->right == child); } } if (node == nodes) break; } *node_a = nodes->left; *node_b = split_root; buffer_split_end: return(result); } internal_4tech int buffer_build_tree_floating(Rope_Buffer *buffer, char *str, int len, int *out, void *scratch, int scratch_size, int *request_amount){ Rope_Node *super_root_node; int result; int super_root; result = 0; if (buffer_alloc_rope_node(buffer, &super_root)){ super_root_node = buffer->nodes + super_root; memset_4tech(super_root_node, 0, sizeof(*super_root_node)); if (buffer_build_tree(buffer, str, len, super_root, scratch, scratch_size, request_amount)){ *out = buffer->nodes[super_root].left; buffer_free_rope_node(buffer, super_root); } else{ result = 1; buffer_free_rope_node(buffer, super_root); } } else{ result = 1; buffer->grow_string_memory = 0; *request_amount = buffer->node_count*sizeof(Rope_Node)*2; } return(result); } internal_4tech int buffer_replace_range(Rope_Buffer *buffer, int start, int end, char *str, int len, int *shift_amount, void *scratch, int scratch_size, int *request_amount){ Rope_Node *nodes; Rope_Buffer_Edit_State state; int result; int size; state = buffer->edit_state; size = buffer_size(buffer); assert_4tech(0 <= start); assert_4tech(start <= end); assert_4tech(end <= size); *shift_amount = (len - (end - start)); nodes = buffer->nodes; result = 0; buffer_cheap_check(buffer); for (; buffer->edit_stage < 9; ++buffer->edit_stage){ buffer_cheap_check(buffer); switch (buffer->edit_stage){ case 0: if (end == 0){ state.throw_away = 0; state.right = nodes->left; } else if (end == size){ state.throw_away = nodes->left; state.right = 0; } else{ result = buffer_split(buffer, end, &state.throw_away, &state.right, request_amount); } if (state.right) buffer_node_check(buffer, state.right); break; case 1: if (start == 0){ state.left = 0; } else if (start == end){ state.left = state.throw_away; state.throw_away = 0; } else{ result = buffer_split(buffer, start, &state.left, &state.throw_away, request_amount); } if (state.left) buffer_node_check(buffer, state.left); break; case 2: if (state.throw_away){ buffer_free_tree(buffer, state.throw_away, scratch, scratch_size); } break; case 3: if (len == 0) buffer->edit_stage += 4; break; case 4: if (state.left) buffer_node_check(buffer, state.left); if (state.right) buffer_node_check(buffer, state.right); result = buffer_build_tree_floating(buffer, str, len, &state.middle, scratch, scratch_size, request_amount); if (state.left) buffer_node_check(buffer, state.left); if (state.right) buffer_node_check(buffer, state.right); break; case 5: if (state.left){ result = buffer_concat(buffer, state.left, state.middle, &state.middle, request_amount); } break; case 6: if (state.right){ buffer_balance(buffer, &state.middle); buffer_node_check(buffer, state.middle); result = buffer_concat(buffer, state.middle, state.right, &state.middle, request_amount); } break; case 7: buffer_balance(buffer, &state.middle); buffer_node_check(buffer, state.middle); buffer->edit_stage = 9; break; case 8: if (state.left && state.right){ result = buffer_concat(buffer, state.left, state.right, &state.middle, request_amount); } else if (state.left){ state.middle = state.left; } else{ state.middle = state.right; } break; } buffer_cheap_check(buffer); if (result) goto rope_buffer_replace_range_end; } buffer->edit_stage = 0; nodes[state.middle].parent = 0; nodes->left = state.middle; nodes->weight = nodes->left_weight = nodes[state.middle].weight; memset_4tech(&state, 0, sizeof(state)); buffer_rope_check(buffer, scratch, scratch_size); rope_buffer_replace_range_end: buffer->edit_state = state; return(result); } // NOTE(allen): This could should be optimized for Gap_Buffer internal_4tech int buffer_batch_edit_step(Buffer_Batch_State *state, Rope_Buffer *buffer, Buffer_Edit *sorted_edits, char *strings, int edit_count, void *scratch, int scratch_size, int *request_amount){ Buffer_Edit *edit; int i, result; int shift_total, shift_amount; result = 0; shift_total = state->shift_total; i = state->i; edit = sorted_edits + i; for (; i < edit_count; ++i, ++edit){ result = buffer_replace_range(buffer, edit->start + shift_total, edit->end + shift_total, strings + edit->str_start, edit->len, &shift_amount, scratch, scratch_size, request_amount); if (result) break; shift_total += shift_amount; } state->shift_total = shift_total; state->i = i; return(result); } internal_4tech void* buffer_edit_provide_memory(Rope_Buffer *buffer, void *new_data, int size){ void *result; Rope_String *rope_string; Rope_Node *node; int start, end, i; if (buffer->grow_string_memory){ assert_4tech(size >= buffer->string_count * rope_string_full_size); result = buffer->data; memcpy_4tech(new_data, buffer->data, buffer->string_count * rope_string_full_size); buffer->data = new_data; start = buffer->string_count*rope_string_full_size; end = size/rope_string_full_size; buffer->string_count = end; end = (end-1)*rope_string_full_size; for (i = start; i < end; i += rope_string_full_size){ rope_string = (Rope_String*)((char*)new_data + i); rope_string->next_free = i + rope_string_full_size; } rope_string = (Rope_String*)((char*)new_data + i); rope_string->next_free = buffer->free_rope_string; buffer->free_rope_string = start; } else{ assert_4tech(size >= buffer->node_count * sizeof(Rope_Node)); result = buffer->nodes; memcpy_4tech(new_data, buffer->nodes, buffer->node_count * sizeof(Rope_Node)); buffer->nodes = (Rope_Node*)new_data; start = buffer->node_count; end = size/sizeof(Rope_Node); buffer->node_count = end; end -= 1; node = buffer->nodes + start; for (i = start; i < end; ++i, ++node){ node->parent = i+1; } node->parent = buffer->free_rope_node; buffer->free_rope_node = start; } return(result); } // BOTTOM