整数集,为redis中的一种结构体,你可以把它理解成stl中的std::<set>,当然redis专门定制化这种结构是为了优化内存效率和查找效率。
#define INTSET_ENC_INT16 (sizeof(int16_t)) //16位编码
#define INTSET_ENC_INT32 (sizeof(int32_t)) //32位编码
#define INTSET_ENC_INT64 (sizeof(int64_t)) //64位编码
#ifndef __INTSET_H
#define __INTSET_H
#include <stdint.h>
typedef struct intset {
uint32_t encoding;//保存元素所使用类型的长度
uint32_t length;//保存元素的个数
int8_t contents[];//保存元素的数组
} intset;
intset *intsetNew(void); //新建一个inset实例
intset *intsetAdd(intset *is, int64_t value, uint8_t *success);//添加一个元素
intset *intsetRemove(intset *is, int64_t value, int *success);//删除一个元素
uint8_t intsetFind(intset *is, int64_t value);//查找元素
int64_t intsetRandom(intset *is);//随机返回一个元素
uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value);//获取具体位置的元素
uint32_t intsetLen(const intset *is);//返回intset的长度
size_t intsetBlobLen(intset *is);//返回整数集合现在占用的字节数
//验证数据结构的完整性。
//当'deep'为0时,仅验证标头的完整性。
//当'deep'为1时,我们确保没有重复或无序的记录
int intsetValidateIntegrity(const unsigned char *is, size_t size, int deep);
#ifdef REDIS_TEST
int intsetTest(int argc, char *argv[], int accurate);//测试intse用
#endif
#endif // __INTSET_H
在intset.c源码中,提供了三种编码类型,16位、32位和64位,用户可以根据需要定制各种类型的整数集。intset内部也提供可动态伸缩编码类型的函数
/* Upgrades the intset to a larger encoding and inserts the given integer. */
static intset *intsetUpgradeAndAdd(intset *is, int64_t value)
inset内部查找算法,一个二分查找算法。
/* Search for the position of "value". Return 1 when the value was found and
* sets "pos" to the position of the value within the intset. Return 0 when
* the value is not present in the intset and sets "pos" to the position
* where "value" can be inserted. */
static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
int min = 0, max = intrev32ifbe(is->length)-1, mid = -1;
int64_t cur = -1;
/* The value can never be found when the set is empty */
if (intrev32ifbe(is->length) == 0) {
if (pos) *pos = 0;
return 0;
} else {
/* Check for the case where we know we cannot find the value,
* but do know the insert position. */
if (value > _intsetGet(is,max)) {
if (pos) *pos = intrev32ifbe(is->length);
return 0;
} else if (value < _intsetGet(is,0)) {
if (pos) *pos = 0;
return 0;
}
}
while(max >= min) {
mid = ((unsigned int)min + (unsigned int)max) >> 1;
cur = _intsetGet(is,mid);
if (value > cur) {
min = mid+1;
} else if (value < cur) {
max = mid-1;
} else {
break;
}
}
if (value == cur) {
if (pos) *pos = mid;
return 1;
} else {
if (pos) *pos = min;
return 0;
}
}