redis inset整数集合的源码分析

       inset是redis中用于保存整数值的集合抽象数据结构,可以保存类型为int16_t,int32_t,int64_t的整数值,并且在集合中不会出现重复整数值。

       一个inset就表示一个整数集合:

typedef struct intset {
      uint32_t encoding;
      uint32_t length;
      int8_t contents[];
    } intset;

      encoding记录来编码方式

#define INTSET_ENC_INT16 (sizeof(int16_t))
#define INTSET_ENC_INT32 (sizeof(int32_t))
#define INTSET_ENC_INT64 (sizeof(int64_t))

       length记录了整数集合包含的元素个数,即content数组的长度。

       contents数组是整数集合的底层实现:整数集合中的每个元素就是centents数组的每个元素,其中的每个元素都是按数值从小到大排列的,且元素不重复。虽然在结构体中contents被声明为int8_t类型数组,但是contents不会保存任何int8_t类型的元素,保存的正真的类型取决于encodeing。(contents[]这种结构体最后一个成员为[]数组的声明方式,不需要初始化,数组 名就是所在的偏移地址)

       整数集合的基本操作

//整数集合的初始化,不进行集合内存的预分配(每次添加需要重新分配内存),只初始化encoding和length。
intset *intsetNew(void) {
    intset *is = zmalloc(sizeof(intset));
    is->encoding = intrev32ifbe(INTSET_ENC_INT16);//初始化编码为INTSET_ENC_INT16
    is->length = 0;//长度为0
    return is;
}
static intset *intsetResize(intset *is, uint32_t len);//重新分配contents数组指定长度的内存
//用二分查找在contents数组中查找value,返回pos
static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos);
//添加value到contents正确的位置,保证inset的有序性
intset *intsetAdd(intset *is, int64_t value, uint8_t *success);
//从整数集合中删除指定value
intset *intsetRemove(intset *is, int64_t value, int *success);
uint8_t intsetFind(intset *is, int64_t value);//在inset查找value
int64_t intsetRandom(intset *is);//从整数集合中随机获取一个value
uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value);//获取整数集合指定位置的value
size_t intsetBlobLen(intset *is);//获取整数集合占用的字节数

       由于每次我们添加新元素到整数集合中,可能新元素的类型会比整数集合中现有的类型要长,所以需要升级类型这一操作,才能进行元素添加。

    升级整数集合并添加新元素主要分三步:

    1)根据新元素的类型,扩展整数集合底层数组contents的空间大小;

    2)将底层数组现有的所有元素转换成与新元素相同的类型,并将类型转换后的元素放到正确位置,并保证有序性不变

    3)将新元素添加到底层数组中;

//升级整数集合类型,并添加新元素
static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {
    uint8_t curenc = intrev32ifbe(is->encoding);
    uint8_t newenc = _intsetValueEncoding(value);
    int length = intrev32ifbe(is->length);
    /*由于要升级类型,所有value的绝对值笔集合中的所有值都大,当
    value<0时,value放在contents的第一个,反之放最后一个*/
    int prepend = value < 0 ? 1 : 0;
    //更新集合的encoding,根据encoding扩展整数集合的空间大小
    is->encoding = intrev32ifbe(newenc);
    is = intsetResize(is,intrev32ifbe(is->length)+1);
    while(length--)
        _intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc));
    if (prepend)
        _intsetSet(is,0,value);//value为最小值
    else//value为最大值
        _intsetSet(is,intrev32ifbe(is->length),value);
    is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
    return is;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值