X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/a5456b2cb69c5bde1ea5403c6459885b074a8575..9ae6b0be4ac05c919b943ed29ffa20e5560855a2:/ziplist.c diff --git a/ziplist.c b/ziplist.c index 50b92514..71d965a8 100644 --- a/ziplist.c +++ b/ziplist.c @@ -48,6 +48,9 @@ #define ZIPLIST_TAIL_OFFSET(zl) (*((zl)+sizeof(unsigned int))) #define ZIPLIST_LENGTH(zl) (*((zl)+2*sizeof(unsigned int))) #define ZIPLIST_HEADER_SIZE (2*sizeof(unsigned int)+1) +#define ZIPLIST_ENTRY_HEAD(zl) ((zl)+ZIPLIST_HEADER_SIZE) +#define ZIPLIST_ENTRY_TAIL(zl) ((zl)+ZIPLIST_TAIL_OFFSET(zl)) +#define ZIPLIST_ENTRY_END(zl) ((zl)+ZIPLIST_BYTES(zl)-1) #define ZIPLIST_INCR_LENGTH(zl,incr) { \ if (ZIPLIST_LENGTH(zl) < ZIP_BIGLEN) ZIPLIST_LENGTH(zl)+=incr; } @@ -56,6 +59,7 @@ typedef struct zlentry { unsigned int lensize, len; unsigned int headersize; unsigned char encoding; + unsigned char *p; } zlentry; /* Return bytes needed to store integer encoded by 'encoding' */ @@ -129,23 +133,52 @@ static unsigned int zipEncodeLength(unsigned char *p, char encoding, unsigned in return len; } +/* Decode the length of the previous element stored at "p". */ +static unsigned int zipPrevDecodeLength(unsigned char *p, unsigned int *lensize) { + unsigned int len = *p; + if (len < ZIP_BIGLEN) { + if (lensize) *lensize = 1; + } else { + if (lensize) *lensize = 1+sizeof(len); + memcpy(&len,p+1,sizeof(len)); + } + return len; +} + +/* Encode the length of the previous entry and write it to "p". Return the + * number of bytes needed to encode this length if "p" is NULL. */ +static unsigned int zipPrevEncodeLength(unsigned char *p, unsigned int len) { + if (p == NULL) { + return (len < ZIP_BIGLEN) ? 1 : sizeof(len)+1; + } else { + if (len < ZIP_BIGLEN) { + p[0] = len; + return 1; + } else { + p[0] = ZIP_BIGLEN; + memcpy(p+1,&len,sizeof(len)); + return 1+sizeof(len); + } + } +} + /* Return the difference in number of bytes needed to store the new length * "len" on the entry pointed to by "p". */ static int zipPrevLenByteDiff(unsigned char *p, unsigned int len) { unsigned int prevlensize; - zipDecodeLength(p,&prevlensize); - return zipEncodeLength(NULL,ZIP_ENC_RAW,len)-prevlensize; + zipPrevDecodeLength(p,&prevlensize); + return zipPrevEncodeLength(NULL,len)-prevlensize; } /* Check if string pointed to by 'entry' can be encoded as an integer. * Stores the integer value in 'v' and its encoding in 'encoding'. * Warning: this function requires a NULL-terminated string! */ -static int zipTryEncoding(unsigned char *entry, long long *v, char *encoding) { +static int zipTryEncoding(char *entry, long long *v, char *encoding) { long long value; char *eptr; if (entry[0] == '-' || (entry[0] >= '0' && entry[0] <= '9')) { - value = strtoll((char*)entry,&eptr,10); + value = strtoll(entry,&eptr,10); if (eptr[0] != '\0') return 0; if (value >= SHRT_MIN && value <= SHRT_MAX) { *encoding = ZIP_ENC_SHORT; @@ -202,21 +235,18 @@ static long long zipLoadInteger(unsigned char *p, char encoding) { /* Return a struct with all information about an entry. */ static zlentry zipEntry(unsigned char *p) { zlentry e; - e.prevrawlen = zipDecodeLength(p,&e.prevrawlensize); + e.prevrawlen = zipPrevDecodeLength(p,&e.prevrawlensize); e.len = zipDecodeLength(p+e.prevrawlensize,&e.lensize); e.headersize = e.prevrawlensize+e.lensize; e.encoding = ZIP_ENCODING(p+e.prevrawlensize); + e.p = p; return e; } -/* Return the total amount used by an entry (encoded length + payload). */ +/* Return the total number of bytes used by the entry at "p". */ static unsigned int zipRawEntryLength(unsigned char *p) { - unsigned int prevlensize, lensize, len; - /* Byte-size of encoded length of previous entry */ - zipDecodeLength(p,&prevlensize); - /* Encoded length of this entry's payload */ - len = zipDecodeLength(p+prevlensize, &lensize); - return prevlensize+lensize+len; + zlentry e = zipEntry(p); + return e.headersize + e.len; } /* Create a new empty ziplist. */ @@ -238,94 +268,127 @@ static unsigned char *ziplistResize(unsigned char *zl, unsigned int len) { return zl; } -static unsigned char *ziplistHead(unsigned char *zl) { - return zl+ZIPLIST_HEADER_SIZE; -} - -static unsigned char *ziplistTail(unsigned char *zl) { - unsigned char *p, *q; - p = q = ziplistHead(zl); - while (*p != ZIP_END) { - q = p; +/* Delete "num" entries, starting at "p". Returns pointer to the ziplist. */ +static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, int num) { + unsigned int i, totlen, deleted = 0; + int nextdiff = 0; + zlentry first = zipEntry(p); + for (i = 0; p[0] != ZIP_END && i < num; i++) { p += zipRawEntryLength(p); + deleted++; + } + + totlen = p-first.p; + if (totlen > 0) { + if (p[0] != ZIP_END) { + /* Tricky: storing the prevlen in this entry might reduce or + * increase the number of bytes needed, compared to the current + * prevlen. Note that we can always store this length because + * it was previously stored by an entry that is being deleted. */ + nextdiff = zipPrevLenByteDiff(p,first.prevrawlen); + zipPrevEncodeLength(p-nextdiff,first.prevrawlen); + + /* Update offset for tail */ + ZIPLIST_TAIL_OFFSET(zl) -= totlen+nextdiff; + + /* Move tail to the front of the ziplist */ + memmove(first.p,p-nextdiff,ZIPLIST_BYTES(zl)-(p-zl)-1+nextdiff); + } else { + /* The entire tail was deleted. No need to move memory. */ + ZIPLIST_TAIL_OFFSET(zl) = (first.p-zl)-first.prevrawlen; + } + + /* Resize and update length */ + zl = ziplistResize(zl, ZIPLIST_BYTES(zl)-totlen+nextdiff); + ZIPLIST_INCR_LENGTH(zl,-deleted); } - return q; + return zl; } -unsigned char *ziplistPush(unsigned char *zl, unsigned char *entry, unsigned int elen, int where) { - unsigned int curlen = ZIPLIST_BYTES(zl), reqlen, prevlen; - unsigned char *p, *curtail; +/* Insert item at "p". */ +static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, char *s, unsigned int slen) { + unsigned int curlen = ZIPLIST_BYTES(zl), reqlen, prevlen = 0; + unsigned int offset, nextdiff = 0; + unsigned char *tail; char encoding = ZIP_ENC_RAW; long long value; + zlentry entry; - /* We need to store the length of the current tail when the list - * is non-empty and we push at the tail. */ - curtail = zl+ZIPLIST_TAIL_OFFSET(zl); - if (where == ZIPLIST_TAIL && curtail[0] != ZIP_END) { - prevlen = zipRawEntryLength(curtail); + /* Find out prevlen for the entry that is inserted. */ + if (p[0] != ZIP_END) { + entry = zipEntry(p); + prevlen = entry.prevrawlen; } else { - prevlen = 0; + tail = ZIPLIST_ENTRY_TAIL(zl); + if (tail[0] != ZIP_END) { + prevlen = zipRawEntryLength(tail); + } } /* See if the entry can be encoded */ - if (zipTryEncoding(entry,&value,&encoding)) { + if (zipTryEncoding(s,&value,&encoding)) { reqlen = zipEncodingSize(encoding); } else { - reqlen = elen; + reqlen = slen; } /* We need space for both the length of the previous entry and * the length of the payload. */ - reqlen += zipEncodeLength(NULL,ZIP_ENC_RAW,prevlen); - reqlen += zipEncodeLength(NULL,encoding,elen); - - /* Resize the ziplist and move if needed */ - zl = ziplistResize(zl,curlen+reqlen); - if (where == ZIPLIST_HEAD) { - p = zl+ZIPLIST_HEADER_SIZE; - if (*p != ZIP_END) { - /* Subtract one because of the ZIP_END bytes */ - memmove(p+reqlen,p,curlen-ZIPLIST_HEADER_SIZE-1); - } + reqlen += zipPrevEncodeLength(NULL,prevlen); + reqlen += zipEncodeLength(NULL,encoding,slen); + + /* When the insert position is not equal to the tail, we need to + * make sure that the next entry can hold this entry's length in + * its prevlen field. */ + nextdiff = (p[0] != ZIP_END) ? zipPrevLenByteDiff(p,reqlen) : 0; + + /* Store offset because a realloc may change the address of zl. */ + offset = p-zl; + zl = ziplistResize(zl,curlen+reqlen+nextdiff); + p = zl+offset; + + /* Apply memory move when necessary and update tail offset. */ + if (p[0] != ZIP_END) { + /* Subtract one because of the ZIP_END bytes */ + memmove(p+reqlen,p-nextdiff,curlen-offset-1+nextdiff); + /* Encode this entry's raw length in the next entry. */ + zipPrevEncodeLength(p+reqlen,reqlen); + /* Update offset for tail */ + ZIPLIST_TAIL_OFFSET(zl) += reqlen+nextdiff; } else { - p = zl+curlen-1; - } - - /* Update tail offset if this is not the first element */ - if (curtail[0] != ZIP_END) { - if (where == ZIPLIST_HEAD) { - ZIPLIST_TAIL_OFFSET(zl) += reqlen; - } else { - ZIPLIST_TAIL_OFFSET(zl) += prevlen; - } + /* This element will be the new tail. */ + ZIPLIST_TAIL_OFFSET(zl) = p-zl; } /* Write the entry */ - p += zipEncodeLength(p,ZIP_ENC_RAW,prevlen); - p += zipEncodeLength(p,encoding,elen); + p += zipPrevEncodeLength(p,prevlen); + p += zipEncodeLength(p,encoding,slen); if (encoding != ZIP_ENC_RAW) { zipSaveInteger(p,value,encoding); } else { - memcpy(p,entry,elen); + memcpy(p,s,slen); } ZIPLIST_INCR_LENGTH(zl,1); return zl; } +unsigned char *ziplistPush(unsigned char *zl, char *s, unsigned int slen, int where) { + unsigned char *p; + p = (where == ZIPLIST_HEAD) ? ZIPLIST_ENTRY_HEAD(zl) : ZIPLIST_ENTRY_END(zl); + return __ziplistInsert(zl,p,s,slen); +} + unsigned char *ziplistPop(unsigned char *zl, sds *target, int where) { - unsigned int curlen = ZIPLIST_BYTES(zl), rawlen; zlentry entry; - int nextdiff = 0; unsigned char *p; long long value; if (target) *target = NULL; /* Get pointer to element to remove */ - p = (where == ZIPLIST_HEAD) ? ziplistHead(zl) : ziplistTail(zl); + p = (where == ZIPLIST_HEAD) ? ZIPLIST_ENTRY_HEAD(zl) : ZIPLIST_ENTRY_TAIL(zl); if (*p == ZIP_END) return zl; entry = zipEntry(p); - rawlen = entry.headersize+entry.len; if (target) { if (entry.encoding == ZIP_ENC_RAW) { *target = sdsnewlen(p+entry.headersize,entry.len); @@ -335,138 +398,121 @@ unsigned char *ziplistPop(unsigned char *zl, sds *target, int where) { } } - if (where == ZIPLIST_HEAD) { - /* The next entry will now be the head of the list */ - if (p[rawlen] != ZIP_END) { - /* Tricky: storing the length of the previous entry in the next - * entry (this previous length is always 0 when popping from the - * head), might reduce the number of bytes needed. - * - * In this special case (new length is 0), we know that the - * byte difference to store is always <= 0, which means that - * we always have space to store it. */ - nextdiff = zipPrevLenByteDiff(p+rawlen,0); - zipEncodeLength(p+rawlen-nextdiff,ZIP_ENC_RAW,0); - } - /* Move list to the front */ - memmove(p,p+rawlen-nextdiff,curlen-ZIPLIST_HEADER_SIZE-rawlen+nextdiff); - - /* Subtract the gained space from the tail offset */ - ZIPLIST_TAIL_OFFSET(zl) -= rawlen+nextdiff; - } else { - /* Subtract the length of the previous element from the tail offset. */ - ZIPLIST_TAIL_OFFSET(zl) -= entry.prevrawlen; - } - - /* Resize and update length */ - zl = ziplistResize(zl,curlen-rawlen+nextdiff); - ZIPLIST_INCR_LENGTH(zl,-1); + zl = __ziplistDelete(zl,p,1); return zl; } -/* Returns an offset to use for iterating with ziplistNext. */ -unsigned char *ziplistIndex(unsigned char *zl, unsigned int index) { - unsigned char *p = zl+ZIPLIST_HEADER_SIZE; - unsigned int i = 0; - for (; i < index; i++) { - if (*p == ZIP_END) break; - p += zipRawEntryLength(p); +/* Returns an offset to use for iterating with ziplistNext. When the given + * index is negative, the list is traversed back to front. When the list + * doesn't contain an element at the provided index, NULL is returned. */ +unsigned char *ziplistIndex(unsigned char *zl, int index) { + unsigned char *p; + zlentry entry; + if (index < 0) { + index = (-index)-1; + p = ZIPLIST_ENTRY_TAIL(zl); + if (p[0] != ZIP_END) { + entry = zipEntry(p); + while (entry.prevrawlen > 0 && index--) { + p -= entry.prevrawlen; + entry = zipEntry(p); + } + } + } else { + p = ZIPLIST_ENTRY_HEAD(zl); + while (p[0] != ZIP_END && index--) { + p += zipRawEntryLength(p); + } } - return p; + return (p[0] == ZIP_END || index > 0) ? NULL : p; } /* Return pointer to next entry in ziplist. */ unsigned char *ziplistNext(unsigned char *p) { - return *p == ZIP_END ? p : p+zipRawEntryLength(p); + return (p[0] == ZIP_END) ? NULL : p+zipRawEntryLength(p); +} + +/* Return pointer to previous entry in ziplist. */ +unsigned char *ziplistPrev(unsigned char *p) { + zlentry entry = zipEntry(p); + return (entry.prevrawlen == 0) ? NULL : p-entry.prevrawlen; } /* Get entry pointer to by 'p' and store in either 'e' or 'v' depending * on the encoding of the entry. 'e' is always set to NULL to be able * to find out whether the string pointer or the integer value was set. * Return 0 if 'p' points to the end of the zipmap, 1 otherwise. */ -unsigned int ziplistGet(unsigned char *p, unsigned char **e, unsigned int *elen, long long *v) { +unsigned int ziplistGet(unsigned char *p, char **sstr, unsigned int *slen, long long *sval) { zlentry entry; - if (*p == ZIP_END) return 0; - if (e) *e = NULL; + if (p == NULL || p[0] == ZIP_END) return 0; + if (sstr) *sstr = NULL; entry = zipEntry(p); if (entry.encoding == ZIP_ENC_RAW) { - if (e) { - *elen = entry.len; - *e = p+entry.headersize; + if (sstr) { + *slen = entry.len; + *sstr = (char*)p+entry.headersize; } } else { - if (v) { - *v = zipLoadInteger(p+entry.headersize,entry.encoding); + if (sval) { + *sval = zipLoadInteger(p+entry.headersize,entry.encoding); } } return 1; } -/* Delete a range of entries from the ziplist. */ -unsigned char *ziplistDeleteRange(unsigned char *zl, unsigned int index, unsigned int num) { - unsigned char *p, *first = ziplistIndex(zl, index); - unsigned int i, totlen, deleted = 0; - for (p = first, i = 0; *p != ZIP_END && i < num; i++) { - p += zipRawEntryLength(p); - deleted++; - } - - totlen = p-first; - if (totlen > 0) { - /* Move current tail to the new tail when there *is* a tail */ - if (*p != ZIP_END) memmove(first,p,ZIPLIST_BYTES(zl)-(p-zl)-1); - - /* Resize and update length */ - zl = ziplistResize(zl, ZIPLIST_BYTES(zl)-totlen); - ZIPLIST_INCR_LENGTH(zl,-deleted); - } - return zl; +/* Insert an entry at "p". */ +unsigned char *ziplistInsert(unsigned char *zl, unsigned char *p, char *s, unsigned int slen) { + return __ziplistInsert(zl,p,s,slen); } /* Delete a single entry from the ziplist, pointed to by *p. * Also update *p in place, to be able to iterate over the * ziplist, while deleting entries. */ -unsigned char *ziplistDelete(unsigned char *zl, unsigned char **p) { - unsigned int offset = *p-zl, tail, len; - len = zipRawEntryLength(*p); - tail = ZIPLIST_BYTES(zl)-offset-len-1; - - /* Move current tail to the new tail when there *is* a tail */ - if (tail > 0) memmove(*p,*p+len,tail); - - /* Resize and update length */ - zl = ziplistResize(zl, ZIPLIST_BYTES(zl)-len); - ZIPLIST_INCR_LENGTH(zl,-1); - - /* Store new pointer to current element in p. - * This needs to be done because zl can change on realloc. */ - *p = zl+offset; +unsigned char *ziplistDelete(unsigned char *zl, unsigned char **p, int direction) { + unsigned int offset = *p-zl; + zl = __ziplistDelete(zl,*p,1); + + /* Store pointer to current element in p, because ziplistDelete will + * do a realloc which might result in a different "zl"-pointer. + * When the delete direction is back to front, we might delete the last + * entry and end up with "p" pointing to ZIP_END, so check this. */ + if (*(zl+offset) == ZIP_END && direction == ZIPLIST_HEAD) { + *p = ZIPLIST_ENTRY_TAIL(zl); + } else { + *p = zl+offset; + } return zl; } +/* Delete a range of entries from the ziplist. */ +unsigned char *ziplistDeleteRange(unsigned char *zl, unsigned int index, unsigned int num) { + unsigned char *p = ziplistIndex(zl,index); + return (p == NULL) ? zl : __ziplistDelete(zl,p,num); +} + /* Compare entry pointer to by 'p' with 'entry'. Return 1 if equal. */ -unsigned int ziplistCompare(unsigned char *p, unsigned char *s, unsigned int slen) { +unsigned int ziplistCompare(unsigned char *p, char *sstr, unsigned int slen) { zlentry entry; - unsigned char sencoding; + char sencoding; long long val, sval; - if (*p == ZIP_END) return 0; + if (p[0] == ZIP_END) return 0; entry = zipEntry(p); if (entry.encoding == ZIP_ENC_RAW) { /* Raw compare */ if (entry.len == slen) { - return memcmp(p+entry.headersize,s,slen) == 0; + return memcmp(p+entry.headersize,sstr,slen) == 0; } else { return 0; } } else { - if (zipTryEncoding(s,&sval,&sencoding)) { - /* Do integer compare */ - val = zipLoadInteger(p+entry.headersize,entry.encoding); - return val == sval; - } else { - /* Ziplist entry is integer encoded, but given entry is not. */ + /* Try to compare encoded values */ + if (zipTryEncoding(sstr,&sval,&sencoding)) { + if (entry.encoding == sencoding) { + val = zipLoadInteger(p+entry.headersize,entry.encoding); + return val == sval; + } } } return 0; @@ -496,24 +542,22 @@ unsigned int ziplistSize(unsigned char *zl) { } void ziplistRepr(unsigned char *zl) { - unsigned char *p, encoding; - unsigned int prevrawlensize, prevrawlen, lensize, len; + unsigned char *p; + zlentry entry; printf("{total bytes %d} {length %u}\n",ZIPLIST_BYTES(zl), ZIPLIST_LENGTH(zl)); - p = ziplistHead(zl); + p = ZIPLIST_ENTRY_HEAD(zl); while(*p != ZIP_END) { - prevrawlen = zipDecodeLength(p,&prevrawlensize); - len = zipDecodeLength(p+prevrawlensize,&lensize); - printf("{offset %ld, header %u, payload %u} ",p-zl,prevrawlensize+lensize,len); - encoding = ZIP_ENCODING(p+prevrawlensize); - p += prevrawlensize+lensize; - if (encoding == ZIP_ENC_RAW) { - fwrite(p,len,1,stdout); + entry = zipEntry(p); + printf("{offset %ld, header %u, payload %u} ",p-zl,entry.headersize,entry.len); + p += entry.headersize; + if (entry.encoding == ZIP_ENC_RAW) { + fwrite(p,entry.len,1,stdout); } else { - printf("%lld", zipLoadInteger(p,encoding)); + printf("%lld", zipLoadInteger(p,entry.encoding)); } printf("\n"); - p += len; + p += entry.len; } printf("{end}\n\n"); } @@ -522,10 +566,10 @@ void ziplistRepr(unsigned char *zl) { unsigned char *createList() { unsigned char *zl = ziplistNew(); - zl = ziplistPush(zl, (unsigned char*)"foo", 3, ZIPLIST_TAIL); - zl = ziplistPush(zl, (unsigned char*)"quux", 4, ZIPLIST_TAIL); - zl = ziplistPush(zl, (unsigned char*)"hello", 5, ZIPLIST_HEAD); - zl = ziplistPush(zl, (unsigned char*)"1024", 4, ZIPLIST_TAIL); + zl = ziplistPush(zl, "foo", 3, ZIPLIST_TAIL); + zl = ziplistPush(zl, "quux", 4, ZIPLIST_TAIL); + zl = ziplistPush(zl, "hello", 5, ZIPLIST_HEAD); + zl = ziplistPush(zl, "1024", 4, ZIPLIST_TAIL); return zl; } @@ -549,7 +593,8 @@ unsigned char *createIntList() { } int main(int argc, char **argv) { - unsigned char *zl, *p, *q, *entry; + unsigned char *zl, *p; + char *entry; unsigned int elen; long long value; sds s; @@ -576,6 +621,83 @@ int main(int argc, char **argv) { printf("Pop tail: %s (length %ld)\n", s, sdslen(s)); ziplistRepr(zl); + printf("Get element at index 3:\n"); + { + zl = createList(); + p = ziplistIndex(zl, 3); + if (!ziplistGet(p, &entry, &elen, &value)) { + printf("ERROR: Could not access index 3\n"); + return 1; + } + if (entry) { + fwrite(entry,elen,1,stdout); + printf("\n"); + } else { + printf("%lld\n", value); + } + printf("\n"); + } + + printf("Get element at index 4 (out of range):\n"); + { + zl = createList(); + p = ziplistIndex(zl, 4); + if (p == NULL) { + printf("No entry\n"); + } else { + printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", p-zl); + return 1; + } + printf("\n"); + } + + printf("Get element at index -1 (last element):\n"); + { + zl = createList(); + p = ziplistIndex(zl, -1); + if (!ziplistGet(p, &entry, &elen, &value)) { + printf("ERROR: Could not access index -1\n"); + return 1; + } + if (entry) { + fwrite(entry,elen,1,stdout); + printf("\n"); + } else { + printf("%lld\n", value); + } + printf("\n"); + } + + printf("Get element at index -4 (first element):\n"); + { + zl = createList(); + p = ziplistIndex(zl, -4); + if (!ziplistGet(p, &entry, &elen, &value)) { + printf("ERROR: Could not access index -4\n"); + return 1; + } + if (entry) { + fwrite(entry,elen,1,stdout); + printf("\n"); + } else { + printf("%lld\n", value); + } + printf("\n"); + } + + printf("Get element at index -5 (reverse out of range):\n"); + { + zl = createList(); + p = ziplistIndex(zl, -5); + if (p == NULL) { + printf("No entry\n"); + } else { + printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", p-zl); + return 1; + } + printf("\n"); + } + printf("Iterate list from 0 to end:\n"); { zl = createList(); @@ -639,6 +761,40 @@ int main(int argc, char **argv) { printf("\n"); } + printf("Iterate from back to front:\n"); + { + zl = createList(); + p = ziplistIndex(zl, -1); + while (ziplistGet(p, &entry, &elen, &value)) { + printf("Entry: "); + if (entry) { + fwrite(entry,elen,1,stdout); + } else { + printf("%lld", value); + } + p = ziplistPrev(p); + printf("\n"); + } + printf("\n"); + } + + printf("Iterate from back to front, deleting all items:\n"); + { + zl = createList(); + p = ziplistIndex(zl, -1); + while (ziplistGet(p, &entry, &elen, &value)) { + printf("Entry: "); + if (entry) { + fwrite(entry,elen,1,stdout); + } else { + printf("%lld", value); + } + zl = ziplistDelete(zl, &p, ZIPLIST_HEAD); + printf("\n"); + } + printf("\n"); + } + printf("Delete inclusive range 0,0:\n"); { zl = createList(); @@ -681,7 +837,7 @@ int main(int argc, char **argv) { while (ziplistGet(p, &entry, &elen, &value)) { if (entry && strncmp("foo", entry, elen) == 0) { printf("Delete foo\n"); - zl = ziplistDelete(zl, &p); + zl = ziplistDelete(zl, &p, ZIPLIST_TAIL); } else { printf("Entry: "); if (entry) { @@ -703,21 +859,21 @@ int main(int argc, char **argv) { p = ziplistIndex(zl, 0); if (!ziplistCompare(p,"hello",5)) { printf("ERROR: not \"hello\"\n"); - return; + return 1; } if (ziplistCompare(p,"hella",5)) { printf("ERROR: \"hella\"\n"); - return; + return 1; } p = ziplistIndex(zl, 3); if (!ziplistCompare(p,"1024",4)) { printf("ERROR: not \"1024\"\n"); - return; + return 1; } if (ziplistCompare(p,"1025",4)) { printf("ERROR: \"1025\"\n"); - return; + return 1; } printf("SUCCESS\n"); }