-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgap_buffer.c
127 lines (114 loc) · 3.17 KB
/
gap_buffer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "gap_buffer.h"
#include <stdlib.h>
#include <string.h>
#define GAP_DEFAULT_BUFFER_SIZE 16
static bool resize(struct gap_buffer *gb) {
const size_t new_size = ((double)gb->cap) * 1.7;
char* tmp_buf = realloc(gb->buffer, sizeof(char) * new_size);
if (tmp_buf == NULL) return false;
gb->buffer = tmp_buf;
gb->cap = new_size;
return true;
}
static bool resize_buffer(struct gap_buffer *gb) {
if (!resize(gb)) {
return false;
}
size_t i = gb->len, j = gb->cap;
for (; i > gb->cursor_end; --i, --j) {
gb->buffer[j - 1] = gb->buffer[i - 1];
}
gb->len = gb->cap;
gb->cursor_end = j;
return true;
}
bool gap_buffer_init(struct gap_buffer *gb, size_t buf_size) {
if (buf_size <= 0) {
buf_size = GAP_DEFAULT_BUFFER_SIZE;
}
gb->buffer = (char*)malloc(sizeof(char)*buf_size);
if (gb->buffer == NULL) {
return false;
}
gb->len = buf_size;
gb->cap = buf_size;
gb->cursor_start = 0;
gb->cursor_end = buf_size;
return true;
}
bool gap_buffer_move_cursor(struct gap_buffer *gb, size_t pos) {
if (pos > gb->cap) return false;
const size_t gap_len = gb->cursor_end - gb->cursor_start;
if (pos > gb->cursor_start) {
size_t pos_offset = pos + gap_len;
if (pos_offset > gb->cap) {
pos_offset = gb->cap;
}
const size_t start_idx = gb->cursor_end;
for (size_t i = start_idx; i < pos_offset; ++i) {
gb->buffer[gb->cursor_start] = gb->buffer[i];
gb->cursor_start++;
}
gb->cursor_end = pos_offset;
} else if (pos < gb->cursor_start) {
size_t i = gb->cursor_start - 1;
size_t j = gb->cursor_end;
for (; i >= pos; --i, --j) {
gb->buffer[j - 1] = gb->buffer[i];
// break after we handle 0 otherwise it will wrap
if (i == 0) {
// decrement j in this case because we miss the last decrement
j--;
break;
}
}
gb->cursor_end = j;
gb->cursor_start = pos;
}
return true;
}
void gap_buffer_get_char(struct gap_buffer *gb, size_t pos, char* out) {
if (pos > gb->cap) return;
size_t idx = pos;
if (idx >= gb->cursor_start) {
idx = pos + (gb->cursor_end - gb->cursor_start);
}
*out = gb->buffer[idx];
}
size_t gap_buffer_get_len(struct gap_buffer *gb) {
return gb->len - (gb->cursor_end - gb->cursor_start);
}
bool gap_buffer_insert(struct gap_buffer *gb, char c) {
if (gb->cursor_start >= gb->cursor_end) {
if (!resize_buffer(gb)) return false;
}
gb->buffer[gb->cursor_start] = c;
gb->cursor_start++;
return true;
}
bool gap_buffer_insert_word(struct gap_buffer *gb, size_t pos, char* input) {
if (!gap_buffer_move_cursor(gb, pos)) return false;
const size_t len = strlen(input);
for (int i = 0; i < len; ++i) {
if (!gap_buffer_insert(gb, input[i])) return false;
}
return true;
}
bool gap_buffer_delete(struct gap_buffer *gb) {
if (gb->cursor_start == 0) return false;
gb->cursor_start--;
return true;
}
bool gap_buffer_delete_seq(struct gap_buffer *gb, size_t n) {
if (n > gb->cursor_start) return false;
gb->cursor_start -= n;
return true;
}
void gap_buffer_free(struct gap_buffer *gb) {
free(gb->buffer);
gb->buffer = NULL;
gb->len = 0;
gb->cap = 0;
gb->cursor_end = 0;
gb->cursor_start = 0;
}