/* 返回壓縮表zl的第index個結點,
index爲非負:從表頭開始查找,0表示返回第一個結點
index爲負:從表尾開始查找,-1表示返回最後一個結點
*/
unsigned char *ziplistIndex(unsigned char *zl, int index) {
unsigned char *p; /* 保存目標結點地址 */
zlentry entry; /* 未對改變量進行初始化,考慮到該變量會被函數zipEntry返回值直接賦值,可以原諒未初始化 */
if (index < 0) {
/* 將索引轉換爲正數,因爲負數索引從-1開始,所以轉換爲正數之後索引值-1,
保證索引爲-1,通過計算獲得索引是0,指向的是從表尾開始查找時的最後一個結點 */
index = (-index) - 1;
/* p指向表尾結點,即最後一個結點 */
p = ZIPLIST_ENTRY_TAIL(zl);
/* 如果壓縮表不爲空 */
if (p[0] != ZIP_END) {
entry = zipEntry(p); /* 只有列表不爲空時,p才指向一個結點,才能獲得p指向的結點信息entry */
/* 通過遍歷index次獲得指定索引的結點 */
/* prevrawlen:前置結點的長度 */
while (entry.prevrawlen > 0 && index--) {
p -= entry.prevrawlen;
entry = zipEntry(p); /* 必須確保前置結點長度大於0(entry.prevrawlen > 0),該操作纔有意義 */
}
}
} else {
/* 獲得壓縮表的第一個結點指針 */
p = ZIPLIST_ENTRY_HEAD(zl);
/* 通過遍歷index次獲得指定索引的結點 */
/* p[0] != ZIP_END:保證p執行的結點是有效結點 */
while (p[0] != ZIP_END && index--) {
p += zipRawEntryLength(p); /* 函數zipRawEntryLength功能:返回p指向的結點佔用的字節長度 */
}
}
/* p[0] == ZIP_END:指定的索引值大於0時查找,查找到表尾,還沒有查找到指定索引的結點,
或者p[0] == ZIP_END的同時,index=0,此時索引值大於壓縮表的結點數,仍然返回NULL;
index > 0:指定的索引值小於0時查找,已經到表頭,index仍然大於0,說明指定的索引值超出壓縮表的索引範圍*/
return (p[0] == ZIP_END || index > 0) ? NULL : p;
}