标签:根据 升级 realloc 编码范围 search static sed 整数 二分查找
整数集合是集合键的底层实现,当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis就会用整数集合作为集合键的底层实现。inset采用的是连续内存空间实现,默认是用16位整数,当加入元素/删除元素都要进行扩容缩容,如果新加入的元素大于16位,则要对空间进行扩充。
1、整数集合的结构
typedef struct intset { uint32_t encoding; //解码方式 uint32_t length; //集合包含的元素数量 int8_t contents[]; //保存元素的数组 类型取决于encoding } intset;
2、升级
1.获取value的编码
/* Return the required encoding for the provided value. */ static uint8_t _intsetValueEncoding(int64_t v) { if (v < INT32_MIN || v > INT32_MAX) return INTSET_ENC_INT64; else if (v < INT16_MIN || v > INT16_MAX) return INTSET_ENC_INT32; else return INTSET_ENC_INT16; }
2.resize数组长度
/* Resize the intset */ static intset *intsetResize(intset *is, uint32_t len) { uint32_t size = len*intrev32ifbe(is->encoding); is = zrealloc(is,sizeof(intset)+size); return is; }
3.根据编码类型将value放到指定位置
//根据编码类型将值放入到指定位置 static void _intsetSet(intset *is, int pos, int64_t value) { uint32_t encoding = intrev32ifbe(is->encoding); if (encoding == INTSET_ENC_INT64) { ((int64_t*)is->contents)[pos] = value; memrev64ifbe(((int64_t*)is->contents)+pos); } else if (encoding == INTSET_ENC_INT32) { ((int32_t*)is->contents)[pos] = value; memrev32ifbe(((int32_t*)is->contents)+pos); } else { ((int16_t*)is->contents)[pos] = value; memrev16ifbe(((int16_t*)is->contents)+pos); } }
4.升级
/* Upgrades the intset to a larger encoding and inserts the given integer. */ static intset *intsetUpgradeAndAdd(intset *is, int64_t value) { uint8_t curenc = intrev32ifbe(is->encoding); //set encoding uint8_t newenc = _intsetValueEncoding(value); //value encoding int length = intrev32ifbe(is->length); //set 长度 int prepend = value < 0 ? 1 : 0; /* First set new encoding and resize */ is->encoding = intrev32ifbe(newenc); is = intsetResize(is,intrev32ifbe(is->length)+1); /* Upgrade back-to-front so we don‘t overwrite values. * Note that the "prepend" variable is used to make sure we have an empty * space at either the beginning or the end of the intset. */ while(length--) _intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc)); /* Set the value at the beginning or the end. */ //因为value的编码比原来的编码都要大,所以values的值要么大于集合中的所有元素, //又或者value是小于原来编码范围的负数 小于集合中的所有元素,所以value的值要么添加在set的首位,要么是末尾 if (prepend) _intsetSet(is,0,value); else _intsetSet(is,intrev32ifbe(is->length),value); is->length = intrev32ifbe(intrev32ifbe(is->length)+1); return is; }
5.升级的特点
1.提升灵活性;
2.节约内存;
6.查找
//判断value是否存在 pos保存位置 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 */ //处理is为空的状态 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. */ //value比set里面最后一个值都大 那肯定不在数组中 if (value > _intsetGet(is,intrev32ifbe(is->length)-1)) { if (pos) *pos = intrev32ifbe(is->length); return 0; } else if (value < _intsetGet(is,0)) { //value比set里第一个值都小 那肯定不在数组中 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; } }
3、降级
整数集合不支持降级操作。
标签:根据 升级 realloc 编码范围 search static sed 整数 二分查找
原文地址:https://www.cnblogs.com/chenyang920/p/13162298.html