Lighttpd提供了一个通用数组,这个数组与程序的其他部分练习较少,因此可以单独进行分析。
首先要说一下Lighttpd中的定义的一些数据结构。
在array.h中有下面的定义:
这是一个枚举类型,定义了各个数据类型的标志。从中可以看出程序中所定义使用的数据类型的种类和个数。
Lighttpd在定义数据类型的时候使用了面向对象的思想,因此,程序具有很好的扩展性和适应性。这些类型中,最重要的是UNSET类型,这个类型在所有的数据类型中,起到了父类型的作用。在array.h中,UNSET类型的定义如下:
 data_unset {
    DATA_UNSET;
} data_unset;
其中,UNSET类型数据的定义中,数据的实际定义部分使用宏DATA_UNSET,这样可以方便其他类型在定义中直接引用DATA_UNSET宏来模拟继承。在宏DATA_UNSET中,定义了下面五个函数指针:
这五个函数指针相当于UNSET的成员函数,其他类型可以通过对这五个指针赋值来实现成员函数的重写(Overwrite)。每种类型都配有自己特有的初始化函数,形式为:data_XXXXX *data_XXXXX_init(void)。在这些初始化函数中,对上面这五个函数指针进行赋值,当然,赋值的函数都应先定义好。
这几种类型的继承关系图如下:(类图)

 Lighttpd1.4.20源码分析之array.c(h) -----通用数组

下面分析一下STRING类型的初始化函数data_string * data_string_init(void):

其他类型的init函数,以及其他函数都不难,读者可自行查看代码。
至于各个类型的用处以及各个类型中个成员变量的含义,暂且不用关心,只要知道这七个类型之间的关系即可,除了UNSET类型,其他类型的操作函数的实现都在文件data_XXXXX.c中。这些函数的实现都很简单,不在一一介绍,读者可自己看看。这七个类型构成了通用数组所要处理的类型,其中,在数组的定义和实现中只使用UNSET类型,利用上面的定义,通用数组可以不用关心数组中存储的到底是哪种具体的类型,只需将其按照UNSET类型来处理就可以了。这就实现了通用数组。
下面这个定义是通用数组的核心定义,也就是定义了数组。。。
 is_weakref;                
} array;
各个变量的含义见上。
array.h中还有一个定义:
1 typedef struct {
2  DATA_UNSET;
3  array *value;
4 } data_array;
5 
这个定义了一个array类型的数据,也就是说,通用数组中存放的数据可以数通用数组,这样可以形成多维的通用数组。
在array.h中定义了如下的通用数组操作函数:
1、array *array_init(void);
初始化数组,分配空间。
2、array *array_init_array(array * a);
用数组a来初始化一个数组。也就是得到一个a的深拷贝。
3、void array_free(array * a);
释放数组。释放所有空间。
4、void array_reset(array * a);
重置data中的所有数据(调用UNSET类型数据中的reset函数),并将used设为0。相当于清空数组。
5、int array_insert_unique(array * a, data_unset * str);
将str插入到数组中。
6、data_unset *array_pop(array * a);
弹出data中的最后一个元素,返回奇指针,data中的最后一个位置设为NULL。
7、int array_print(array * a, int depth);
打印数组中的内容。depth参数用于在打印多维数组时,实现缩进。
8、a_unset *array_get_unused_element(array * a, data_type_t t);
返回第一个未使用的数据,也就是used位置的数据,这个数据不在数组中,返回这个数据指针后,将data[unsed]设为NULL。可能返回NULL。
9、data_unset *array_get_element(array * a, const char *key);
根据key值,返回数组中key值与之相同的数据
10、data_unset *array_replace(array * a, data_unset * du);
       如果数组中有与du的key值相同的数据,则用du替换那个数据,并返回那个数据的指针。如果不存在,则把du插入到数组中。(调用data_insert_unique函数)
11、 int array_strcasecmp(const char *a, size_t a_len, const char *b, size_t b_len);
这个函数并没用实现,仅仅给出了上面的定义。也许这个是用来比较两个字符串,并且可能会忽略大小写。
12、void array_print_indent(int depth);
根据depth打印空白,实现缩进。
13、size_t array_get_max_key_length(array * a);
返回数组中最长的key的长度。

另外,在array.c中定义了一个辅助函数static intarray_get_index(array *a, const char *key, size_t keylen, int *rndx)。这个函数的作用是通过key值,查找数据,返回其在数组data中的下标位置,并通过参数rndx返回其下标在数组sorted中的位置。
函数的定义如下:

在上面列出的函数中,还有一个函数要重点讲解一下,也是最复杂的一个函数:int array_insert_unique(array *a, data_unset *str)。这个函数将数据str插入到数组中,当并不是单纯的插入,如果数组中存在key于str相同的数据,则把str的内容拷贝到这个数据中。
其他函数都很简单,读者可自己查看。另外,print函数虽然复杂,但对整个程序的意义不大,读者可自行查看。

总结:
  Lighttpd中的通用数组的设置主要是使用的面向对象的思想,使数组具有很好的扩展性和适应性。通用数组中二分查找的实现也是一个特色。还有就是使用sorted数组只对data中的数据的下标排序,这也是一个很有用的技巧。

  以上就是我的一点拙见,还望读者网友对疏漏之处进行批评指正。 


相关文章:

  • 2021-08-06
  • 2021-07-18
  • 2022-02-23
  • 2022-01-19
  • 2021-06-15
  • 2021-09-19
  • 2022-02-08
猜你喜欢
  • 2021-11-15
  • 2022-01-15
  • 2021-12-12
  • 2021-12-15
  • 2022-03-01
  • 2021-10-10
  • 2021-07-22
相关资源
相似解决方案