+/* Structure to hold set iteration abstraction. */
+typedef struct {
+ robj *subject;
+ unsigned char encoding;
+ unsigned char *zi;
+ listNode *ln;
+} lIterator;
+
+/* Initialize an iterator at the specified index. */
+static lIterator *lInitIterator(robj *subject, int index) {
+ lIterator *li = zmalloc(sizeof(lIterator));
+ li->subject = subject;
+ li->encoding = subject->encoding;
+ if (li->encoding == REDIS_ENCODING_ZIPLIST) {
+ li->zi = ziplistIndex(subject->ptr,index);
+ } else if (li->encoding == REDIS_ENCODING_LIST) {
+ li->ln = listIndex(subject->ptr,index);
+ } else {
+ redisPanic("Unknown list encoding");
+ }
+ return li;
+}
+
+/* Clean up the iterator. */
+static void lReleaseIterator(lIterator *li) {
+ zfree(li);
+}
+
+/* Return entry or NULL at the current position of the iterator. */
+static robj *lGet(lIterator *li) {
+ robj *value = NULL;
+ if (li->encoding == REDIS_ENCODING_ZIPLIST) {
+ char *v;
+ unsigned int vlen;
+ long long vval;
+ redisAssert(li->zi != NULL);
+ if (ziplistGet(li->zi,&v,&vlen,&vval)) {
+ if (v) {
+ value = createStringObject(v,vlen);
+ } else {
+ value = createStringObjectFromLongLong(vval);
+ }
+ }
+ } else if (li->encoding == REDIS_ENCODING_LIST) {
+ redisAssert(li->ln != NULL);
+ value = listNodeValue(li->ln);
+ incrRefCount(value);
+ } else {
+ redisPanic("Unknown list encoding");
+ }
+ return value;
+}
+
+/* Move to the next or previous entry in the list. */
+static void lMove(lIterator *li, int where) {
+ if (li->encoding == REDIS_ENCODING_ZIPLIST) {
+ redisAssert(li->zi != NULL);
+ if (where == REDIS_HEAD)
+ li->zi = ziplistPrev(li->zi);
+ else
+ li->zi = ziplistNext(li->zi);
+ } else if (li->encoding == REDIS_ENCODING_LIST) {
+ redisAssert(li->ln != NULL);
+ if (where == REDIS_HEAD)
+ li->ln = li->ln->prev;
+ else
+ li->ln = li->ln->next;
+ } else {
+ redisPanic("Unknown list encoding");
+ }
+}