aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Pulford <mark@kyne.com.au>2011-04-25 00:56:55 +0930
committerMark Pulford <mark@kyne.com.au>2011-04-25 00:56:55 +0930
commit85f2231b381a232686a39e4962b3d5e3cad61161 (patch)
treea4f91a37496af94a7bbfcdac268296e9dbb2679b
parent2b693fb4493764e71f11b6257c0ce58cdbb8a779 (diff)
downloadlua-cjson-85f2231b381a232686a39e4962b3d5e3cad61161.tar.gz
lua-cjson-85f2231b381a232686a39e4962b3d5e3cad61161.tar.bz2
lua-cjson-85f2231b381a232686a39e4962b3d5e3cad61161.zip
Add support for growing strbufs exponentially
- Change default to 1024 byte strings and doubling in size - Add strbuf debug statistics
-rw-r--r--lua_json.c6
-rw-r--r--strbuf.c80
-rw-r--r--strbuf.h11
3 files changed, 79 insertions, 18 deletions
diff --git a/lua_json.c b/lua_json.c
index 25078a3..10810f0 100644
--- a/lua_json.c
+++ b/lua_json.c
@@ -247,8 +247,7 @@ char *lua_json_encode(lua_State *l, int *len)
247 strbuf_t buf; 247 strbuf_t buf;
248 char *json; 248 char *json;
249 249
250 strbuf_init(&buf); 250 strbuf_init(&buf, 0);
251 strbuf_set_increment(&buf, 256);
252 json_append_data(l, &buf); 251 json_append_data(l, &buf);
253 json = strbuf_free_to_string(&buf, len); 252 json = strbuf_free_to_string(&buf, len);
254 253
@@ -637,8 +636,7 @@ void lua_json_decode(lua_State *l, const char *json_text)
637 636
638 json.data = json_text; 637 json.data = json_text;
639 json.index = 0; 638 json.index = 0;
640 json.tmp = strbuf_new(); 639 json.tmp = strbuf_new(0);
641 strbuf_set_increment(json.tmp, 256);
642 640
643 json_next_token(&json, &token); 641 json_next_token(&json, &token);
644 json_process_value(l, &json, &token); 642 json_process_value(l, &json, &token);
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
diff --git a/strbuf.h b/strbuf.h
index 96dd97b..914274c 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -13,15 +13,20 @@ typedef struct {
13 int length; 13 int length;
14 int increment; 14 int increment;
15 int dynamic; 15 int dynamic;
16 int reallocs;
17 int debug;
16} strbuf_t; 18} strbuf_t;
17 19
20#ifndef STRBUF_DEFAULT_SIZE
21#define STRBUF_DEFAULT_SIZE 1023
22#endif
18#ifndef STRBUF_DEFAULT_INCREMENT 23#ifndef STRBUF_DEFAULT_INCREMENT
19#define STRBUF_DEFAULT_INCREMENT 8 24#define STRBUF_DEFAULT_INCREMENT -2
20#endif 25#endif
21 26
22/* Initialise */ 27/* Initialise */
23extern strbuf_t *strbuf_new(); 28extern strbuf_t *strbuf_new(int len);
24extern void strbuf_init(strbuf_t *s); 29extern void strbuf_init(strbuf_t *s, int len);
25extern void strbuf_set_increment(strbuf_t *s, int increment); 30extern void strbuf_set_increment(strbuf_t *s, int increment);
26 31
27/* Release */ 32/* Release */