概述:
本节我们介绍Twemproxy的两个重要的自定义数据结构:array和string。
array:
故名思议,array就是数组,array的代码在nc_array.c和nc_array.h中,我们先来看看array的结构:
数据结构:
1
2
3
4
5
6
|
struct
array
{
uint32_t
nelem
;
/* # element */
void
*
elem
;
/* element */
size_t
size
;
/* element size */
uint32_t
nalloc
;
/* # allocated element */
}
;
|
array的结构包含:
- 当前数组中元素的数量
- 指向元素的void指针
- 元素的大小
- 预申请的空间的元素数
由此可见,array应该具有以下特点:
- 需要预申请空间,空间不足则需要重新申请
- 数组每个元素大小必须相同
后面我们将通过数组的操作验证。
操作:
对数组的操作包含下面这些,这些都是在nc_array.h中声明和定义的:
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
|
/** 将数组置为null **/
static
inline
void
array_null
(
struct
array
*
a
)
{
a
->
nelem
=
0
;
a
->
elem
=
NULL
;
a
->
size
=
0
;
a
->
nalloc
=
0
;
}
/** 设置一个数组struct的值 **/
static
inline
void
array_set
(
struct
array
*
a
,
void
*
elem
,
size_t
size
,
uint32_t
nalloc
)
{
a
->
nelem
=
0
;
a
->
elem
=
elem
;
a
->
size
=
size
;
a
->
nalloc
=
nalloc
;
}
/** 返回数组的元素数 **/
static
inline
uint32_t
array_n
(
const
struct
array
*
a
)
{
return
a
->
nelem
;
}
struct
array
*
array_create
(
uint32_t
n
,
size_t
size
)
;
//创建包含n个大小为size的elements的数组
void
array_destroy
(
struct
array
*
a
)
;
//销毁一个数组
rstatus_t
array_init
(
struct
array
*
a
,
uint32_t
n
,
size_t
size
)
;
//初始化一个数组
void
array_deinit
(
struct
array
*
a
)
;
//deinit
uint32_t
array_idx
(
struct
array
*
a
,
void
*
elem
)
;
//返回元素的数组下标
void
*
array_push
(
struct
array
*
a
)
;
//push一个元素,返回该元素的指针
void
*
array_pop
(
struct
array
*
a
)
;
//pop一个元素,返回这个元素的指针
void
*
array_get
(
struct
array
*
a
,
uint32_t
idx
)
;
//返回idx位置上的元素
void
*
array_top
(
struct
array
*
a
)
;
//返回队尾的元素
void
array_swap
(
struct
array
*
a
,
struct
array
*
b
)
;
//交换两个数组
void
array_sort
(
struct
array
*
a
,
array_compare_t
compare
)
;
//数组排序
rstatus_t
array_each
(
struct
array
*
a
,
array_each_t
func
,
void
*
data
)
;
//数组迭代
|
接下来我们通过create和push验证一下我们之前的猜想:
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
|
struct
array
*
array_create
(
uint32_t
n
,
size_t
size
)
{
struct
array
*
a
;
ASSERT
(
n
!=
0
&&
size
!=
0
)
;
a
=
nc_alloc
(
sizeof
(
*
a
)
)
;
//申请array的空间
if
(
a
==
NULL
)
{
return
NULL
;
}
a
->
elem
=
nc_alloc
(
n *
size
)
;
//预申请elements空间
if
(
a
->
elem
==
NULL
)
{
nc_free
(
a
)
;
return
NULL
;
}
a
->
nelem
=
0
;
a
->
size
=
size
;
a
->
nalloc
=
n
;
return
a
;
}
void
*
array_push
(
struct
array
*
a
)
{
void
*
elem
,
*
new
;
size_t
size
;
if
(
a
->
nelem
==
a
->
nalloc
)
{
/* array已满,重新申请空间,重新申请的大小为原来的2倍 */
size
=
a
->
size *
a
->
nalloc
;
new
=
nc_realloc
(
a
->
elem
,
2
*
size
)
;
if
(
new
==
NULL
)
{
return
NULL
;
}
a
->
elem
=
new
;
a
->
nalloc *
=
2
;
}
elem
=
(
uint8_t *
)
a
->
elem
+
a
->
size *
a
->
nelem
;
a
->
nelem
++
;
//增加element数
return
elem
;
}
|
从代码可以看出是如何realloc空间的,这里实现的奇怪的是,push操作是将elements数加1,然后返回末尾的element指针。也就是说,调用者需要先调用array_push得到elements指针,然后为其设置字段值,来完成数组元素的push。
另外值得一提的是,array提供了create/destroy和init/deinit这两组创建和销毁函数,这两组函数的区别是:create/destroy同时创建/销毁array和elements空间,而init和deinit只创建/销毁elements空间,看一下array_destroy代码就明白了:
1
2
3
4
5
6
|
void
array_destroy
(
struct
array
*
a
)
{
array_deinit
(
a
)
;
nc_free
(
a
)
;
}
|
array的代码很少,只有200多行,就不详细介绍其他的操作了。
string:
string的代码在nc_string.c和nc_string.h中,封装了一些对字符串的操作。
数据结构:
1
2
3
4
|
struct
string
{
uint32_t
len
;
/* string length */
uint8_t
*
data
;
/* string data */
}
;
|
string的结构包含两个字段:字符串的长度、指向字符串的指针,就这么简单。
操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/** set字符串 **/
#define string_set_text(_str, _text) do { \
(
_str
)
->
len
=
(
uint32_t
)
(
sizeof
(
_text
)
-
1
)
;
\
(
_str
)
->
data
=
(
uint8_t *
)
(
_text
)
;
\
}
while
(
0
)
;
/** set字符串 **/
#define string_set_raw(_str, _raw) do { \
(
_str
)
->
len
=
(
uint32_t
)
(
nc_strlen
(
_raw
)
)
;
\
(
_str
)
->
data
=
(
uint8_t *
)
(
_raw
)
;
\
}
while
(
0
)
;
void
string_init
(
struct
string
*
str
)
;
//初始化string
void
string_deinit
(
struct
string
*
str
)
;
//dinit
bool
string_empty
(
const
struct
string
*
str
)
;
//判断字符串是否是空
rstatus_t
string_duplicate
(
struct
string
*
dst
,
const
struct
string
*
src
)
;
//duplicate一个字符串
rstatus_t
string_copy
(
struct
string
*
dst
,
const
uint8_t *
src
,
uint32_t
srclen
)
;
//copy一个字符串
int
string_compare
(
const
struct
string
*
s1
,
const
struct
string
*
s2
)
;
//字符串比较
|
底下还有用宏定义的一些操作,不过都是操作char*的,这里就不列举了。总的来说string的结构很简单,代码也只有100多行。
小结:
本节我们看了一下array和string这两个数据结构,都很简单,后面我们马上会用到。