summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2012-03-02 16:20:16 +0100
committerYorhel <git@yorhel.nl>2012-03-02 16:33:38 +0100
commitd17d94cefafd25471234307c3b4a67c276d0b651 (patch)
tree28679123487b9baf20920d4f62c6735402abc813
parente7e685dae254e918c2a4afe063e2a1201b97e8ef (diff)
Use lbuf abstraction for JSON-formatting tuples
Makes it easier/more efficient to write tuples directly to the link buffer.
-rw-r--r--tanja.c191
-rw-r--r--tanja.h2
-rw-r--r--test.c7
3 files changed, 97 insertions, 103 deletions
diff --git a/tanja.c b/tanja.c
index e6f8633..1b46d2e 100644
--- a/tanja.c
+++ b/tanja.c
@@ -38,6 +38,58 @@ static void tn_session_reply(tn_session *, tn_tuple *, tn_returnpath *);
+// Tiny buffer abstraction for internal use
+// Note that these macros aren't very safe with respect to argument naming /
+// evaluation. Only pass variables directly.
+
+typedef struct {
+ char *dat;
+ int len;
+ int size;
+} lbuf;
+
+#define lbuf_init(b) do {\
+ b.dat = NULL;\
+ b.size = b.len = 0;\
+ } while(0)
+
+#define lbuf_free(b) do {\
+ if(b.dat)\
+ free(b.dat);\
+ lbuf_init(b);\
+ } while(0)
+
+#define lbuf_grow(b, _m) do {\
+ if(b.size < 16)\
+ b.size = 16;\
+ else\
+ b.size *= 2;\
+ if(b.size < _m)\
+ b.size = _m;\
+ b.dat = realloc(b.dat, b.size);\
+ } while(0)
+
+#define lbuf_append(b, _buf, _len) do {\
+ if(b.size < b.len + _len)\
+ lbuf_grow(b, b.len + _len);\
+ memcpy(b.dat+b.len, _buf, _len);\
+ b.len += _len;\
+ } while(0)
+
+#define lbuf_append_c(b, _c) do {\
+ if(b.size < b.len + 1)\
+ lbuf_grow(b, b.len + 1);\
+ b.dat[b.len++] = _c;\
+ } while(0)
+
+#define lbuf_shift(b, _len) do {\
+ memmove(b.dat, b.dat+_len, b.len-_len);\
+ b.len -= _len;\
+ } while(0)
+
+
+
+
// Generic tuple management
@@ -252,20 +304,14 @@ int tn_tuple_match(tn_tuple *p, tn_tuple *t) {
// Tuple-to-json encoder
-#define ac(c) do {\
- buf[(*w)++] = c;\
- if(--(*len) <= 0)\
- return -1;\
- } while(0)
+#define ac(_c) lbuf_append_c((*buf), _c)
-#define as(s) do {\
- char *tmp=s;\
- while(*tmp)\
- ac(*(tmp++));\
+#define as(_s) do {\
+ int _len = strlen(_s);\
+ lbuf_append((*buf), _s, _len);\
} while(0)
-
-static int json_fmt_string(char *str, char *buf, int *w, int *len) {
+static inline void json_fmt_string(char *str, lbuf *buf) {
ac('\"');
while(*str) {
switch(*str) {
@@ -284,11 +330,10 @@ static int json_fmt_string(char *str, char *buf, int *w, int *len) {
str++;
}
ac('\"');
- return *w;
}
-static int json_fmt_element(tn_element e, char *buf, int *w, int *len) {
+static void json_fmt_element(tn_element e, lbuf *buf) {
char b[25];
int i;
switch(e.type) {
@@ -301,16 +346,14 @@ static int json_fmt_element(tn_element e, char *buf, int *w, int *len) {
as(b);
break;
case TN_VT_STR:
- if(json_fmt_string(e.v.s, buf, w, len) < 0)
- return -1;
+ json_fmt_string(e.v.s, buf);
break;
case TN_VT_AR:
ac('[');
for(i=0; i<e.count; i++) {
if(i)
ac(',');
- if(json_fmt_element(e.v.a[i], buf, w, len) < 0)
- return -1;
+ json_fmt_element(e.v.a[i], buf);
}
ac(']');
break;
@@ -319,11 +362,9 @@ static int json_fmt_element(tn_element e, char *buf, int *w, int *len) {
for(i=0; i<e.count; i++) {
if(i)
ac(',');
- if(json_fmt_string(e.v.m[i].key, buf, w, len) < 0)
- return -1;
+ json_fmt_string(e.v.m[i].key, buf);
ac(':');
- if(json_fmt_element(e.v.m[i].val, buf, w, len) < 0)
- return -1;
+ json_fmt_element(e.v.m[i].val, buf);
}
ac('}');
break;
@@ -331,36 +372,35 @@ static int json_fmt_element(tn_element e, char *buf, int *w, int *len) {
assert(e.type == TN_VT_WC);
as("null");
}
- return *w;
}
-// Write a JSON representation of the tuple into *buf. Returns -1 if it doesn't
-// fit in the buffer, the number of written characters (excluding the trailing
-// \0) otherwise.
-int tn_json_fmt(tn_tuple *tup, char *buf, int l) {
- if(!l)
- return -1;
- int *len = &l;
- int wr = 0;
- int *w = &wr;
+static void tn_json_fmt_buf(tn_tuple *tup, lbuf *buf) {
ac('[');
int i;
for(i=0; i<tup->n; i++) {
if(i)
ac(',');
- if(json_fmt_element(tup->e[i], buf, w, len) < 0)
- return -1;
+ json_fmt_element(tup->e[i], buf);
}
ac(']');
- buf[wr] = 0;
- return wr;
}
#undef as
#undef ac
+// Returns a (0-terminated) JSON representation of the tuple. The returned
+// buffer must be free()'d after use.
+char *tn_json_fmt(tn_tuple *tup) {
+ lbuf buf;
+ lbuf_init(buf);
+ tn_json_fmt_buf(tup, &buf);
+ lbuf_append_c(buf, 0);
+ return buf.dat;
+}
+
+
@@ -819,48 +859,13 @@ struct tn_link {
int errcode;
char *errmsg;
void *data;
- char *rbuf;
- int rbuf_len;
- int rbuf_size;
- char *wbuf;
- int wbuf_len;
- int wbuf_size;
+ lbuf rbuf;
+ lbuf wbuf;
unsigned handshaked : 1;
unsigned sync : 1;
};
-// Tiny buffer abstraction
-
-#define lbuf_init(b) do {\
- b = NULL;\
- b##_size = b##_len = 0;\
- } while(0)
-
-#define lbuf_free(b) do {\
- if(b)\
- free(b);\
- lbuf_init(b);\
- } while(0)
-
-#define lbuf_grow(b, m) do {\
- if(b##_size < 16)\
- b##_size = 16;\
- else\
- b##_size *= 2;\
- if(b##_size < m)\
- b##_size = m;\
- b = realloc(b, b##_size);\
- } while(0)
-
-#define lbuf_append(b, buf, len) do {\
- if(b##_size < b##_len + len)\
- lbuf_grow(b, b##_len + len);\
- memcpy(b+b##_len, buf, len);\
- b##_len += len;\
- } while(0)
-
-
static inline void tn_link_write(tn_link *l, char *msg, int len) {
// No write dispatcher? Then assume we can call ctx->write() directly
if(!l->ctx->wdispatch) {
@@ -871,7 +876,7 @@ static inline void tn_link_write(tn_link *l, char *msg, int len) {
}
// Otherwise, append to the buffer and call the write dispatcher
mutex_lock(l->lock);
- int empty = !l->wbuf_len;
+ int empty = !l->wbuf.len;
lbuf_append(l->wbuf, msg, len);
mutex_unlock(l->lock);
if(empty)
@@ -991,7 +996,7 @@ void tn_link_read(tn_link *l, const char *buf, int len) {
// Don't copy things to the read buffer if we have a full message
int n=1;
- while(!l->rbuf_len && len > 0 && n) {
+ while(!l->rbuf.len && len > 0 && n) {
n = tn_link_handleread(l, buf, len);
buf += n;
len -= n;
@@ -1008,14 +1013,12 @@ void tn_link_read(tn_link *l, const char *buf, int len) {
// actually have to be checked.
int r=0;
n=1;
- while(l->rbuf_len-r > 0 && n) {
- n = tn_link_handleread(l, l->rbuf+r, l->rbuf_len-r);
+ while(l->rbuf.len-r > 0 && n) {
+ n = tn_link_handleread(l, l->rbuf.dat+r, l->rbuf.len-r);
r += n;
}
- if(r > 0) {
- memmove(l->rbuf, l->rbuf+r, l->rbuf_len-r);
- l->rbuf_len -= r;
- }
+ if(r > 0)
+ lbuf_shift(l->rbuf, r);
}
@@ -1034,40 +1037,34 @@ void tn_link_dispatch(tn_link *l) {
// temporarily replace it with an empty one so that other threads can keep
// writing without blocking or losing the new data.
mutex_lock(l->lock);
- if(l->wbuf_len) {
- char *buf = l->wbuf;
- int buf_len = l->wbuf_len;
- int buf_size = l->wbuf_size;
+ if(l->wbuf.len) {
+ lbuf buf = l->wbuf;
lbuf_init(l->wbuf);
mutex_unlock(l->lock);
- int n = l->ctx->write(l, buf, buf_len, &l->errmsg, l->data);
+ int n = l->ctx->write(l, buf.dat, buf.len, &l->errmsg, l->data);
if(n < 0) {
l->errcode = -n;
l->ctx->dispatch(l, l->data);
- free(buf);
+ free(buf.dat);
return;
}
mutex_lock(l->lock);
- if(n > 0) {
- memmove(buf, buf+n, buf_len-n);
- buf_len -= n;
- }
+ if(n > 0)
+ lbuf_shift(buf, n);
// If our buffer has been emptied, then just free it and leave the write buffer alone.
- if(!buf_len)
+ if(!buf.len)
lbuf_free(buf);
else {
// Oops, someone else has written to the buffer while we were being
// busy. Append this data to our buffer.
- if(l->wbuf_len)
- lbuf_append(buf, l->wbuf, l->wbuf_len);
+ if(l->wbuf.len)
+ lbuf_append(buf, l->wbuf.dat, l->wbuf.len);
// Now give back our temporary buffer
- if(l->wbuf)
- free(l->wbuf);
+ if(l->wbuf.dat)
+ free(l->wbuf.dat);
l->wbuf = buf;
- l->wbuf_len = buf_len;
- l->wbuf_size = buf_size;
}
}
mutex_unlock(l->lock);
diff --git a/tanja.h b/tanja.h
index aa3d328..b538789 100644
--- a/tanja.h
+++ b/tanja.h
@@ -81,7 +81,7 @@ void tn_map_set(tn_element *, char *, ...);
tn_tuple *tn_tuple_new(char *, ...);
int tn_tuple_match(tn_tuple *, tn_tuple *);
-int tn_json_fmt(tn_tuple *, char *, int);
+char *tn_json_fmt(tn_tuple *);
void tn_reply(tn_returnpath *, tn_tuple *);
void tn_reply_close(tn_returnpath *rp);
diff --git a/test.c b/test.c
index a28e196..3beff4c 100644
--- a/test.c
+++ b/test.c
@@ -29,11 +29,8 @@ int main() {
tn_array_new("i", INT64_MIN),
tn_map_new("sn", strdup("k\ney"), strdup("va\rlue"), strdup("number\""), 1.5e10)
);
- char *buf = malloc(98);
- if(tn_json_fmt(t, buf, 98) > 0)
- puts(buf);
- else
- puts("Too long");
+ char *buf = tn_json_fmt(t);
+ puts(buf);
free(buf);
tn_tuple_unref(t);
tn_node *n = tn_node_create();