function to insert an element at an arbitrary position in the list

This commit is contained in:
Pieter Noordhuis 2010-05-29 18:52:49 +02:00
parent 0c0d056412
commit 6435c76772

View File

@ -286,66 +286,79 @@ static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, int n
return zl; return zl;
} }
unsigned char *ziplistPush(unsigned char *zl, unsigned char *entry, unsigned int elen, int where) { /* Insert item at "p". */
unsigned int curlen = ZIPLIST_BYTES(zl), reqlen, prevlen; static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen) {
unsigned char *p, *curtail; unsigned int curlen = ZIPLIST_BYTES(zl), reqlen, prevlen = 0;
unsigned int offset, nextdiff = 0;
unsigned char *tail;
char encoding = ZIP_ENC_RAW; char encoding = ZIP_ENC_RAW;
long long value; long long value;
zlentry entry;
/* We need to store the length of the current tail when the list /* Find out prevlen for the entry that is inserted. */
* is non-empty and we push at the tail. */ if (p[0] != ZIP_END) {
curtail = zl+ZIPLIST_TAIL_OFFSET(zl); entry = zipEntry(p);
if (where == ZIPLIST_TAIL && curtail[0] != ZIP_END) { prevlen = entry.prevrawlen;
prevlen = zipRawEntryLength(curtail);
} else { } else {
prevlen = 0; tail = ziplistTail(zl);
if (tail[0] != ZIP_END) {
prevlen = zipRawEntryLength(tail);
}
} }
/* See if the entry can be encoded */ /* See if the entry can be encoded */
if (zipTryEncoding(entry,&value,&encoding)) { if (zipTryEncoding(s,&value,&encoding)) {
reqlen = zipEncodingSize(encoding); reqlen = zipEncodingSize(encoding);
} else { } else {
reqlen = elen; reqlen = slen;
} }
/* We need space for both the length of the previous entry and /* We need space for both the length of the previous entry and
* the length of the payload. */ * the length of the payload. */
reqlen += zipEncodeLength(NULL,ZIP_ENC_RAW,prevlen); reqlen += zipEncodeLength(NULL,ZIP_ENC_RAW,prevlen);
reqlen += zipEncodeLength(NULL,encoding,elen); reqlen += zipEncodeLength(NULL,encoding,slen);
/* Resize the ziplist and move if needed */ /* When the insert position is not equal to the tail, we need to
zl = ziplistResize(zl,curlen+reqlen); * make sure that the next entry can hold this entry's length in
if (where == ZIPLIST_HEAD) { * its prevlen field. */
p = zl+ZIPLIST_HEADER_SIZE; nextdiff = p[0] != ZIP_END ? zipPrevLenByteDiff(p,reqlen) : 0;
if (*p != ZIP_END) {
/* Subtract one because of the ZIP_END bytes */ /* Store offset because a realloc may change the address of zl. */
memmove(p+reqlen,p,curlen-ZIPLIST_HEADER_SIZE-1); 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. */
zipEncodeLength(p+reqlen,ZIP_ENC_RAW,reqlen);
/* Update offset for tail */
ZIPLIST_TAIL_OFFSET(zl) += reqlen+nextdiff;
} else { } else {
p = zl+curlen-1; /* This element will be the new tail. */
} ZIPLIST_TAIL_OFFSET(zl) = p-zl;
/* 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;
}
} }
/* Write the entry */ /* Write the entry */
p += zipEncodeLength(p,ZIP_ENC_RAW,prevlen); p += zipEncodeLength(p,ZIP_ENC_RAW,prevlen);
p += zipEncodeLength(p,encoding,elen); p += zipEncodeLength(p,encoding,slen);
if (encoding != ZIP_ENC_RAW) { if (encoding != ZIP_ENC_RAW) {
zipSaveInteger(p,value,encoding); zipSaveInteger(p,value,encoding);
} else { } else {
memcpy(p,entry,elen); memcpy(p,s,slen);
} }
ZIPLIST_INCR_LENGTH(zl,1); ZIPLIST_INCR_LENGTH(zl,1);
return zl; return zl;
} }
unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int slen, int where) {
unsigned char *p;
p = (where == ZIPLIST_HEAD) ? ziplistHead(zl) : (zl+ZIPLIST_BYTES(zl)-1);
return __ziplistInsert(zl,p,s,slen);
}
unsigned char *ziplistPop(unsigned char *zl, sds *target, int where) { unsigned char *ziplistPop(unsigned char *zl, sds *target, int where) {
zlentry entry; zlentry entry;
unsigned char *p; unsigned char *p;