summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hiredis.c111
-rw-r--r--hiredis.h1
2 files changed, 60 insertions, 52 deletions
diff --git a/hiredis.c b/hiredis.c
index 877e446..16fed97 100644
--- a/hiredis.c
+++ b/hiredis.c
@@ -47,9 +47,8 @@ typedef struct redisReader {
sds buf; /* read buffer */
unsigned int pos; /* buffer cursor */
- redisReadTask *rlist; /* list of items to process */
- unsigned int rlen; /* list length */
- unsigned int rpos; /* list cursor */
+ redisReadTask rstack[3]; /* stack of read tasks */
+ int ridx; /* index of stack */
} redisReader;
static redisReply *createReplyObject(int type);
@@ -183,8 +182,33 @@ static char *readLine(redisReader *r, int *_len) {
return NULL;
}
+static void moveToNextTask(redisReader *r) {
+ redisReadTask *cur, *prv;
+ assert(r->ridx >= 0);
+
+ /* Return a.s.a.p. when the stack is now empty. */
+ if (r->ridx == 0) {
+ r->ridx--;
+ return;
+ }
+
+ cur = &(r->rstack[r->ridx]);
+ prv = &(r->rstack[r->ridx-1]);
+ assert(prv->type == REDIS_REPLY_ARRAY);
+ if (cur->idx == prv->elements-1) {
+ r->ridx--;
+ moveToNextTask(r);
+ } else {
+ /* Reset the type because the next item can be anything */
+ assert(cur->idx < prv->elements);
+ cur->type = -1;
+ cur->elements = -1;
+ cur->idx++;
+ }
+}
+
static int processLineItem(redisReader *r) {
- redisReadTask *cur = &(r->rlist[r->rpos]);
+ redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj;
char *p;
int len;
@@ -199,14 +223,14 @@ static int processLineItem(redisReader *r) {
/* If there is no root yet, register this object as root. */
if (r->reply == NULL)
r->reply = obj;
- r->rpos++;
+ moveToNextTask(r);
return 0;
}
return -1;
}
static int processBulkItem(redisReader *r) {
- redisReadTask *cur = &(r->rlist[r->rpos]);
+ redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj = NULL;
char *p, *s;
long len;
@@ -235,7 +259,7 @@ static int processBulkItem(redisReader *r) {
r->pos += bytelen;
if (r->reply == NULL)
r->reply = obj;
- r->rpos++;
+ moveToNextTask(r);
return 0;
}
}
@@ -243,53 +267,42 @@ static int processBulkItem(redisReader *r) {
}
static int processMultiBulkItem(redisReader *r) {
- redisReadTask *cur = &(r->rlist[r->rpos]);
+ redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj;
char *p;
- long elements, j;
+ long elements;
if ((p = readLine(r,NULL)) != NULL) {
elements = strtol(p,NULL,10);
if (elements == -1) {
obj = r->fn->createNil(cur);
+ moveToNextTask(r);
} else {
obj = r->fn->createArray(cur,elements);
- /* Modify read list when there are more than 0 elements. */
+ /* Modify task stack when there are more than 0 elements. */
if (elements > 0) {
- /* Append elements to the read list. */
- r->rlen += elements;
- if ((r->rlist = realloc(r->rlist,sizeof(redisReadTask)*r->rlen)) == NULL)
- redisOOM();
-
- /* Move existing items backwards. */
- memmove(&(r->rlist[r->rpos+1+elements]),
- &(r->rlist[r->rpos+1]),
- (r->rlen-(r->rpos+1+elements))*sizeof(redisReadTask));
-
- /* Populate new read items. */
- redisReadTask *t;
- for (j = 0; j < elements; j++) {
- t = &(r->rlist[r->rpos+1+j]);
- t->type = -1;
- t->parent = obj;
- t->idx = j;
- }
+ cur->elements = elements;
+ r->ridx++;
+ r->rstack[r->ridx].type = -1;
+ r->rstack[r->ridx].elements = -1;
+ r->rstack[r->ridx].parent = obj;
+ r->rstack[r->ridx].idx = 0;
+ } else {
+ moveToNextTask(r);
}
}
- if (obj != NULL) {
- if (r->reply == NULL)
- r->reply = obj;
- r->rpos++;
- return 0;
- }
+ /* Object was created, so we can always continue. */
+ if (r->reply == NULL)
+ r->reply = obj;
+ return 0;
}
return -1;
}
static int processItem(redisReader *r) {
- redisReadTask *cur = &(r->rlist[r->rpos]);
+ redisReadTask *cur = &(r->rstack[r->ridx]);
char *p;
sds byte;
@@ -347,7 +360,7 @@ void *redisReplyReaderCreate(redisReplyObjectFunctions *fn) {
r->error = NULL;
r->fn = fn == NULL ? &defaultFunctions : fn;
r->buf = sdsempty();
- r->rlist = malloc(sizeof(redisReadTask)*1);
+ r->ridx = -1;
return r;
}
@@ -368,8 +381,6 @@ void redisReplyReaderFree(void *reader) {
r->fn->freeObject(r->reply);
if (r->buf != NULL)
sdsfree(r->buf);
- if (r->rlist != NULL)
- free(r->rlist);
free(r);
}
@@ -383,7 +394,7 @@ static void redisSetReplyReaderError(redisReader *r, sds err) {
r->buf = sdsempty();
r->pos = 0;
}
- r->rlen = r->rpos = 0;
+ r->ridx = -1;
r->error = err;
}
@@ -408,18 +419,17 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
if (sdslen(r->buf) == 0)
return REDIS_OK;
- /* Create first item to process when the item list is empty. */
- if (r->rlen == 0) {
- r->rlist = realloc(r->rlist,sizeof(redisReadTask)*1);
- r->rlist[0].type = -1;
- r->rlist[0].parent = NULL;
- r->rlist[0].idx = -1;
- r->rlen = 1;
- r->rpos = 0;
+ /* Set first item to process when the stack is empty. */
+ if (r->ridx == -1) {
+ r->rstack[0].type = -1;
+ r->rstack[0].elements = -1;
+ r->rstack[0].parent = NULL;
+ r->rstack[0].idx = -1;
+ r->ridx = 0;
}
/* Process items in reply. */
- while (r->rpos < r->rlen)
+ while (r->ridx >= 0)
if (processItem(r) < 0)
break;
@@ -436,7 +446,7 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
}
/* Emit a reply when there is one. */
- if (r->rpos == r->rlen) {
+ if (r->ridx == -1) {
void *aux = r->reply;
r->reply = NULL;
@@ -447,9 +457,6 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
r->pos = 0;
}
- /* Set list of items to read to be empty. */
- r->rlen = r->rpos = 0;
-
/* Check if there actually *is* a reply. */
if (r->error != NULL) {
return REDIS_ERR;
diff --git a/hiredis.h b/hiredis.h
index 4142573..08d1df9 100644
--- a/hiredis.h
+++ b/hiredis.h
@@ -61,6 +61,7 @@ typedef struct redisReply {
typedef struct redisReadTask {
int type;
+ int elements; /* number of elements in multibulk container */
void *parent; /* optional pointer to parent object */
int idx; /* index in parent (array) object */
} redisReadTask;