aboutsummaryrefslogtreecommitdiff
path: root/strbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'strbuf.c')
-rw-r--r--strbuf.c80
1 files changed, 69 insertions, 11 deletions
diff --git a/strbuf.c b/strbuf.c
index 9f0d212..227cb47 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -16,19 +16,31 @@ static void die(const char *format, ...)
16 exit(-1); 16 exit(-1);
17} 17}
18 18
19void strbuf_init(strbuf_t *s) 19void strbuf_init(strbuf_t *s, int len)
20{ 20{
21 int size;
22
23 if (len <= 0)
24 size = STRBUF_DEFAULT_SIZE;
25 else
26 size = len + 1; /* \0 terminator */
27
21 s->buf = NULL; 28 s->buf = NULL;
22 s->size = 0; 29 s->size = size;
23 s->length = 0; 30 s->length = 0;
24 s->increment = STRBUF_DEFAULT_INCREMENT; 31 s->increment = STRBUF_DEFAULT_INCREMENT;
25 s->dynamic = 0; 32 s->dynamic = 0;
33 s->reallocs = 0;
34 s->debug = 0;
35
36 s->buf = malloc(size);
37 if (!s->buf)
38 die("Out of memory");
26 39
27 strbuf_resize(s, 0);
28 strbuf_ensure_null(s); 40 strbuf_ensure_null(s);
29} 41}
30 42
31strbuf_t *strbuf_new() 43strbuf_t *strbuf_new(int len)
32{ 44{
33 strbuf_t *s; 45 strbuf_t *s;
34 46
@@ -36,7 +48,7 @@ strbuf_t *strbuf_new()
36 if (!s) 48 if (!s)
37 die("Out of memory"); 49 die("Out of memory");
38 50
39 strbuf_init(s); 51 strbuf_init(s, len);
40 52
41 /* Dynamic strbuf allocation / deallocation */ 53 /* Dynamic strbuf allocation / deallocation */
42 s->dynamic = 1; 54 s->dynamic = 1;
@@ -46,14 +58,26 @@ strbuf_t *strbuf_new()
46 58
47void strbuf_set_increment(strbuf_t *s, int increment) 59void strbuf_set_increment(strbuf_t *s, int increment)
48{ 60{
49 if (increment <= 0) 61 /* Increment > 0: Linear buffer growth rate
62 * Increment < -1: Exponential buffer growth rate */
63 if (increment == 0 || increment == -1)
50 die("BUG: Invalid string increment"); 64 die("BUG: Invalid string increment");
51 65
52 s->increment = increment; 66 s->increment = increment;
53} 67}
54 68
69static inline void debug_stats(strbuf_t *s)
70{
71 if (s->debug) {
72 fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n",
73 (long)s, s->reallocs, s->length, s->size);
74 }
75}
76
55void strbuf_free(strbuf_t *s) 77void strbuf_free(strbuf_t *s)
56{ 78{
79 debug_stats(s);
80
57 if (s->buf) 81 if (s->buf)
58 free(s->buf); 82 free(s->buf);
59 if (s->dynamic) 83 if (s->dynamic)
@@ -64,6 +88,8 @@ char *strbuf_free_to_string(strbuf_t *s, int *len)
64{ 88{
65 char *buf; 89 char *buf;
66 90
91 debug_stats(s);
92
67 strbuf_ensure_null(s); 93 strbuf_ensure_null(s);
68 94
69 buf = s->buf; 95 buf = s->buf;
@@ -76,20 +102,52 @@ char *strbuf_free_to_string(strbuf_t *s, int *len)
76 return buf; 102 return buf;
77} 103}
78 104
105static int calculate_new_size(strbuf_t *s, int len)
106{
107 int reqsize, newsize;
108
109 if (len <= 0)
110 die("BUG: Invalid strbuf length requested");
111
112 /* Ensure there is room for optional NULL termination */
113 reqsize = len + 1;
114
115 /* If the user has requested to shrink the buffer, do it exactly */
116 if (s->size > reqsize)
117 return reqsize;
118
119 newsize = s->size;
120 if (s->increment < 0) {
121 /* Exponential sizing */
122 while (newsize < reqsize)
123 newsize *= -s->increment;
124 } else {
125 /* Linear sizing */
126 newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
127 }
128
129 return newsize;
130}
131
132
79/* Ensure strbuf can handle a string length bytes long (ignoring NULL 133/* Ensure strbuf can handle a string length bytes long (ignoring NULL
80 * optional termination). */ 134 * optional termination). */
81void strbuf_resize(strbuf_t *s, int len) 135void strbuf_resize(strbuf_t *s, int len)
82{ 136{
83 int newsize; 137 int newsize;
84 138
85 /* Ensure there is room for optional NULL termination */ 139 newsize = calculate_new_size(s, len);
86 newsize = len + 1; 140
87 /* Round up to the next increment */ 141 if (s->debug > 1) {
88 newsize = ((newsize + s->increment - 1) / s->increment) * s->increment; 142 fprintf(stderr, "strbuf(%lx) resize: %d => %d\n",
143 (long)s, s->size, newsize);
144 }
145
89 s->size = newsize; 146 s->size = newsize;
90 s->buf = realloc(s->buf, s->size); 147 s->buf = realloc(s->buf, s->size);
91 if (!s->buf) 148 if (!s->buf)
92 die("Out of memory"); 149 die("Out of memory");
150 s->reallocs++;
93} 151}
94 152
95void strbuf_append_mem(strbuf_t *s, const char *c, int len) 153void strbuf_append_mem(strbuf_t *s, const char *c, int len)
@@ -109,7 +167,7 @@ void strbuf_append_string(strbuf_t *s, const char *str)
109 167
110 for (i = 0; str[i]; i++) { 168 for (i = 0; str[i]; i++) {
111 if (space < 1) { 169 if (space < 1) {
112 strbuf_resize(s, s->length + s->increment); 170 strbuf_resize(s, s->length + 1);
113 space = strbuf_empty_length(s); 171 space = strbuf_empty_length(s);
114 } 172 }
115 173