1
2
3
4
5
|
typedef
struct
intset {
uint32_t encoding;
// 编码方式
uint32_t length;
// 集合包含的元素数量
int8_t contents[];
// 保存元素的数组
} intset;
|
1
2
3
|
#define INTSET_ENC_INT16 (sizeof(int16_t))
#define INTSET_ENC_INT32 (sizeof(int32_t))
#define INTSET_ENC_INT64 (sizeof(int64_t))
|
1
2
3
4
5
6
7
8
|
intset *intsetNew(
void
);
//新建一个整数集合
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);
//获取指定pos位置上的元素值
uint32_t intsetLen(intset *is);
//获取整数集合元素的个数
size_t
intsetBlobLen(intset *is);
//返回整数集合现在占用的字节总数量
|
1
2
3
4
5
6
|
intset *intsetNew(
void
) {
intset *is = zmalloc(
sizeof
(intset));
is->encoding = intrev32ifbe(INTSET_ENC_INT16);
is->length = 0;
return
is;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
/* Insert an integer in the intset */
intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {
uint8_t valenc = _intsetValueEncoding(value);
uint32_t pos;
if
(success) *success = 1;
/* Upgrade encoding if necessary. If we need to upgrade, we know that
* this value should be either appended (if > 0) or prepended (if < 0),
* because it lies outside the range of existing values. */
if
(valenc > intrev32ifbe(is->encoding)) {
/* This always succeeds, so we don't need to curry *success. */
return
intsetUpgradeAndAdd(is,value);
}
else
{
/* Abort if the value is already present in the set.
* This call will populate "pos" with the right position to insert
* the value when it cannot be found. */
if
(intsetSearch(is,value,&pos)) {
if
(success) *success = 0;
return
is;
}
is = intsetResize(is,intrev32ifbe(is->length)+1);
if
(pos < intrev32ifbe(is->length)) intsetMoveTail(is,pos,pos+1);
}
_intsetSet(is,pos,value);
is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
return
is;
}
/* 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);
uint8_t newenc = _intsetValueEncoding(value);
int
length = intrev32ifbe(is->length);
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. */
if
(prepend)
_intsetSet(is,0,value);
else
_intsetSet(is,intrev32ifbe(is->length),value);
is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
return
is;
}
/* 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,intrev32ifbe(is->length)-1)) {
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;
}
}
|