系统程序员成长计划

2019 年 01 月 24 日

第一章 从双向链表学习设计

1.3 Wirte once, run anywhere (WORA)

  • 让C++可以调用
# ifdef __cplusplus
extern "C" {
#endif

//.....

# ifdef __cplusplus
}
#endif

1.4 拥抱变化

/*
 * File:    dlist.h
 */

#ifndef DLIST_H
#define DLIST_H

#ifdef __cplusplus
extern "C" {
#endif/*__cplusplus*/

typedef enum _DListRet
{
	DLIST_RET_OK,
	DLIST_RET_OOM,
	DLIST_RET_STOP,
	DLIST_RET_PARAMS,
	DLIST_RET_FAIL
}DListRet;

struct _DList;
typedef struct _DList DList;

typedef DListRet (*DListDataPrintFunc)(void* data);

DList* dlist_create(void);

DListRet dlist_insert(DList* thiz, size_t index, void* data);
DListRet dlist_prepend(DList* thiz, void* data);
DListRet dlist_append(DList* thiz, void* data);
DListRet dlist_delete(DList* thiz, size_t index);
DListRet dlist_get_by_index(DList* thiz, size_t index, void** data);
DListRet dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
DListRet dlist_print(DList* thiz, DListDataPrintFunc print);

void dlist_destroy(DList* thiz);

#ifdef __cplusplus
}
#endif/*__cplusplus*/

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	DListNode* first;
};

static DListNode* dlist_node_create(void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL) {
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_node_destroy(DListNode* node)
{
	if(node != NULL) {
		node->next = NULL;
		node->prev = NULL;
		free(node);
	}
	return;
}

DList* dlist_create(void)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL){
		thiz->first = NULL;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0){
		iter = iter->next;
		index--;
	}

	if(!fail_return_last) {
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

DListRet dlist_insert(DList* thiz, size_t index, void* data)
{
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	if((node = dlist_node_create(data)) == NULL) {
		return DLIST_RET_OOM; 
	}

	if(thiz->first == NULL) {
		thiz->first = node;
		return DLIST_RET_OK;
	}

	cursor = dlist_get_node(thiz, index, 1);
	
	if(index < dlist_length(thiz)) {
		if(thiz->first == cursor) {
			thiz->first = node;
		}else{
			cursor->prev->next = node;
			node->prev = cursor->prev;
		}
		node->next = cursor;
		cursor->prev = node;
	}else{
		cursor->next = node;
		node->prev = cursor;
	}

	return DLIST_RET_OK;
}

DListRet dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

DListRet dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

DListRet dlist_delete(DList* thiz, size_t index)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		if(cursor == thiz->first){
			thiz->first = cursor->next;
		}

		if(cursor->next != NULL){
			cursor->next->prev = cursor->prev;
		}

		if(cursor->prev != NULL){
			cursor->prev->next = cursor->next;
		}

		dlist_node_destroy(cursor);
	}

	return DLIST_RET_OK;
}

DListRet dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		*data = cursor->data;
	}

	return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

DListRet dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		cursor->data = data;
	}

	return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = thiz->first;

	while(iter != NULL){
		length++;
		iter = iter->next;
	}

	return length;
}

DListRet dlist_print(DList* thiz, DListDataPrintFunc print)
{
	DListRet ret = DLIST_RET_OK;
	DListNode* iter = thiz->first;

	while(iter != NULL){
		print(iter->data);
		iter = iter->next;
	}

	return ret;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = thiz->first;
	DListNode* next = NULL;

	while(iter != NULL){
		next = iter->next;
		dlist_node_destroy(iter);
		iter = next;
	}

	thiz->first = NULL;
	free(thiz);

	return;
}
/*
* 1.4 拥抱拜变化 
*/

/* 
 * File:    dlist.c
 */

#include <stdio.h>
#include <assert.h>
#include "dlist.h"

static DListRet print_int(void* data)
{
	printf("%d ", (int)data);

	return DLIST_RET_OK;
}

int main(int argc, char* argv[])
{
	int i = 0;
	int n = 100;
	DList* dlist = dlist_create();

	for(i = 0; i < n; i++)
	{
		assert(dlist_append(dlist, (void*)i) == DLIST_RET_OK);
	}
	for(i = 0; i < n; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == DLIST_RET_OK);
	}

	dlist_print(dlist, print_int);
	printf("\n");

	dlist_destroy(dlist);

	return 0;
}

all:
	gcc -g -m32 dlist.c main.c -o demo
clean:
	rm -f demo

1.5 Don't Repeat Yourself(DRY)

需求描述

  • 对一个存放整数的的双向链表,找出链表中的最大值.
  • 对一个存放整数的的双向链表,累加链表中的所有整数.
/*
 * File:    dlist.h
 */


#ifndef DLIST_H
#define DLIST_H

#ifdef __cplusplus
extern "C" {
#endif/*__cplusplus*/

typedef enum _DListRet
{
	DLIST_RET_OK,
	DLIST_RET_OOM,
	DLIST_RET_STOP,
	DLIST_RET_PARAMS,
	DLIST_RET_FAIL
}DListRet;

struct _DList;
typedef struct _DList DList;

typedef int (*DListDataCompareFunc)(void* ctx, void* data);
typedef DListRet (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(void);

DListRet dlist_insert(DList* thiz, size_t index, void* data);
DListRet dlist_prepend(DList* thiz, void* data);
DListRet dlist_append(DList* thiz, void* data);
DListRet dlist_delete(DList* thiz, size_t index);
DListRet dlist_get_by_index(DList* thiz, size_t index, void** data);
DListRet dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
DListRet dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

#ifdef __cplusplus
}
#endif/*__cplusplus*/

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	DListNode* first;
};

static DListNode* dlist_node_create(void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL) {
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_node_destroy(DListNode* node)
{
	if(node != NULL) {
		node->next = NULL;
		node->prev = NULL;
		free(node);
	}

	return;
}

DList* dlist_create(void)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL) {
		thiz->first = NULL;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0){
		iter = iter->next;
		index--;
	}

	if(!fail_return_last){
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

DListRet dlist_insert(DList* thiz, size_t index, void* data)
{
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	if((node = dlist_node_create(data)) == NULL){
		return DLIST_RET_OOM; 
	}

	if(thiz->first == NULL){
		thiz->first = node;
		return DLIST_RET_OK;
	}

	cursor = dlist_get_node(thiz, index, 1);
	
	if(index < dlist_length(thiz)) {
		if(thiz->first == cursor){
			thiz->first = node;
		}else{
			cursor->prev->next = node;
			node->prev = cursor->prev;
		}
		node->next = cursor;
		cursor->prev = node;
	}else{
		cursor->next = node;
		node->prev = cursor;
	}

	return DLIST_RET_OK;
}

DListRet dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

DListRet dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

DListRet dlist_delete(DList* thiz, size_t index)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		if(cursor == thiz->first){
			thiz->first = cursor->next;
		}

		if(cursor->next != NULL){
			cursor->next->prev = cursor->prev;
		}

		if(cursor->prev != NULL){
			cursor->prev->next = cursor->next;
		}

		dlist_node_destroy(cursor);
	}

	return DLIST_RET_OK;
}

DListRet dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		*data = cursor->data;
	}

	return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

DListRet dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL){
		cursor->data = data;
	}

	return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = thiz->first;

	while(iter != NULL){
		length++;
		iter = iter->next;
	}

	return length;
}

DListRet dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
	DListRet ret = DLIST_RET_OK;
	DListNode* iter = thiz->first;

	while(iter != NULL && ret != DLIST_RET_STOP){
		ret = visit(ctx, iter->data);
		iter = iter->next;
	}

	return ret;
}

int   dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = thiz->first;

	while(iter != NULL){
		if(cmp(ctx, iter->data) == 0){
			break;
		}
		i++;
		iter = iter->next;
	}

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = thiz->first;
	DListNode* next = NULL;

	while(iter != NULL){
		next = iter->next;
		dlist_node_destroy(iter);
		iter = next;
	}

	thiz->first = NULL;
	free(thiz);

	return;
}


/*
 * File:    main.c
 */

#include <stdio.h>
#include "dlist.h"
#include <assert.h>

static DListRet sum_cb(void* ctx, void* data)
{
	long long* result = ctx;
	*result += (int)data;

	return DLIST_RET_OK;
}

typedef struct _MaxCtx
{
	int is_first;
	int max;
}MaxCtx;

static DListRet max_cb(void* ctx, void* data)
{
	MaxCtx* max_ctx = ctx;
	if(max_ctx->is_first) {
		max_ctx->is_first = 0;
		max_ctx->max = (int)data;
	}else if(max_ctx->max < (int)data){
		max_ctx->max = (int)data;
	}

	return DLIST_RET_OK;
}

static DListRet print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return DLIST_RET_OK;
}

int main(int argc, char* argv[])
{
	int i = 0;
	int n = 100;
	long long sum = 0;
	MaxCtx max_ctx = {.is_first = 1, 0};
	DList* dlist = dlist_create();

	for(i = 0; i < n; i++) {
		assert(dlist_append(dlist, (void*)i) == DLIST_RET_OK);
	}

	dlist_foreach(dlist, print_int, NULL);
	dlist_foreach(dlist, max_cb, &max_ctx);
	dlist_foreach(dlist, sum_cb, &sum);

	printf("\nsum=%lld max=%d\n", sum, max_ctx.max);
	dlist_destroy(dlist);

	return 0;
}

all:
	gcc -g -m32 dlist.c main.c -o demo

clean:
	rm -f demo

1.6 你的数据放在哪里

需求描述

对一个存放字符串的双向链表,把存放在其中的字符串转换成大写字母.


/*
 * File: dlist_toupper.c
 */

#include "dlist.h"
#include <string.h>
#include <stdio.h>
#include <ctype.h>

static DListRet str_toupper(void* ctx, void* data)
{
	char* p = (char*)data;
	if(p != NULL){
		while(*p != '\0'){
			if(islower((*p))){
				*p = toupper(*p);
			}
			p++;
		}
	}

	return DLIST_RET_OK;
}

static DListRet str_print(void* ctx, void* data)
{
	printf("%s\n", (char *)data);
	
	return DLIST_RET_OK;
}

/* 双向链表中存放常量字符串,转换时出现段错误*/
static void demo_const(void)
{
	DList* dlist = dlist_create(NULL, NULL);
	dlist_append(dlist, "It");
	dlist_append(dlist, "is");
	dlist_append(dlist, "OK");
	dlist_append(dlist, "!");
	dlist_foreach(dlist, str_toupper, NULL);
	dlist_destroy(dlist);

	return ;
}

/* 双向链表中存放的是临时变量,转换后发现所有字符串都一样*/
static void demo_temp(void)
{
	char str[256] = {0};
	DList* dlist = dlist_create(NULL, NULL);
	strcpy(str, "It");
	dlist_append(dlist, str);
	strcpy(str, "is");
	dlist_append(dlist, str);
	strcpy(str, "OK");
	dlist_append(dlist, str);
	strcpy(str, "!");
	dlist_append(dlist, str);
	dlist_foreach(dlist, str_toupper, NULL);
	dlist_foreach(dlist, str_print, NULL);
	dlist_destroy(dlist);

	return ;
}

static void data_free(void* ctx, void* data)
{
	free(data);

	return;
}

/*存放时,复制了数据,但没有释放所分配的内存*/
static void demo_heap(void)
{
	DList* dlist = dlist_create(data_free, NULL);
	dlist_append(dlist, strdup("It"));
	dlist_append(dlist, strdup("is"));
	dlist_append(dlist, strdup("OK"));
	dlist_append(dlist, strdup("!"));
	dlist_foreach(dlist, str_toupper, NULL);
	dlist_foreach(dlist, str_print, NULL);
	dlist_destroy(dlist);

	return ;
}

int main(int argc, char* argv[])
{
	demo_temp();
	demo_heap();
	demo_const();

	return 0;
}
/* 
 * bss.c 
 * */

/* 未初始化的全局变量(.bss段) */
int bss_array[1024 * 1024];

int main(int argc, char* argv[])
{
	return 0;
}
/*
 * data.c
 */

/* 初始化过的全局变量(.data段) */
int data_array[1024 * 1024] = {1};

int main(int argc, char* argv[])
{
	return 0;
}
/*
 * File: heap_error.c
 */
 
#include <stdlib.h>
#include <string.h>

/*# valgrind --tool=memcheck --leak-check=full ./heap_error */

int main(int argc, char* argv[])
{
	/*memory leak and buffer overflow.*/
	char* str = malloc(10);
	strcpy(str, "123456788900");

	return 0;
}
ARCH=-m32
all:
	gcc -g ${ARCH} toupper.c -o toupper_test
	gcc -g ${ARCH} dlist.c dlist_toupper.c -o dlist_toupper_test
	gcc -g ${ARCH} bss.c -o bss.exe
	gcc -g ${ARCH} data.c -o data.exe
	gcc -g ${ARCH} heap_error.c -o heap_error_test
clean:
	rm -f *test *.exe

第二章 写的又好又快的秘诀

2.3 避免常见错误

  • strcpy , strcat, sprintf, 与 strncpy , strncat, snprintf,

  • sizeoff

  • valotile

  • intptr_t, uintptr_t

    这两个数据类型的定义,位于 /usr/include/stdint.h 文件中,这个文件是在 C99 中新增加的文件, /usr/include/inttypes.h C99 新增加的文件,在这个文件中有 #include<stdint.h> ,

    因此,使用时,既可以

    #include <stdint.h>
    

    又可以

    #include <inttypes.h>
    

    /usr/include/stdint.h 中定义:

    /* Types for `void *' pointers.  */
    #if __WORDSIZE == 64
    # ifndef __intptr_t_defined
    typedef long int                intptr_t;
    #  define __intptr_t_defined
    # endif
    typedef unsigned long int       uintptr_t;
    #else
    # ifndef __intptr_t_defined
    typedef int                     intptr_t;
    #  define __intptr_t_defined
    # endif
    typedef unsigned int            uintptr_t;
    #endif
    
    1. 提高程序的可移植性(在32位和64位的机器上).
    2. 定义这两个数据类型别名也是为了 void * 指针. 在C语言中,任何类型的指针都可以转换为 void * 类型,并且在将它转换回原来的类型时不会丢失信息。

2.4 自动测试

/*
 * File:    dlist.h
 */

#include <stdio.h>

#ifndef DLIST_H
#define DLIST_H

#ifdef __cplusplus
extern "C" {
#endif/*__cplusplus*/

typedef enum _DListRet
{
	DLIST_RET_OK,
	DLIST_RET_OOM,
	DLIST_RET_STOP,
	DLIST_RET_INVALID_PARAMS,
	DLIST_RET_FAIL
}DListRet;

struct _DList;
typedef struct _DList DList;

typedef void     (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int      (*DListDataCompareFunc)(void* ctx, void* data);
typedef DListRet (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* data_destroy_ctx);

DListRet dlist_insert(DList* thiz, size_t index, void* data);
DListRet dlist_prepend(DList* thiz, void* data);
DListRet dlist_append(DList* thiz, void* data);
DListRet dlist_delete(DList* thiz, size_t index);
DListRet dlist_get_by_index(DList* thiz, size_t index, void** data);
DListRet dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
DListRet dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#ifdef __cplusplus
}
#endif/*__cplusplus*/

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include <stdint.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	DListNode* first;
	void* data_destroy_ctx;
	DListDataDestroyFunc data_destroy;
};

static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL){
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL){
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL){
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		free(node);
	}

	return;
}

DList* dlist_create(DListDataDestroyFunc data_destroy, void* data_destroy_ctx)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL){
		thiz->first = NULL;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = data_destroy_ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0){
		iter = iter->next;
		index--;
	}

	if(!fail_return_last){
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

DListRet dlist_insert(DList* thiz, size_t index, void* data)
{
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, DLIST_RET_INVALID_PARAMS); 

	if((node = dlist_create_node(thiz, data)) == NULL){
		return DLIST_RET_OOM; 
	}

	if(thiz->first == NULL){
		thiz->first = node;

		return DLIST_RET_OK;
	}

	cursor = dlist_get_node(thiz, index, 1);
	
	if(index < dlist_length(thiz)){
		if(thiz->first == cursor){
			thiz->first = node;
		}else{
			cursor->prev->next = node;
			node->prev = cursor->prev;
		}
		node->next = cursor;
		cursor->prev = node;
	}else{
		cursor->next = node;
		node->prev = cursor;
	}

	return DLIST_RET_OK;
}

DListRet dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

DListRet dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

DListRet dlist_delete(DList* thiz, size_t index)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);
	
	return_val_if_fail(cursor != NULL, DLIST_RET_INVALID_PARAMS); 

	if(cursor != NULL)
	{
		if(cursor == thiz->first){
			thiz->first = cursor->next;
		}

		if(cursor->next != NULL){
			cursor->next->prev = cursor->prev;
		}

		if(cursor->prev != NULL){
			cursor->prev->next = cursor->next;
		}

		dlist_destroy_node(thiz, cursor);
	}

	return DLIST_RET_OK;
}

DListRet dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	return_val_if_fail(cursor != NULL, DLIST_RET_INVALID_PARAMS); 

	if(cursor != NULL){
		*data = cursor->data;
	}

	return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

DListRet dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);

	return_val_if_fail(cursor != NULL, DLIST_RET_INVALID_PARAMS); 

	if(cursor != NULL){
		cursor->data = data;
	}

	return cursor != NULL ? DLIST_RET_OK : DLIST_RET_FAIL;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, 0);

	iter = thiz->first;

	while(iter != NULL){
		length++;
		iter = iter->next;
	}

	return length;
}

DListRet dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
	DListRet ret = DLIST_RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, DLIST_RET_INVALID_PARAMS);

	iter = thiz->first;

	while(iter != NULL && ret != DLIST_RET_STOP){
		ret = visit(ctx, iter->data);

		iter = iter->next;
	}

	return ret;
}

int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	iter = thiz->first;
	while(iter != NULL){
		if(cmp(ctx, iter->data) == 0){
			break;
		}
		i++;
		iter = iter->next;
	}

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	iter = thiz->first;
	while(iter != NULL){
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	free(thiz);

	return;
}

#ifdef DLIST_TEST

#include <assert.h>

static int cmp_int(void* ctx, void* data)
{
	//return (int)data - (int)ctx;
	return (intptr_t)data - (intptr_t)ctx;
}

static DListRet print_int(void* ctx, void* data)
{
	//printf("%d ", (int)data);
	//printf("%d ", (intptr_t)data);
	printf("%p ", data);
	//printf("%ld ", (intptr_t)data);

	return DLIST_RET_OK;
}

static DListRet check_and_dec_int(void* ctx, void* data)
{
	//int* expected =(int*)ctx;
	//assert(*expected == (int)data);
	intptr_t* expected =(intptr_t*)ctx;
	assert(*expected == (intptr_t)data);

	(*expected)--;

	return DLIST_RET_OK;
}

void test_int_dlist(void)
{

	//int s = 0;
	//int i = 0;
	//int n = 100;
	//int data = 0;
	intptr_t s = 0;
	intptr_t i = 0;
	intptr_t n = 100;
	intptr_t data = 0;
	
	DList* dlist = dlist_create(NULL, NULL);

	for(i = 0; i < n; i++){
		assert(dlist_append(dlist, (void*)i) == DLIST_RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == DLIST_RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == DLIST_RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == DLIST_RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == DLIST_RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++){
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == DLIST_RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n){
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++){
		assert(dlist_prepend(dlist, (void*)i) == DLIST_RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == DLIST_RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == DLIST_RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == DLIST_RET_OK);
	
	s = dlist_length(dlist);
	for(i = 1; i < n; i++){
		assert(dlist_insert(dlist, i, (void*)i) == DLIST_RET_OK);
		assert(dlist_length(dlist) == (s + i));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == DLIST_RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == DLIST_RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == DLIST_RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == DLIST_RET_OK);
	}

	dlist_destroy(dlist);

	return;
}

void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == DLIST_RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

int main(int argc, char* argv[])
{
	test_int_dlist();

	test_invalid_params();

	return 0;
}
#endif

ARCH=-m32
all:
	gcc -g ${ARCH} -fPIC -shared dlist.c -o libdlist.so 
	gcc -g ${ARCH} -DDLIST_TEST dlist.c  -o dlist_test

clean:
	rm -f *test *.exe *.so

第三章 从动态数组学习设计

3.1 动态数组与双向链表

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

typedef void     (*DataDestroyFunc)(void* ctx, void* data);
typedef int      (*DataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DataVisitFunc)(void* ctx, void* data);

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);

#endif/*TYPEDEF_H*/

/*
 * File:    darray.h
 */

#include <stdio.h>
#include "typedef.h"

#ifndef DARRAY_H
#define DARRAY_H

DECLS_BEGIN

struct _DArray;
typedef struct _DArray DArray;

DArray* darray_create(DataDestroyFunc data_destroy, void* ctx);

Ret    darray_insert(DArray* thiz, size_t index, void* data);
Ret    darray_prepend(DArray* thiz, void* data);
Ret    darray_append(DArray* thiz, void* data);
Ret    darray_delete(DArray* thiz, size_t index);
Ret    darray_get_by_index(DArray* thiz, size_t index, void** data);
Ret    darray_set_by_index(DArray* thiz, size_t index, void* data);
size_t darray_length(DArray* thiz);
int    darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx);
Ret    darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx);

void darray_destroy(DArray* thiz);

DECLS_END

#endif/*DARRAY_H*/

/*
 * File:    darray.c
 */

#include <stdlib.h>
#include <stdint.h>
#include "darray.h"

struct _DArray
{
	void** data;
	size_t size;
	size_t alloc_size;

	void* data_destroy_ctx;
	DataDestroyFunc data_destroy;
};

static void darray_destroy_data(DArray* thiz, void* data)
{
	if(thiz->data_destroy != NULL)
	{
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

DArray* darray_create(DataDestroyFunc data_destroy, void* ctx)
{
	DArray* thiz = malloc(sizeof(DArray));

	if(thiz != NULL)
	{
		thiz->data  = NULL;
		thiz->size  = 0;
		thiz->alloc_size = 0;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

#define MIN_PRE_ALLOCATE_NR 10
static Ret darray_expand(DArray* thiz, size_t need)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	if((thiz->size + need) > thiz->alloc_size)
	{
		/*  thiz->alloc_size * 1.5 + MIN_PRE_ALLOCATE_NR   */
		size_t alloc_size = thiz->alloc_size + (thiz->alloc_size>>1) + MIN_PRE_ALLOCATE_NR;

		void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);
		if(data != NULL)
		{
			thiz->data = data;
			thiz->alloc_size = alloc_size;
		}
	}

	return ((thiz->size + need) <= thiz->alloc_size) ? RET_OK : RET_FAIL;
}

static Ret darray_shrink(DArray* thiz)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	if((thiz->size < (thiz->alloc_size >> 1)) && (thiz->alloc_size > MIN_PRE_ALLOCATE_NR))
	{
		size_t alloc_size = thiz->size + (thiz->size >> 1);

		void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);
		if(data != NULL)
		{
			thiz->data = data;
			thiz->alloc_size = alloc_size;
		}
	}

	return RET_OK;
}

Ret darray_insert(DArray* thiz, size_t index, void* data)
{
	Ret ret = RET_OOM;
	size_t cursor = index;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	cursor = cursor < thiz->size ? cursor : thiz->size;

	if(darray_expand(thiz, 1) == RET_OK)
	{
		size_t i = 0;
		for(i = thiz->size; i > cursor; i--)
		{
			thiz->data[i] = thiz->data[i-1];
		}

		thiz->data[cursor] = data;
		thiz->size++;
		
		ret = RET_OK;
	}

	return ret;
}

Ret darray_prepend(DArray* thiz, void* data)
{
	return darray_insert(thiz, 0, data);
}

Ret darray_append(DArray* thiz, void* data)
{
	return darray_insert(thiz, -1, data);
}

Ret darray_delete(DArray* thiz, size_t index)
{
	size_t i = 0;
	Ret ret = RET_OK;

	return_val_if_fail(thiz != NULL && thiz->size > index, RET_INVALID_PARAMS); 

	darray_destroy_data(thiz, thiz->data[index]);
	for(i = index; (i+1) < thiz->size; i++)
	{
		thiz->data[i] = thiz->data[i+1];
	}
	thiz->size--;

	darray_shrink(thiz);

	return RET_OK;
}

Ret darray_get_by_index(DArray* thiz, size_t index, void** data)
{

	return_val_if_fail(thiz != NULL && data != NULL && index < thiz->size, 
		RET_INVALID_PARAMS); 

	*data = thiz->data[index];

	return RET_OK;
}

Ret darray_set_by_index(DArray* thiz, size_t index, void* data)
{
	return_val_if_fail(thiz != NULL && index < thiz->size, 
		RET_INVALID_PARAMS); 

	thiz->data[index] = data;

	return RET_OK;
}

size_t   darray_length(DArray* thiz)
{
	size_t length = 0;
	
	return_val_if_fail(thiz != NULL, 0);

	return thiz->size;
}

Ret darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx)
{
	size_t i = 0;	
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	for(i = 0; i < thiz->size; i++)
	{
		ret = visit(ctx, thiz->data[i]);
	}

	return ret;
}

int      darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx)
{
	size_t i = 0;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	for(i = 0; i < thiz->size; i++)
	{
		if(cmp(ctx, thiz->data[i]) == 0)
		{
			break;
		}
	}

	return i;
}

void darray_destroy(DArray* thiz)
{
	size_t i = 0;
	
	if(thiz != NULL)
	{
		for(i = 0; i < thiz->size; i++)
		{
			darray_destroy_data(thiz, thiz->data[i]);
		}
		
		SAFE_FREE(thiz->data);
		SAFE_FREE(thiz);
	}

	return;
}

#ifdef DARRAY_TEST

#include <assert.h>

static int int_cmp(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_darray(void)
{
	//int i = 0;
	//int n = 100;
	//int data = 0;

	intptr_t i = 0;
	intptr_t n = 100;
	intptr_t data = 0;

	DArray* darray = darray_create(NULL, NULL);

	for(i = 0; i < n; i++)
	{
		assert(darray_append(darray, (void*)i) == RET_OK);
		assert(darray_length(darray) == (i + 1));
		assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(darray_set_by_index(darray, i, (void*)(2*i)) == RET_OK);
		assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(darray_set_by_index(darray, i, (void*)i) == RET_OK);
		assert(darray_find(darray, int_cmp, (void*)i) == i);
	}

	for(i = 0; i < n; i++)
	{
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(darray_length(darray) == (n-i));
		assert(darray_delete(darray, 0) == RET_OK);
		assert(darray_length(darray) == (n-i-1));
		if((i + 1) < n)
		{
			assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(darray_length(darray) == 0);

	for(i = 0; i < n; i++)
	{
		assert(darray_prepend(darray, (void*)i) == RET_OK);
		assert(darray_length(darray) == (i + 1));
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(darray_set_by_index(darray, 0, (void*)(2*i)) == RET_OK);
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(darray_set_by_index(darray, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(darray_foreach(darray, check_and_dec_int, &i) == RET_OK);

	darray_destroy(darray);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(darray_length(NULL) == 0);
	assert(darray_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(darray_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(darray_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(darray_find(NULL, NULL, NULL) < 0);
	assert(darray_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_darray();
	test_invalid_params();

	return;
}

int main(int argc, char* argv[])
{
	single_thread_test();

	return 0;
}
#endif

CFILES=darray.c
all:
	gcc -g -shared -fPIC  -lpthread $(CFILES) -o libdarray.so
	gcc -g -DDARRAY_TEST -lpthread $(CFILES)  -o darray_test

clean:
	rm -f *test *.exe *.so

3.2 排序

  • 冒泡排序
  • 快速排序
    先将元素分成两个区,所有小于某个元素的值在第一个区,其他在第二个区。然后分别对这两个区进行快速排序,直到所分的区只剩下一个元素为止。
  • 归并排序
    让左右两部分进行排序,然后把它们合并起来。在排序左右两部分时,同样使用归并排序.
/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

typedef void     (*DataDestroyFunc)(void* ctx, void* data);
typedef intptr_t      (*DataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DataVisitFunc)(void* ctx, void* data);

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);

#endif/*TYPEDEF_H*/

/*
 * File:    sort.h
 */

#ifndef SORT_H
#define SORT_H

#include "typedef.h"

Ret bubble_sort(void** array, size_t nr, DataCompareFunc cmp);
Ret quick_sort(void** array, size_t nr, DataCompareFunc cmp);
Ret merge_sort(void** array, size_t nr, DataCompareFunc cmp);

#endif/*SORT_H*/

/*
 * File:    sort.c
 */

#include "sort.h"

/*
 *  冒泡排序
 */
Ret bubble_sort(void** p_array, size_t nr, DataCompareFunc cmp)
{
	size_t i     = 0;
	size_t max   = 0;
	size_t right = 0;


	return_val_if_fail(p_array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr < 2){
		return RET_OK;
	}
	
	intptr_t* array = (intptr_t*)p_array;

	for(right = nr - 1; right > 0; right--){
		for(i = 1, max = 0; i < right; i++){
			if(cmp((void *)(array[i]), (void *)(array[max])) > 0){
				max = i;
			}
		}

		if(cmp((void *)(array[max]), (void *)(array[right])) > 0){
			intptr_t data = array[right];
			array[right] = array[max];
			array[max] = data;
		}
	}

	return RET_OK;
}


/*
 *  快速排序
 */
void quick_sort_impl(void** p_array, size_t left, size_t right, DataCompareFunc cmp)
{
	size_t save_left  = left;
	size_t save_right = right;
	
	intptr_t * array = (intptr_t *) p_array;    	

	intptr_t x = array[left];
	/*这个循环,让小于x的元素在左边,大于x的元素在右边*/
	while(left < right){
		while(cmp((void*)(array[right]), (void *) x) >= 0 && left < right) right--;
		if(left != right){
			array[left] = array[right];
			left++;
		}

		while(cmp((void *)(array[left]), (void *) x) <= 0 && left < right)	left++;
		if(left != right){
			array[right] = array[left];
			right--;
		}
	}
	array[left] = x;

	if(save_left < left){
		quick_sort_impl((void **)array, save_left, left-1, cmp);
	}

	if(save_right > left){
		quick_sort_impl((void **)array, left+1, save_right, cmp);
	}

	return;
}

Ret quick_sort(void** array, size_t nr, DataCompareFunc cmp)
{
	Ret ret = RET_OK;

	return_val_if_fail(array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr > 1){
		quick_sort_impl(array, 0, nr - 1, cmp);
	}

	return ret;
}

/*
 * 归并排序
 */
static Ret merge_sort_impl(void** p_storage, void** p_array, size_t low, size_t mid, size_t high, DataCompareFunc cmp)
{
	size_t i = low;
	size_t j = low;
	size_t k = mid;

	intptr_t* storage = (intptr_t *) p_storage;
	intptr_t* array = (intptr_t *) p_array;
  
	/* 对左半部分排序 */
	if((low + 1) < mid){
		size_t x = low + ((mid - low) >> 1);
		merge_sort_impl(p_storage, p_array, low, x, mid, cmp);
	}
	
	/* 对右半部分排序 */
	if((mid + 1) < high){
		size_t x = mid + ((high - mid) >> 1);
		merge_sort_impl(p_storage, p_array, mid, x, high, cmp);
	}

	/* 合并两个有序数组 */	
	while(j < mid && k < high){
		if(cmp((void *)(array[j]), (void *)(array[k])) <= 0) {
			storage[i++] = array[j++];
		}
		else{
			storage[i++] = array[k++];
		}
	}

	while(j < mid){
		storage[i++] = array[j++];
	}

	while(k < high){
		storage[i++] = array[k++];
	}

	for(i = low; i < high; i++){
		array[i] = storage[i];
	}

	return RET_OK;
}

Ret merge_sort(void** array, size_t nr, DataCompareFunc cmp)
{
	void** storage = NULL;
	Ret ret = RET_OK;

	return_val_if_fail(array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr > 1)
	{
		storage = (void**)malloc(sizeof(void*) * nr);
		if(storage != NULL)
		{
			ret = merge_sort_impl(storage, array, 0, nr>>1, nr, cmp);

			free(storage);
		}
	}

	return ret;
}


#ifdef SORT_TEST
#include <assert.h>
intptr_t int_cmp(void* a, void* b)
{
	return (intptr_t)a - (intptr_t)b;
}

intptr_t int_cmp_invert(void* a, void* b)
{
	return (intptr_t)b - (intptr_t)a;
}

static void** create_int_array(intptr_t n)
{
	intptr_t i = 0;
	intptr_t* array = (intptr_t*)malloc(sizeof(intptr_t) * n);
	for(i = 0; i < n; i++)
	{
		array[i] = rand();
	}

	return (void**)array;
}

static void sort_test_one_asc(SortFunc sort, intptr_t n)
{
	intptr_t i = 0;
	void** p_array = create_int_array(n);

	sort(p_array, n, int_cmp);

	intptr_t* array =  (intptr_t *)p_array;
	for(i = 1; i < n; i++)
	{
		assert(array[i] >= array[i-1]);
	}

	free(array);

	return;
}

static void sort_test_one_dec(SortFunc sort, intptr_t n)
{
	intptr_t i = 0;
	void** p_array = create_int_array(n);

	sort((void**)p_array, n, int_cmp_invert);


	intptr_t* array =  (intptr_t *)p_array;
	for(i = 1; i < n; i++)
	{
		assert(array[i] <= array[i-1]);
	}

	free(array);

	return;
}

static void sort_test(SortFunc sort)
{
	intptr_t i = 0;
	for(i = 0; i < 1000; i++) {
		sort_test_one_dec(sort, i);
		sort_test_one_asc(sort, i);
	}
	return ;
}

intptr_t main(intptr_t argc, char* argv[])
{
	srand(100);
	sort_test(bubble_sort); // 冒泡排序 测试
	sort_test(quick_sort);  // 快速排序 测试
	sort_test(merge_sort);  // 归并排序 测试

	return 0;
}
#endif/*SORT_TEST*/
all:
	gcc -g sort.c -DSORT_TEST -o sort_test 

clean:
	rm -f *test *.exe *.so

3.3. 有序数组的两个应用

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

typedef void     (*DataDestroyFunc)(void* ctx, void* data);
typedef int      (*DataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DataVisitFunc)(void* ctx, void* data);

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);

#endif/*TYPEDEF_H*/

/*
 * File : search.c
 */

#include "typedef.h"

int qsearch(void** array, size_t nr, void* data, DataCompareFunc cmp)
{
	int low    = 0;
	int mid    = 0;
	int high   = nr-1;
	int result = 0;

	return_val_if_fail(array != NULL && cmp != NULL, -1);

	while(low <= high)
	{
		mid  = low + ((high - low) >> 1);
		result = cmp(array[mid], data);

		if(result == 0){
			return mid;
		}else if(result < 0){
			low = mid + 1;
		}else{
			high = mid - 1;
		}
	}

	return -1;
}

#ifdef SEARCH_TEST
#include <assert.h>
int int_cmp(void* a, void* b)
{
	return (int)a - (int)b;
}

static void search_test(size_t n)
{
	int i = 0;
	int* array = (int*)malloc(n * sizeof(int));
	
	for(i = 0; i < n; i++){
		array[i] = i;
	}

	for(i = 0; i < n; i++){
		assert(qsearch((void**)array, n, (void*)i, int_cmp) == i);
	}

	free(array);

	return;
}

int main(int argc, char* argv[])
{
	int i = 0;
	for(i = 1; i < 1000; i++){
		search_test(i);
	}

	return 0;
}
#endif/*QSEARCH_TEST*/

/*
 * File:    sort.h
  */

#ifndef SORT_H
#define SORT_H

#include "typedef.h"

DECLS_BEGIN

Ret bubble_sort(void** array, size_t nr, DataCompareFunc cmp);
Ret quick_sort(void** array, size_t nr, DataCompareFunc cmp);
Ret merge_sort(void** array, size_t nr, DataCompareFunc cmp);

DECLS_END

#endif/*SORT_H*/

/*
 * File:    sort.c
 */

#include "sort.h"

Ret bubble_sort(void** array, size_t nr, DataCompareFunc cmp)
{
	size_t i     = 0;
	size_t max   = 0;
	size_t right = 0;

	return_val_if_fail(array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr < 2) 
	{
		return RET_OK;
	}

	for(right = nr - 1; right > 0; right--)
	{
		for(i = 1, max = 0; i < right; i++)
		{
			if(cmp(array[i], array[max]) > 0)
			{
				max = i;
			}
		}

		if(cmp(array[max], array[right]) > 0)
		{
			void* data = array[right];
			array[right] = array[max];
			array[max] = data;
		}
	}

	return RET_OK;
}

void quick_sort_impl(void** array, size_t left, size_t right, DataCompareFunc cmp)
{
	size_t save_left  = left;
	size_t save_right = right;
	void* x = array[left];

	while(left < right)
	{
		while(cmp(array[right], x) >= 0 && left < right) right--;
		if(left != right)
		{
			array[left] = array[right];
			left++;
		}

		while(cmp(array[left], x) <= 0 && left < right)	left++;
		if(left != right)
		{
			array[right] = array[left];
			right--;
		}
	}
	array[left] = x;

	if(save_left < left)
	{
		quick_sort_impl(array, save_left, left-1, cmp);
	}

	if(save_right > left)
	{
		quick_sort_impl(array, left+1, save_right, cmp);
	}

	return;
}

Ret quick_sort(void** array, size_t nr, DataCompareFunc cmp)
{
	Ret ret = RET_OK;

	return_val_if_fail(array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr > 1)
	{
		quick_sort_impl(array, 0, nr - 1, cmp);
	}

	return ret;
}

static Ret merge_sort_impl(void** storage, void** array, size_t low, size_t mid, size_t high, DataCompareFunc cmp)
{
	size_t i = low;
	size_t j = low;
	size_t k = mid;

	if((low + 1) < mid)
	{
		size_t x = low + ((mid - low) >> 1);
		merge_sort_impl(storage, array, low, x, mid, cmp);
	}
	
	if((mid + 1) < high)
	{
		size_t x = mid + ((high - mid) >> 1);
		merge_sort_impl(storage, array, mid, x, high, cmp);
	}

	
	while(j < mid && k < high)
	{
		if(cmp(array[j], array[k]) <= 0)
		{
			storage[i++] = array[j++];
		}
		else
		{
			storage[i++] = array[k++];
		}
	}

	while(j < mid)
	{
		storage[i++] = array[j++];
	}

	while(k < high)
	{
		storage[i++] = array[k++];
	}

	for(i = low; i < high; i++)
	{
		array[i] = storage[i];
	}

	return RET_OK;
}

Ret merge_sort(void** array, size_t nr, DataCompareFunc cmp)
{
	void** storage = NULL;
	Ret ret = RET_OK;

	return_val_if_fail(array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr > 1)
	{
		storage = (void**)malloc(sizeof(void*) * nr);
		if(storage != NULL)
		{
			ret = merge_sort_impl(storage, array, 0, nr>>1, nr, cmp);

			free(storage);
		}
	}

	return ret;
}


#ifdef SORT_TEST
#include <assert.h>
int int_cmp(void* a, void* b)
{
	return (int)a - (int)b;
}

int int_cmp_invert(void* a, void* b)
{
	return (int)b - (int)a;
}

static void** create_int_array(int n)
{
	int i = 0;
	int* array = (int*)malloc(sizeof(int) * n);

	for(i = 0; i < n; i++)
	{
		array[i] = rand();
	}

	return (void**)array;
}

static void sort_test_one_asc(SortFunc sort, int n)
{
	int i = 0;
	void** array = create_int_array(n);

	sort(array, n, int_cmp);

	for(i = 1; i < n; i++)
	{
		assert(array[i] >= array[i-1]);
	}

	free(array);

	return;
}

static void sort_test_one_dec(SortFunc sort, int n)
{
	int i = 0;
	void** array = create_int_array(n);

	sort((void**)array, n, int_cmp_invert);

	for(i = 1; i < n; i++)
	{
		assert(array[i] <= array[i-1]);
	}

	free(array);

	return;
}

static void sort_test(SortFunc sort)
{
	int i = 0;
	for(i = 0; i < 1000; i++)
	{
		sort_test_one_dec(sort, i);
		sort_test_one_asc(sort, i);
	}

	return ;
}

int main(int argc, char* argv[])
{
	srand(100);

	sort_test(quick_sort);
	sort_test(merge_sort);
	sort_test(bubble_sort);

	return 0;
}
#endif/*SORT_TEST*/
/*
 * File:    darray.h
 */

#include <stdio.h>
#include "typedef.h"

#ifndef DARRAY_H
#define DARRAY_H

DECLS_BEGIN

struct _DArray;
typedef struct _DArray DArray;

DArray* darray_create(DataDestroyFunc data_destroy, void* ctx);

Ret    darray_insert(DArray* thiz, size_t index, void* data);
Ret    darray_prepend(DArray* thiz, void* data);
Ret    darray_append(DArray* thiz, void* data);
Ret    darray_delete(DArray* thiz, size_t index);
Ret    darray_get_by_index(DArray* thiz, size_t index, void** data);
Ret    darray_set_by_index(DArray* thiz, size_t index, void* data);
size_t darray_length(DArray* thiz);
int    darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx);
Ret    darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx);
Ret    darray_sort(DArray* thiz, SortFunc sort, DataCompareFunc cmp);

void darray_destroy(DArray* thiz);

DECLS_END

#endif/*DARRAY_H*/

/*
 * File:    darray.c
 */

#include <stdlib.h>
#include "darray.h"

struct _DArray
{
	void** data;
	size_t size;
	size_t alloc_size;

	void* data_destroy_ctx;
	DataDestroyFunc data_destroy;
};

static void darray_destroy_data(DArray* thiz, void* data)
{
	if(thiz->data_destroy != NULL)
	{
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

DArray* darray_create(DataDestroyFunc data_destroy, void* ctx)
{
	DArray* thiz = malloc(sizeof(DArray));

	if(thiz != NULL)
	{
		thiz->data  = NULL;
		thiz->size  = 0;
		thiz->alloc_size = 0;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

#define MIN_PRE_ALLOCATE_NR 10
static Ret darray_expand(DArray* thiz, size_t need)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	if((thiz->size + need) > thiz->alloc_size)
	{
		size_t alloc_size = thiz->alloc_size + (thiz->alloc_size>>1) + MIN_PRE_ALLOCATE_NR;

		void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);
		if(data != NULL)
		{
			thiz->data = data;
			thiz->alloc_size = alloc_size;
		}
	}

	return ((thiz->size + need) <= thiz->alloc_size) ? RET_OK : RET_FAIL;
}

static Ret darray_shrink(DArray* thiz)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	if((thiz->size < (thiz->alloc_size >> 1)) && (thiz->alloc_size > MIN_PRE_ALLOCATE_NR))
	{
		size_t alloc_size = thiz->size + (thiz->size >> 1);

		void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);
		if(data != NULL)
		{
			thiz->data = data;
			thiz->alloc_size = alloc_size;
		}
	}

	return RET_OK;
}

Ret darray_insert(DArray* thiz, size_t index, void* data)
{
	Ret ret = RET_OOM;
	size_t cursor = index;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	cursor = cursor < thiz->size ? cursor : thiz->size;

	if(darray_expand(thiz, 1) == RET_OK)
	{
		size_t i = 0;
		for(i = thiz->size; i > cursor; i--)
		{
			thiz->data[i] = thiz->data[i-1];
		}

		thiz->data[cursor] = data;
		thiz->size++;
		
		ret = RET_OK;
	}

	return ret;
}

Ret darray_prepend(DArray* thiz, void* data)
{
	return darray_insert(thiz, 0, data);
}

Ret darray_append(DArray* thiz, void* data)
{
	return darray_insert(thiz, -1, data);
}

Ret darray_delete(DArray* thiz, size_t index)
{
	size_t i = 0;

	return_val_if_fail(thiz != NULL && thiz->size > index, RET_INVALID_PARAMS); 

	darray_destroy_data(thiz, thiz->data[index]);
	for(i = index; (i+1) < thiz->size; i++)
	{
		thiz->data[i] = thiz->data[i+1];
	}
	thiz->size--;

	darray_shrink(thiz);

	return RET_OK;
}

Ret darray_get_by_index(DArray* thiz, size_t index, void** data)
{

	return_val_if_fail(thiz != NULL && data != NULL && index < thiz->size, 
		RET_INVALID_PARAMS); 

	*data = thiz->data[index];

	return RET_OK;
}

Ret darray_set_by_index(DArray* thiz, size_t index, void* data)
{
	return_val_if_fail(thiz != NULL && index < thiz->size, 
		RET_INVALID_PARAMS); 

	thiz->data[index] = data;

	return RET_OK;
}

size_t   darray_length(DArray* thiz)
{
	return_val_if_fail(thiz != NULL, 0);

	return thiz->size;
}

Ret darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx)
{
	size_t i = 0;	
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	for(i = 0; i < thiz->size; i++)
	{
		ret = visit(ctx, thiz->data[i]);
	}

	return ret;
}

int      darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx)
{
	size_t i = 0;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	for(i = 0; i < thiz->size; i++)
	{
		if(cmp(ctx, thiz->data[i]) == 0)
		{
			break;
		}
	}

	return i;
}

void darray_destroy(DArray* thiz)
{
	size_t i = 0;
	
	if(thiz != NULL)
	{
		for(i = 0; i < thiz->size; i++)
		{
			darray_destroy_data(thiz, thiz->data[i]);
		}
		
		SAFE_FREE(thiz->data);
		SAFE_FREE(thiz);
	}

	return;
}

Ret    darray_sort(DArray* thiz, SortFunc sort, DataCompareFunc cmp)
{
	return_val_if_fail(thiz != NULL && sort != NULL && cmp != NULL, RET_INVALID_PARAMS);

	return sort(thiz->data, thiz->size, cmp);
}

#ifdef DARRAY_TEST

#include "sort.h"
#include <assert.h>
#include "test_helper.c"

static void darray_assert_sorted(DArray* thiz, DataCompareFunc cmp)
{
	size_t i = 0;
	for(i = 1; i < thiz->size; i++)
	{
		assert(cmp(thiz->data[i], thiz->data[i-1]) >= 0);
	}

	return;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_darray(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DArray* darray = darray_create(NULL, NULL);

	for(i = 0; i < n; i++)
	{
		assert(darray_append(darray, (void*)i) == RET_OK);
		assert(darray_length(darray) == (i + 1));
		assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(darray_set_by_index(darray, i, (void*)(2*i)) == RET_OK);
		assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(darray_set_by_index(darray, i, (void*)i) == RET_OK);
		assert(darray_find(darray, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++)
	{
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(darray_length(darray) == (n-i));
		assert(darray_delete(darray, 0) == RET_OK);
		assert(darray_length(darray) == (n-i-1));
		if((i + 1) < n)
		{
			assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(darray_length(darray) == 0);

	for(i = 0; i < n; i++)
	{
		assert(darray_prepend(darray, (void*)i) == RET_OK);
		assert(darray_length(darray) == (i + 1));
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(darray_set_by_index(darray, 0, (void*)(2*i)) == RET_OK);
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(darray_set_by_index(darray, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(darray_foreach(darray, check_and_dec_int, &i) == RET_OK);

	darray_sort(darray, quick_sort, cmp_int);
	darray_assert_sorted(darray, cmp_int);

	darray_destroy(darray);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(darray_length(NULL) == 0);
	assert(darray_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(darray_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(darray_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(darray_find(NULL, NULL, NULL) < 0);
	assert(darray_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_darray();
	test_invalid_params();

	return;
}

int main(int argc, char* argv[])
{
	single_thread_test();

	return 0;
}
#endif

/* 
 * File :  test_helper.c
 */

static int cmp_int(void* ctx, void* data)
{
	return (int)ctx - (int)data;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}
all:
	gcc -g -m32 -DDARRAY_TEST -lpthread darray.c sort.c -o darray_test
	gcc -g -m32 -Wall -DSORT_TEST sort.c -o sort_test
	gcc -g -m32 -Wall -DSEARCH_TEST search.c -o search_test
	gcc -g -m32 -Wall -DUNIQUE_TEST unique.c darray.c sort.c -o unique_test

clean:
	rm -f *test *.exe *.so

第四章 并发与同步

4.1 并发

4.2 同步

/*
 * File:    typedef.h
 */

#include <stdio.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

#endif/*TYPEDEF_H*/

/*
 * File:    locker
 */

#include "typedef.h"

#ifndef LOCKER_H
#define LOCKER_H

DECLS_BEGIN

struct _Locker;
typedef struct _Locker Locker;

typedef Ret  (*LockerLockFunc)(Locker* thiz);
typedef Ret  (*LockerUnlockFunc)(Locker* thiz);
typedef void (*LockerDestroyFunc)(Locker* thiz);

struct _Locker
{
	LockerLockFunc    lock;
	LockerUnlockFunc  unlock;
	LockerDestroyFunc destroy;

	char priv[0];
};

static inline Ret locker_lock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->lock != NULL, RET_INVALID_PARAMS);

	return thiz->lock(thiz);
}

static inline Ret locker_unlock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->unlock != NULL, RET_INVALID_PARAMS);

	return thiz->unlock(thiz);
}

static inline void locker_destroy(Locker* thiz)
{
	return_if_fail(thiz != NULL && thiz->destroy != NULL);

	thiz->destroy(thiz);

	return;
}

DECLS_END

#endif/*LOCKER_H*/

/*
 * File:    locker_pthread.h
 */
#include "locker.h"

#ifndef LOCKER_PTHREAD_H
#define LOCKER_PTHREAD_H

DECLS_BEGIN

Locker* locker_pthread_create(void);

DECLS_END

#endif/*LOCKER_PTHREAD_H*/

/*
 * File:    locker_pthread.c
 */

#include <stdlib.h>
#include <pthread.h>
#include "locker_pthread.h"

typedef struct _PrivInfo
{
	pthread_mutex_t mutex;
}PrivInfo;

static Ret  locker_pthread_lock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_lock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static Ret  locker_pthread_unlock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_unlock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static void locker_pthread_destroy(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_destroy(&priv->mutex);

	SAFE_FREE(thiz);

	return;
}

Locker* locker_pthread_create(void)
{
	Locker* thiz = (Locker*)malloc(sizeof(Locker) + sizeof(PrivInfo));

	if(thiz != NULL)
	{
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->lock    = locker_pthread_lock;
		thiz->unlock  = locker_pthread_unlock;
		thiz->destroy = locker_pthread_destroy;

		pthread_mutex_init(&(priv->mutex), NULL);
	}

	return thiz;
}


/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "locker.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

typedef void     (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int      (*DListDataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, Locker* locker);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include <unistd.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	Locker* locker;
	DListNode* first;
	void* data_destroy_ctx;
	DListDataDestroyFunc data_destroy;
};

static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL)
	{
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL)
	{
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL)
	{
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		SAFE_FREE(node);
	}

	return;
}

static void dlist_lock(DList* thiz)
{
	if(thiz->locker != NULL)
	{
		locker_lock(thiz->locker);
	}

	return;
}

static void dlist_unlock(DList* thiz)
{
	if(thiz->locker != NULL)
	{
		locker_unlock(thiz->locker);
	}

	return;
}

static void dlist_destroy_locker(DList* thiz)
{
	if(thiz->locker != NULL)
	{
		locker_unlock(thiz->locker);
		locker_destroy(thiz->locker);
	}

	return;
}

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, Locker* locker)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL)
	{
		thiz->first  = NULL;
		thiz->locker = locker;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0)
	{
		iter = iter->next;
		index--;
	}

	if(!fail_return_last)
	{
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
	Ret ret = RET_OK;
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	dlist_lock(thiz);

	do
	{
		if((node = dlist_create_node(thiz, data)) == NULL)
		{
			ret = RET_OOM;
			break;
		}

		if(thiz->first == NULL)
		{
			thiz->first = node;
			break;
		}

		cursor = dlist_get_node(thiz, index, 1);
		
		if(index < dlist_length(thiz))
		{
			node->next = cursor;
			if(cursor->prev != NULL)
			{
				cursor->prev->next = node;
			}
			cursor->prev = node;
			if(thiz->first == cursor)
			{
				thiz->first = node;
			}
		}
		else
		{
			cursor->next = node;
			node->prev = cursor;
		}
	}while(0);

	dlist_unlock(thiz);

	return ret;
}

Ret dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
	Ret ret = RET_OK;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 
	
	dlist_lock(thiz);
	cursor = dlist_get_node(thiz, index, 0);

	do
	{
		if(cursor == NULL)
		{
			ret = RET_INVALID_PARAMS;
			break;
		}

		if(cursor != NULL)
		{
			if(cursor == thiz->first)
			{
				thiz->first = cursor->next;
			}

			if(cursor->next != NULL)
			{
				cursor->next->prev = cursor->prev;
			}

			if(cursor->prev != NULL)
			{
				cursor->prev->next = cursor->next;
			}

			dlist_destroy_node(thiz, cursor);
		}

	}while(0);

	dlist_unlock(thiz);

	return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS); 

	dlist_lock(thiz);

	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL)
	{
		*data = cursor->data;
	}
	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	dlist_lock(thiz);
	
	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL)
	{
		cursor->data = data;
	}

	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, 0);

	dlist_lock(thiz);

	iter = thiz->first;

	while(iter != NULL)
	{
		length++;
		iter = iter->next;
	}

	dlist_unlock(thiz);

	return length;
}

Ret dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
	Ret ret = RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	dlist_lock(thiz);

	iter = thiz->first;

	while(iter != NULL && ret != RET_STOP)
	{
		ret = visit(ctx, iter->data);

		iter = iter->next;
	}
	dlist_unlock(thiz);

	return ret;
}

int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	dlist_lock(thiz);

	iter = thiz->first;
	while(iter != NULL)
	{
		if(cmp(ctx, iter->data) == 0)
		{
			break;
		}
		i++;
		iter = iter->next;
	}

	dlist_unlock(thiz);

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	dlist_lock(thiz);

	iter = thiz->first;
	while(iter != NULL)
	{
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	dlist_destroy_locker(thiz);
	
	SAFE_FREE(thiz);

	return;
}

#ifdef DLIST_TEST

#include <assert.h>
#include <pthread.h>
#include "locker_pthread.h"

static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_dlist(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DList* dlist = dlist_create(NULL, NULL, NULL);

	for(i = 0; i < n; i++)
	{
		assert(dlist_append(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++)
	{
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n)
		{
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == RET_OK);

	dlist_destroy(dlist);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_dlist();
	test_invalid_params();

	return;
}

static void* producer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 100; i++)
	{
		assert(dlist_append(dlist, (void*)i) == RET_OK);
	}
	sleep(1);
	for(i = 0; i < 100; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
	}

	return NULL;
}

static void* consumer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 200; i++)
	{
		usleep(20);
		assert(dlist_delete(dlist, 0) == RET_OK);
	}

	return NULL;
}

static void multi_thread_test(void)
{
	pthread_t consumer_tid = 0;
	pthread_t producer_tid = 0;
	DList* dlist = dlist_create(NULL, NULL, locker_pthread_create());
	pthread_create(&producer_tid, NULL, producer, dlist);
	pthread_create(&consumer_tid, NULL, consumer, dlist);

	pthread_join(consumer_tid, NULL);
	pthread_join(producer_tid, NULL);

	return;
}
int main(int argc, char* argv[])
{
	single_thread_test();
	multi_thread_test();

	return 0;
}
#endif

CFILES=dlist.c  locker_pthread.c 
all:
	#gcc -g -m32 -fPIC -shared -lpthread $(CFILES)  -o libdlist.so  
	gcc -g -m32 -shared -lpthread $(CFILES)  -o libdlist.so  
	gcc -g -m32 -DDLIST_TEST  $(CFILES)  -o dlist_test  -lpthread

clean:
	rm -f *test *.exe *.so

4.3 嵌套锁与装饰模式

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

#endif/*TYPEDEF_H*/

/*
 * File:    locker.h
 */

#include "typedef.h"

#ifndef LOCKER_H
#define LOCKER_H

DECLS_BEGIN

struct _Locker;
typedef struct _Locker Locker;

typedef Ret  (*LockerLockFunc)(Locker* thiz);
typedef Ret  (*LockerUnlockFunc)(Locker* thiz);
typedef void (*LockerDestroyFunc)(Locker* thiz);

struct _Locker
{
	LockerLockFunc    lock;
	LockerUnlockFunc  unlock;
	LockerDestroyFunc destroy;

	char priv[0];
};

static inline Ret locker_lock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->lock != NULL, RET_INVALID_PARAMS);

	return thiz->lock(thiz);
}

static inline Ret locker_unlock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->unlock != NULL, RET_INVALID_PARAMS);

	return thiz->unlock(thiz);
}

static inline void locker_destroy(Locker* thiz)
{
	return_if_fail(thiz != NULL && thiz->destroy != NULL);

	thiz->destroy(thiz);

	return;
}

DECLS_END

#endif/*LOCKER_H*/

/*
 * File:    locker_pthread.h
 */

#include "locker.h"

#ifndef LOCKER_PTHREAD_H
#define LOCKER_PTHREAD_H

DECLS_BEGIN

Locker* locker_pthread_create(void);

DECLS_END

#endif/*LOCKER_PTHREAD_H*/

/*
 * File:    locker_pthread.c
 */

#include <stdlib.h>
#include <pthread.h>
#include "locker_pthread.h"

typedef struct _PrivInfo
{
	pthread_mutex_t mutex;
}PrivInfo;

static Ret  locker_pthread_lock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_lock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static Ret  locker_pthread_unlock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_unlock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static void locker_pthread_destroy(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_destroy(&priv->mutex);

	SAFE_FREE(thiz);

	return;
}

Locker* locker_pthread_create(void)
{
	Locker* thiz = (Locker*)malloc(sizeof(Locker) + sizeof(PrivInfo));

	if(thiz != NULL) {
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->lock    = locker_pthread_lock;
		thiz->unlock  = locker_pthread_unlock;
		thiz->destroy = locker_pthread_destroy;

		pthread_mutex_init(&(priv->mutex), NULL);
	}

	return thiz;
}


/*
 * File:    locker_nest.h
 */

#include "locker.h"

#ifndef LOCKER_NEST_H
#define LOCKER_NEST_H

DECLS_BEGIN

typedef int (*TaskSelfFunc)(void);
Locker* locker_nest_create(Locker* real_locker, TaskSelfFunc task_self);

DECLS_END

#endif/*LOCKER_NEST_H*/

/*
 * File:    locker_nest.c
 */

#include "locker_nest.h"

typedef struct _PrivInfo
{
	int owner;
	int refcount;
	Locker* real_locker;
	TaskSelfFunc task_self;
}PrivInfo;

static Ret  locker_nest_lock(Locker* thiz)
{
	Ret ret = RET_OK;
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	if(priv->owner == priv->task_self()) {
		priv->refcount++;
	} else {
		if( (ret = locker_lock(priv->real_locker)) == RET_OK) {
			priv->refcount = 1;
			priv->owner = priv->task_self();
		}
	}

	return ret;
}

static Ret  locker_nest_unlock(Locker* thiz)
{
	Ret ret = RET_OK;
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return_val_if_fail(priv->owner == priv->task_self(), RET_FAIL);
	
	priv->refcount--;
	if(priv->refcount == 0) {
		priv->owner = 0;
		ret = locker_unlock(priv->real_locker);
	}

	return ret;
}

static void  locker_nest_destroy(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	priv->owner = 0;
	priv->refcount = 0;
	locker_destroy(priv->real_locker);
	priv->real_locker = NULL;

	SAFE_FREE(thiz);

	return;
}

Locker* locker_nest_create(Locker* real_locker, TaskSelfFunc task_self)
{
	Locker* thiz = NULL;
	return_val_if_fail(real_locker != NULL && task_self != NULL, NULL);
	
	thiz = (Locker*)malloc(sizeof(Locker) + sizeof(PrivInfo));

	if(thiz != NULL) {
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->lock    = locker_nest_lock;
		thiz->unlock  = locker_nest_unlock;
		thiz->destroy = locker_nest_destroy;

		priv->owner = 0;
		priv->refcount = 0;
		priv->real_locker = real_locker;
		priv->task_self = task_self;
	}

	return thiz;
}

/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "locker.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

typedef void     (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int      (*DListDataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, Locker* locker);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include <unistd.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	Locker* locker;
	DListNode* first;
	void* data_destroy_ctx;
	DListDataDestroyFunc data_destroy;
};

static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL){
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL){
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL){
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		SAFE_FREE(node);
	}

	return;
}

static void dlist_lock(DList* thiz)
{
	if(thiz->locker != NULL){
		locker_lock(thiz->locker);
	}

	return;
}

static void dlist_unlock(DList* thiz)
{
	if(thiz->locker != NULL) {
		locker_unlock(thiz->locker);
	}

	return;
}

static void dlist_destroy_locker(DList* thiz)
{
	if(thiz->locker != NULL) {
		locker_unlock(thiz->locker);
		locker_destroy(thiz->locker);
		thiz->locker = NULL;
	}

	return;
}

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, Locker* locker)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL){
		thiz->first  = NULL;
		thiz->locker = locker;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0) {
		iter = iter->next;
		index--;
	}

	if(!fail_return_last) {
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
	Ret ret = RET_OK;
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	dlist_lock(thiz);

	do
	{
		if((node = dlist_create_node(thiz, data)) == NULL) {
			ret = RET_OOM;
			break;
		}

		if(thiz->first == NULL) {
			thiz->first = node;
			break;
		}

		cursor = dlist_get_node(thiz, index, 1);
		
		if(index < dlist_length(thiz)) {
			node->next = cursor;
			if(cursor->prev != NULL) {
				cursor->prev->next = node;
			}
			cursor->prev = node;
			if(thiz->first == cursor) {
				thiz->first = node;
			}
		}else {
			cursor->next = node;
			node->prev = cursor;
		}
	}while(0);

	dlist_unlock(thiz);

	return ret;
}

Ret dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
	Ret ret = RET_OK;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 
	
	dlist_lock(thiz);
	cursor = dlist_get_node(thiz, index, 0);

	do
	{
		if(cursor == NULL) {
			ret = RET_INVALID_PARAMS;
			break;
		}

		if(cursor != NULL) {
			if(cursor == thiz->first) {
				thiz->first = cursor->next;
			}

			if(cursor->next != NULL) {
				cursor->next->prev = cursor->prev;
			}

			if(cursor->prev != NULL) {
				cursor->prev->next = cursor->next;
			}

			dlist_destroy_node(thiz, cursor);
		}

	}while(0);

	dlist_unlock(thiz);

	return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS); 

	dlist_lock(thiz);

	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL) {
		*data = cursor->data;
	}
	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	dlist_lock(thiz);
	
	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL) {
		cursor->data = data;
	}

	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, 0);

	dlist_lock(thiz);

	iter = thiz->first;

	while(iter != NULL) {
		length++;
		iter = iter->next;
	}

	dlist_unlock(thiz);

	return length;
}

Ret dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
	Ret ret = RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	dlist_lock(thiz);

	iter = thiz->first;

	while(iter != NULL && ret != RET_STOP) {
		ret = visit(ctx, iter->data);
		iter = iter->next;
	}
	dlist_unlock(thiz);

	return ret;
}

int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	dlist_lock(thiz);

	iter = thiz->first;
	while(iter != NULL) {
		if(cmp(ctx, iter->data) == 0) {
			break;
		}
		i++;
		iter = iter->next;
	}

	dlist_unlock(thiz);

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	dlist_lock(thiz);

	iter = thiz->first;
	while(iter != NULL) {
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	dlist_destroy_locker(thiz);

	SAFE_FREE(thiz);

	return;
}

#ifdef DLIST_TEST

#include <assert.h>
#include <pthread.h>
#include "locker_pthread.h"
#include "locker_nest.h"

static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_dlist(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DList* dlist = dlist_create(NULL, NULL, NULL);

	for(i = 0; i < n; i++){
		assert(dlist_append(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++){
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n){
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++){
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == RET_OK);

	dlist_destroy(dlist);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_dlist();
	test_invalid_params();

	return;
}

static void* producer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 100; i++){
		assert(dlist_append(dlist, (void*)i) == RET_OK);
	}
	sleep(1);
	for(i = 0; i < 100; i++){
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
	}

	return NULL;
}

static void* consumer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 200; i++){
		usleep(20);
		assert(dlist_delete(dlist, 0) == RET_OK);
	}

	return NULL;
}

static void multi_thread_test(void)
{
	pthread_t consumer_tid = 0;
	pthread_t producer_tid = 0;
	Locker* locker = locker_pthread_create();
	Locker* nest_locker = locker_nest_create(locker, (TaskSelfFunc)pthread_self);
	DList*  dlist = dlist_create(NULL, NULL, nest_locker);
	pthread_create(&producer_tid, NULL, producer, dlist);
	pthread_create(&consumer_tid, NULL, consumer, dlist);

	pthread_join(consumer_tid, NULL);
	pthread_join(producer_tid, NULL);
	dlist_destroy(dlist);

	return;
}
int main(int argc, char* argv[])
{
	single_thread_test();
	multi_thread_test();

	return 0;
}
#endif

CFILES=dlist.c  locker_pthread.c locker_nest.c
all:
	gcc -g -m32 -shared -lpthread $(CFILES) -o libdlist.so
	gcc -g -m32 -DDLIST_TEST  $(CFILES)  -o dlist_test -lpthread

clean:
	rm -f *test *.exe *.so

4.4 读写锁

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

#endif/*TYPEDEF_H*/

/*
 * File:    locker.h
 */

#include "typedef.h"

#ifndef LOCKER_H
#define LOCKER_H

DECLS_BEGIN

struct _Locker;
typedef struct _Locker Locker;

typedef Ret  (*LockerLockFunc)(Locker* thiz);
typedef Ret  (*LockerUnlockFunc)(Locker* thiz);
typedef void (*LockerDestroyFunc)(Locker* thiz);

struct _Locker
{
	LockerLockFunc    lock;
	LockerUnlockFunc  unlock;
	LockerDestroyFunc destroy;

	char priv[0];
};

static inline Ret locker_lock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->lock != NULL, RET_INVALID_PARAMS);

	return thiz->lock(thiz);
}

static inline Ret locker_unlock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->unlock != NULL, RET_INVALID_PARAMS);

	return thiz->unlock(thiz);
}

static inline void locker_destroy(Locker* thiz)
{
	return_if_fail(thiz != NULL && thiz->destroy != NULL);

	thiz->destroy(thiz);

	return;
}

DECLS_END

#endif/*LOCKER_H*/

/*
 * File:    locker_pthread.h
 */

#include "locker.h"

#ifndef LOCKER_PTHREAD_H
#define LOCKER_PTHREAD_H

DECLS_BEGIN

Locker* locker_pthread_create(void);

DECLS_END

#endif/*LOCKER_PTHREAD_H*/

/*
 * File:    locker_pthread.c
 */

#include <stdlib.h>
#include <pthread.h>
#include "locker_pthread.h"

typedef struct _PrivInfo
{
	pthread_mutex_t mutex;
}PrivInfo;

static Ret  locker_pthread_lock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_lock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static Ret  locker_pthread_unlock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_unlock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static void locker_pthread_destroy(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_destroy(&priv->mutex);

	SAFE_FREE(thiz);

	return;
}

Locker* locker_pthread_create(void)
{
	Locker* thiz = (Locker*)malloc(sizeof(Locker) + sizeof(PrivInfo));

	if(thiz != NULL)
	{
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->lock    = locker_pthread_lock;
		thiz->unlock  = locker_pthread_unlock;
		thiz->destroy = locker_pthread_destroy;

		pthread_mutex_init(&(priv->mutex), NULL);
	}

	return thiz;
}


/*
 * File:    locker_nest.h
 */

#include "locker.h"

#ifndef LOCKER_NEST_H
#define LOCKER_NEST_H

DECLS_BEGIN

typedef int (*TaskSelfFunc)(void);
Locker* locker_nest_create(Locker* real_locker, TaskSelfFunc task_self);

DECLS_END

#endif/*LOCKER_NEST_H*/

/*
 * File:    locker_nest.c
 */

#include "locker_nest.h"

typedef struct _PrivInfo
{
	int owner;
	int refcount;
	Locker* real_locker;
	TaskSelfFunc task_self;
}PrivInfo;

static Ret  locker_nest_lock(Locker* thiz)
{
	Ret ret = RET_OK;
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	if(priv->owner == priv->task_self())
	{
		priv->refcount++;
	}
	else
	{
		if( (ret = locker_lock(priv->real_locker)) == RET_OK)
		{
			priv->refcount = 1;
			priv->owner = priv->task_self();
		}
	}

	return ret;
}

static Ret  locker_nest_unlock(Locker* thiz)
{
	Ret ret = RET_OK;
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return_val_if_fail(priv->owner == priv->task_self(), RET_FAIL);
	
	priv->refcount--;
	if(priv->refcount == 0)
	{
		priv->owner = 0;
		ret = locker_unlock(priv->real_locker);
	}

	return ret;
}

static void  locker_nest_destroy(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	priv->owner = 0;
	priv->refcount = 0;
	locker_destroy(priv->real_locker);
	priv->real_locker = NULL;

	SAFE_FREE(thiz);

	return;
}

Locker* locker_nest_create(Locker* real_locker, TaskSelfFunc task_self)
{
	Locker* thiz = NULL;
	return_val_if_fail(real_locker != NULL && task_self != NULL, NULL);
	
	thiz = (Locker*)malloc(sizeof(Locker) + sizeof(PrivInfo));

	if(thiz != NULL)
	{
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->lock    = locker_nest_lock;
		thiz->unlock  = locker_nest_unlock;
		thiz->destroy = locker_nest_destroy;

		priv->owner = 0;
		priv->refcount = 0;
		priv->real_locker = real_locker;
		priv->task_self = task_self;
	}

	return thiz;
}

/*
 * File:    rw_locker.h
 */

#include "locker.h"

#ifndef RW_LOCKR_H
#define RW_LOCKER_H

struct _RwLocker;
typedef struct _RwLocker RwLocker;

RwLocker* rw_locker_create(Locker* rw_locker, Locker* rd_locker);

Ret rw_locker_wrlock(RwLocker* thiz);
Ret rw_locker_rdlock(RwLocker* thiz);
Ret rw_locker_unlock(RwLocker* thiz);

void rw_locker_destroy(RwLocker* thiz);

#endif/*RW_LOCKER_H*/

/*
 * File:    rw_locker.c
 */

#include "rw_locker.h"

typedef enum _RwLockerMode
{
	RW_LOCKER_NONE,
	RW_LOCKER_WR,
	RW_LOCKER_RD,
	RW_LOCKER_NR
}RwLockerMode;

struct _RwLocker
{
	int readers;
	RwLockerMode mode;
	Locker* rw_locker;
	Locker* rd_locker;
};

RwLocker* rw_locker_create(Locker* rw_locker, Locker* rd_locker)
{
	RwLocker* thiz = NULL;
	return_val_if_fail(rw_locker != NULL && rd_locker != NULL, NULL);

	thiz = (RwLocker*)malloc(sizeof(RwLocker));
	if(thiz != NULL)
	{
		thiz->readers = 0;
		thiz->mode = RW_LOCKER_NONE;
		thiz->rw_locker = rw_locker;
		thiz->rd_locker = rd_locker;
	}

	return thiz;
}

Ret rw_locker_wrlock(RwLocker* thiz)
{
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	if((ret = locker_lock(thiz->rw_locker)) == RET_OK)
	{
		thiz->mode = RW_LOCKER_WR;
	}

	return ret;
}

Ret rw_locker_rdlock(RwLocker* thiz)
{
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);
	
	if((ret = locker_lock(thiz->rd_locker)) == RET_OK)
	{
		thiz->readers++;
		if(thiz->readers == 1)
		{
			ret = locker_lock(thiz->rw_locker);
			thiz->mode = RW_LOCKER_RD;
		}
		locker_unlock(thiz->rd_locker);
	}

	return ret;
}

Ret rw_locker_unlock(RwLocker* thiz)
{
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	if(thiz->mode == RW_LOCKER_WR)
	{
		thiz->mode == RW_LOCKER_NONE;
		ret = locker_unlock(thiz->rw_locker);
	}
	else
	{
		assert(thiz->mode == RW_LOCKER_RD);
		if((ret = locker_lock(thiz->rd_locker)) == RET_OK)
		{
			thiz->readers--;
			if(thiz->readers == 0)
			{
				thiz->mode == RW_LOCKER_NONE;
				ret = locker_unlock(thiz->rw_locker);
			}
			locker_unlock(thiz->rd_locker);
		}
	}

	return ret;
}

void rw_locker_destroy(RwLocker* thiz)
{
	if(thiz != NULL)
	{
		locker_destroy(thiz->rd_locker);
		locker_destroy(thiz->rw_locker);
		thiz->rd_locker = thiz->rw_locker = NULL;
		SAFE_FREE(thiz);
	}

	return;
}


/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "rw_locker.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

typedef void     (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int      (*DListDataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, RwLocker* rw_locker);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    dlist.c
 */


#include <stdlib.h>
#include <unistd.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	RwLocker* rw_locker;
	DListNode* first;
	void* data_destroy_ctx;
	DListDataDestroyFunc data_destroy;
};

size_t dlist_length_nolock(DList* thiz);

static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL)
	{
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL)
	{
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL)
	{
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		SAFE_FREE(node);
	}

	return;
}

static void dlist_wrlock(DList* thiz)
{
	if(thiz->rw_locker != NULL)
	{
		rw_locker_wrlock(thiz->rw_locker);
	}

	return;
}

static void dlist_rdlock(DList* thiz)
{
	if(thiz->rw_locker != NULL)
	{
		rw_locker_rdlock(thiz->rw_locker);
	}

	return;
}

static void dlist_unlock(DList* thiz)
{
	if(thiz->rw_locker != NULL)
	{
		rw_locker_unlock(thiz->rw_locker);
	}

	return;
}

static void dlist_destroy_locker(DList* thiz)
{
	if(thiz->rw_locker != NULL)
	{
		rw_locker_unlock(thiz->rw_locker);
		rw_locker_destroy(thiz->rw_locker);
	}

	return;
}

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, RwLocker* rw_locker)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL)
	{
		thiz->first  = NULL;
		thiz->rw_locker = rw_locker;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0)
	{
		iter = iter->next;
		index--;
	}

	if(!fail_return_last)
	{
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
	Ret ret = RET_OK;
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	dlist_wrlock(thiz);

	do
	{
		if((node = dlist_create_node(thiz, data)) == NULL)
		{
			ret = RET_OOM;
			break;
		}

		if(thiz->first == NULL)
		{
			thiz->first = node;
			break;
		}

		cursor = dlist_get_node(thiz, index, 1);
		
		if(index < dlist_length_nolock(thiz))
		{
			node->next = cursor;
			if(cursor->prev != NULL)
			{
				cursor->prev->next = node;
			}
			cursor->prev = node;
			if(thiz->first == cursor)
			{
				thiz->first = node;
			}
		}
		else
		{
			cursor->next = node;
			node->prev = cursor;
		}
	}while(0);

	dlist_unlock(thiz);

	return ret;
}

Ret dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
	Ret ret = RET_OK;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 
	
	dlist_wrlock(thiz);
	cursor = dlist_get_node(thiz, index, 0);

	do
	{
		if(cursor == NULL)
		{
			ret = RET_INVALID_PARAMS;
			break;
		}

		if(cursor != NULL)
		{
			if(cursor == thiz->first)
			{
				thiz->first = cursor->next;
			}

			if(cursor->next != NULL)
			{
				cursor->next->prev = cursor->prev;
			}

			if(cursor->prev != NULL)
			{
				cursor->prev->next = cursor->next;
			}

			dlist_destroy_node(thiz, cursor);
		}

	}while(0);

	dlist_unlock(thiz);

	return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS); 

	dlist_rdlock(thiz);

	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL)
	{
		*data = cursor->data;
	}
	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	dlist_wrlock(thiz);
	
	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL)
	{
		cursor->data = data;
	}

	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

size_t dlist_length_nolock(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;

	iter = thiz->first;

	while(iter != NULL)
	{
		length++;
		iter = iter->next;
	}

	return length;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	
	return_val_if_fail(thiz != NULL, 0);

	dlist_rdlock(thiz);
	
	length = dlist_length_nolock(thiz);

	dlist_unlock(thiz);

	return length;
}

Ret dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
	Ret ret = RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	dlist_rdlock(thiz);

	iter = thiz->first;

	while(iter != NULL && ret != RET_STOP)
	{
		ret = visit(ctx, iter->data);

		iter = iter->next;
	}
	dlist_unlock(thiz);

	return ret;
}

int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	dlist_rdlock(thiz);

	iter = thiz->first;
	while(iter != NULL)
	{
		if(cmp(ctx, iter->data) == 0)
		{
			break;
		}
		i++;
		iter = iter->next;
	}

	dlist_unlock(thiz);

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	dlist_wrlock(thiz);

	iter = thiz->first;
	while(iter != NULL)
	{
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	dlist_destroy_locker(thiz);
	
	SAFE_FREE(thiz);

	return;
}

#ifdef DLIST_TEST

#include <assert.h>
#include <pthread.h>
#include "locker_pthread.h"
#include "locker_nest.h"

static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_dlist(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DList* dlist = dlist_create(NULL, NULL, NULL);

	for(i = 0; i < n; i++)
	{
		assert(dlist_append(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++)
	{
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n)
		{
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == RET_OK);

	dlist_destroy(dlist);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_dlist();
	test_invalid_params();

	return;
}

#define NR 1000
static void* producer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < NR; i++)
	{
		assert(dlist_append(dlist, (void*)i) == RET_OK);
	}
	sleep(1);
	for(i = 0; i < NR; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
	}
	for(i = 0; i < NR; i++)
	{
		assert(dlist_insert(dlist, i, (void*)i) == RET_OK);
	}

	return NULL;
}

static void* consumer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 3 * NR; i++)
	{
		usleep(20);
		assert(dlist_delete(dlist, 0) == RET_OK);
	}

	return NULL;
}

static void* reader(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < NR; i++)
	{
		int length = dlist_length(dlist);
		dlist_find(dlist, cmp_int, (void*)i);
	}

	return NULL;
}

static void multi_thread_test(void)
{
	pthread_t consumer_tid = 0;
	pthread_t producer_tid = 0;
	pthread_t reader_tid = 0;
	Locker* rw_locker = locker_pthread_create();
	Locker* rd_locker = locker_pthread_create();
	DList* dlist = dlist_create(NULL, NULL,
		rw_locker_create(rw_locker, rd_locker));

	pthread_create(&producer_tid, NULL, producer, dlist);
	pthread_create(&consumer_tid, NULL, consumer, dlist);
	pthread_create(&reader_tid, NULL, reader, dlist);

	pthread_join(consumer_tid, NULL);
	pthread_join(producer_tid, NULL);
	pthread_join(reader_tid, NULL);
	printf("length=%d\n", dlist_length(dlist));
	dlist_destroy(dlist);

	return;
}
int main(int argc, char* argv[])
{
	single_thread_test();
	multi_thread_test();

	return 0;
}
#endif

CFILES=dlist.c  locker_pthread.c locker_nest.c rw_locker.c
all:
	gcc -g -m32  -shared -lpthread $(CFILES) -o libdlist.so
	gcc -g -m32 -DDLIST_TEST  $(CFILES) -o dlist_test -lpthread

clean:
	rm -f *test *.exe *.so

4.5 无锁数据结构

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

#endif/*TYPEDEF_H*/

/*
 * File:    fifo_ring.c
 */

#include "typedef.h"

typedef struct _FifoRing
{
	int r_cursor;
	int w_cursor;
	size_t length;
	void* data[0];
	
}FifoRing;

FifoRing* fifo_ring_create(size_t length)
{
	FifoRing* thiz = NULL;
	
	return_val_if_fail(length > 1, NULL);

	thiz = (FifoRing*)malloc(sizeof(FifoRing) + length * sizeof(void*));

	if(thiz != NULL) {
		thiz->r_cursor = 0;
		thiz->w_cursor = 0;
		thiz->length   = length;
	}

	return thiz;
}

Ret fifo_ring_pop(FifoRing* thiz, void** data)
{
	Ret ret = RET_FAIL;
	return_val_if_fail(thiz != NULL && data != NULL, RET_FAIL);

	if(thiz->r_cursor != thiz->w_cursor) {
		*data = thiz->data[thiz->r_cursor];
		thiz->r_cursor = (thiz->r_cursor + 1)%thiz->length;

		ret = RET_OK;
	}

	return ret;
}

Ret fifo_ring_push(FifoRing* thiz, void* data)    
{
	int w_cursor = 0;
	Ret ret = RET_FAIL;
	return_val_if_fail(thiz != NULL, RET_FAIL);

	w_cursor = (thiz->w_cursor + 1) % thiz->length;
	
	if(w_cursor != thiz->r_cursor) {
		thiz->data[thiz->w_cursor] = data;
		thiz->w_cursor = w_cursor;

		ret = RET_OK;
	}

	return ret;
}

void fifo_ring_destroy(FifoRing* thiz)
{
	if(thiz != NULL) {
		free(thiz);
	}

	return;
}

#ifdef FIFO_RING_TEST
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

//#define NR 1000000
#define NR 1000

static void* thread_push(void* param)
{
	int i = 0;
	FifoRing* fifo = (FifoRing*)param;

	while(i < NR) {
		if(fifo_ring_push(fifo, (void*)i) == RET_OK) {
			i++;
		}else{
			usleep(10);
		}
	}

	return NULL;
}

static void* thread_pop(void* param)
{
	int i = 0;
	void* data = 0;
	FifoRing* fifo = (FifoRing*)param;

	while(i < NR) {
		if(fifo_ring_pop(fifo, (void**)&data) == RET_OK) {
			assert(i == (int)data);
			i++;
		}else{
			usleep(10);
		}
	}

	return NULL;
}

void push_pop_test(size_t fifo_length)
{
	pthread_t push_tid = 0;
	pthread_t pop_tid = 0;
	FifoRing* fifo = fifo_ring_create(fifo_length);

	pthread_create(&push_tid, NULL, thread_push, fifo);
	pthread_create(&pop_tid, NULL, thread_pop, fifo);

	pthread_join(push_tid, NULL);
	pthread_join(pop_tid, NULL);

	fifo_ring_destroy(fifo);
	
	return;
}

int main(int argc, char* argv[])
{
	push_pop_test(2);
	push_pop_test(20);
	push_pop_test(200);
	push_pop_test(2000);

	return 0;
}

#endif/*FIFO_RING_TEST*/

/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "locker.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

typedef void     (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int      (*DListDataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, Locker* locker);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    swmr_dlist.c
 */

#include <unistd.h>
#include "dlist.h"
#include "iatomic.h"

#define CAS(_a, _o, _n)                                    \
({ __typeof__(_o) __o = _o;                                \
   __asm__ __volatile__(                                   \
       "lock cmpxchg %3,%1"                                \
       : "=a" (__o), "=m" (*(volatile unsigned int *)(_a)) \
       :  "0" (__o), "r" (_n) );                           \
   __o;                                                    \
})

typedef struct _SwmrDList
{
	atomic_t rd_index_and_ref;
	DList* dlists[2];
}SwmrDList;

void swmr_dlist_destroy(SwmrDList* thiz);

SwmrDList* swmr_dlist_create(DListDataDestroyFunc data_destroy, void* ctx)
{
	Ret ret = RET_FAIL;
	SwmrDList* thiz = (SwmrDList*)calloc(1, sizeof(SwmrDList));

	do
	{
		if((thiz->dlists[0] = dlist_create(data_destroy, ctx, NULL)) == NULL) {
			break;
		}
	
		if((thiz->dlists[1] = dlist_create(data_destroy, ctx, NULL)) == NULL) {
			break;
		}

		ret = RET_OK;
	}while(0);

	if(ret != RET_OK) {
		swmr_dlist_destroy(thiz);
		thiz = NULL;
	}

	return thiz;
}

void swmr_dlist_destroy(SwmrDList* thiz)
{
	if(thiz != NULL) {
		if(thiz->dlists != NULL) {
			dlist_destroy(thiz->dlists[0]);
			dlist_destroy(thiz->dlists[1]);
			thiz->dlists[0] = NULL;
			thiz->dlists[1] = NULL;
		}
		free(thiz);
	}

	return;
}

int swmr_dlist_find(SwmrDList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int ret = 0;
	return_val_if_fail(thiz != NULL && thiz->dlists != NULL, -1);

	atomic_inc(&(thiz->rd_index_and_ref));
	size_t rd_index = (thiz->rd_index_and_ref.counter>>24) & 0x1;
	ret = dlist_find(thiz->dlists[rd_index], cmp, ctx);
	atomic_dec(&(thiz->rd_index_and_ref));

	return ret;
}

int swmr_dlist_length(SwmrDList* thiz)
{
	int ret = 0;
	return_val_if_fail(thiz != NULL && thiz->dlists != NULL, -1);

	atomic_inc(&(thiz->rd_index_and_ref));
	size_t rd_index = (thiz->rd_index_and_ref.counter>>24) & 0x1;
	ret = dlist_length(thiz->dlists[rd_index]);
	atomic_dec(&(thiz->rd_index_and_ref));

	return ret;
}

Ret swmr_dlist_insert(SwmrDList* thiz, size_t index, void* data)
{
	Ret ret = RET_FAIL;
	DList* wr_dlist = NULL;
	return_val_if_fail(thiz != NULL && thiz->dlists != NULL, ret);

	size_t wr_index = !((thiz->rd_index_and_ref.counter>>24) & 0x1);
	if((ret = dlist_insert(thiz->dlists[wr_index], index, data)) == RET_OK) {
		int rd_index_old = thiz->rd_index_and_ref.counter & 0xFF000000;
		int rd_index_new = wr_index << 24;

		do
		{
			usleep(100);
		}while(CAS(&(thiz->rd_index_and_ref), rd_index_old, rd_index_new));
		
		wr_index = rd_index_old>>24;
		ret = dlist_insert(thiz->dlists[wr_index], index, data);
	}

	return ret;
}

Ret swmr_dlist_delete(SwmrDList* thiz, size_t index)
{
	Ret ret = RET_FAIL;
	DList* wr_dlist = NULL;
	return_val_if_fail(thiz != NULL && thiz->dlists != NULL, ret);

	size_t wr_index = !((thiz->rd_index_and_ref.counter>>24) & 0x1);
	if((ret = dlist_delete(thiz->dlists[wr_index], index)) == RET_OK) {
		int rd_index_old = thiz->rd_index_and_ref.counter & 0xFF000000;
		int rd_index_new = wr_index << 24;

		do
		{
			usleep(100);
		}while(CAS(&(thiz->rd_index_and_ref), rd_index_old, rd_index_new));
		
		wr_index = rd_index_old>>24;
		ret = dlist_delete(thiz->dlists[wr_index], index);
	}

	return ret;
}

#ifdef SWMR_DLIST_TEST
#include <pthread.h>
#define NR 1000
static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}
static void* reader(void* param)
{
	int i = 0;
	int j = 0;
	size_t length = 0;
	SwmrDList* swmr = (SwmrDList*)param;

	for(j = 0; j < NR; j++) {
		for(i = 0; i < swmr_dlist_length(swmr); i++) {
			assert(swmr_dlist_find(swmr, cmp_int, (void*)i) == i);
		}
	}

	return NULL;
}

static void* writer(void* param)
{
	int i = 0;
	SwmrDList* swmr = (SwmrDList*)param;

	for(i = 0; i < NR; i++) {
		swmr_dlist_insert(swmr, i, (void*)i);
	}
	
	for(; i>0; i--) {
		swmr_dlist_delete(swmr, i);
	}

	return NULL;
}

#define RD_NR 100

int main(int argc, char* argv[])
{
	int i = 0;
	pthread_t wr_tid = 0;
	pthread_t rd_tids[RD_NR] = {0};
	SwmrDList* swmr = swmr_dlist_create(NULL, NULL);

	pthread_create(&wr_tid, NULL, writer, swmr);
	for(i = 0; i < RD_NR; i++) {
		pthread_create(rd_tids+i, NULL, reader, swmr);
	}
	
	for(i = 0; i < RD_NR; i++) {
		pthread_join(rd_tids[i], NULL);
	}

	pthread_join(wr_tid, NULL);

	return 0;
}
#endif/*SWMR_DLIST_TEST*/

#ifndef __ALSA_IATOMIC_H
#define __ALSA_IATOMIC_H

#if defined(__i386__) || defined(__x86_64__)

/*
 * Atomic operations that C can't guarantee us.  Useful for
 * resource counting etc..
 */

#define ATOMIC_SMP_LOCK "lock ; "

/*
 * Make sure gcc doesn't try to be clever and move things around
 * on us. We need to use _exactly_ the address the user gave us,
 * not some alias that contains the same information.
 */
typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

/**
 * atomic_read - read atomic variable
 * @v: pointer of type atomic_t
 * 
 * Atomically reads the value of @v.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
#define atomic_read(v)		((v)->counter)

/**
 * atomic_set - set atomic variable
 * @v: pointer of type atomic_t
 * @i: required value
 * 
 * Atomically sets the value of @v to @i.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
#define atomic_set(v,i)		(((v)->counter) = (i))

/**
 * atomic_add - add integer to atomic variable
 * @i: integer value to add
 * @v: pointer of type atomic_t
 * 
 * Atomically adds @i to @v.  Note that the guaranteed useful range
 * of an atomic_t is only 24 bits.
 */
static __inline__ void atomic_add(int i, atomic_t *v)
{
	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "addl %1,%0"
		:"=m" (v->counter)
		:"ir" (i), "m" (v->counter));
}

/**
 * atomic_sub - subtract the atomic variable
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 * 
 * Atomically subtracts @i from @v.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
static __inline__ void atomic_sub(int i, atomic_t *v)
{
	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "subl %1,%0"
		:"=m" (v->counter)
		:"ir" (i), "m" (v->counter));
}

/**
 * atomic_sub_and_test - subtract value from variable and test result
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 * 
 * Atomically subtracts @i from @v and returns
 * true if the result is zero, or false for all
 * other cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
{
	unsigned char c;

	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "subl %2,%0; sete %1"
		:"=m" (v->counter), "=qm" (c)
		:"ir" (i), "m" (v->counter) : "memory");
	return c;
}

/**
 * atomic_inc - increment atomic variable
 * @v: pointer of type atomic_t
 * 
 * Atomically increments @v by 1.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
static __inline__ void atomic_inc(atomic_t *v)
{
	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "incl %0"
		:"=m" (v->counter)
		:"m" (v->counter));
}

/**
 * atomic_dec - decrement atomic variable
 * @v: pointer of type atomic_t
 * 
 * Atomically decrements @v by 1.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
static __inline__ void atomic_dec(atomic_t *v)
{
	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "decl %0"
		:"=m" (v->counter)
		:"m" (v->counter));
}

/**
 * atomic_dec_and_test - decrement and test
 * @v: pointer of type atomic_t
 * 
 * Atomically decrements @v by 1 and
 * returns true if the result is 0, or false for all other
 * cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
static __inline__ int atomic_dec_and_test(atomic_t *v)
{
	unsigned char c;

	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "decl %0; sete %1"
		:"=m" (v->counter), "=qm" (c)
		:"m" (v->counter) : "memory");
	return c != 0;
}

/**
 * atomic_inc_and_test - increment and test 
 * @v: pointer of type atomic_t
 * 
 * Atomically increments @v by 1
 * and returns true if the result is zero, or false for all
 * other cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
static __inline__ int atomic_inc_and_test(atomic_t *v)
{
	unsigned char c;

	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "incl %0; sete %1"
		:"=m" (v->counter), "=qm" (c)
		:"m" (v->counter) : "memory");
	return c != 0;
}

/**
 * atomic_add_negative - add and test if negative
 * @v: pointer of type atomic_t
 * @i: integer value to add
 * 
 * Atomically adds @i to @v and returns true
 * if the result is negative, or false when
 * result is greater than or equal to zero.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
static __inline__ int atomic_add_negative(int i, atomic_t *v)
{
	unsigned char c;

	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "addl %2,%0; sets %1"
		:"=m" (v->counter), "=qm" (c)
		:"ir" (i), "m" (v->counter) : "memory");
	return c;
}

/* These are x86-specific, used by some header files */
#define atomic_clear_mask(mask, addr) \
__asm__ __volatile__(ATOMIC_SMP_LOCK "andl %0,%1" \
: : "r" (~(mask)),"m" (*addr) : "memory")

#define atomic_set_mask(mask, addr) \
__asm__ __volatile__(ATOMIC_SMP_LOCK "orl %0,%1" \
: : "r" (mask),"m" (*addr) : "memory")

/*
 * Force strict CPU ordering.
 * And yes, this is required on UP too when we're talking
 * to devices.
 *
 * For now, "wmb()" doesn't actually do anything, as all
 * Intel CPU's follow what Intel calls a *Processor Order*,
 * in which all writes are seen in the program order even
 * outside the CPU.
 *
 * I expect future Intel CPU's to have a weaker ordering,
 * but I'd also expect them to finally get their act together
 * and add some real memory barriers if so.
 */
 
#ifdef __i386__
#define mb() 	__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
#define rmb()	mb()
#define wmb()	__asm__ __volatile__ ("": : :"memory")
#else
#define mb() 	asm volatile("mfence":::"memory")
#define rmb()	asm volatile("lfence":::"memory")
#define wmb()	asm volatile("sfence":::"memory")
#endif

#undef ATOMIC_SMP_LOCK

#define IATOMIC_DEFINED		1

#endif /* __i386__ */

#ifdef __ia64__

/*
 * On IA-64, counter must always be volatile to ensure that that the
 * memory accesses are ordered.
 */
typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)		((atomic_t) { (i) })

#define atomic_read(v)		((v)->counter)
#define atomic_set(v,i)		(((v)->counter) = (i))

/* stripped version - we need only 4byte version */
#define ia64_cmpxchg(sem,ptr,old,new,size) \
({ \
	__typeof__(ptr) _p_ = (ptr); \
	__typeof__(new) _n_ = (new); \
	unsigned long _o_, _r_; \
	_o_ = (unsigned int) (long) (old); \
	__asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \
	__asm__ __volatile__ ("cmpxchg4."sem" %0=[%1],%2,ar.ccv" \
			      : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \
	(__typeof__(old)) _r_; \
})

static __inline__ int
ia64_atomic_add (int i, atomic_t *v)
{
	int old, new;
	// CMPXCHG_BUGCHECK_DECL

	do {
		// CMPXCHG_BUGCHECK(v);
		old = atomic_read(v);
		new = old + i;
	} while (ia64_cmpxchg("acq", v, old, old + i, sizeof(atomic_t)) != old);
	return new;
}

static __inline__ int
ia64_atomic_sub (int i, atomic_t *v)
{
	int old, new;
	// CMPXCHG_BUGCHECK_DECL

	do {
		// CMPXCHG_BUGCHECK(v);
		old = atomic_read(v);
		new = old - i;
	} while (ia64_cmpxchg("acq", v, old, new, sizeof(atomic_t)) != old);
	return new;
}

#define IA64_FETCHADD(tmp,v,n,sz)						\
({										\
	switch (sz) {								\
	      case 4:								\
		__asm__ __volatile__ ("fetchadd4.rel %0=[%1],%2"		\
				      : "=r"(tmp) : "r"(v), "i"(n) : "memory");	\
		break;								\
										\
	      case 8:								\
		__asm__ __volatile__ ("fetchadd8.rel %0=[%1],%2"		\
				      : "=r"(tmp) : "r"(v), "i"(n) : "memory");	\
		break;								\
	}									\
})

#define ia64_fetch_and_add(i,v)							\
({										\
	unsigned long _tmp;								\
	volatile __typeof__(*(v)) *_v = (v);					\
	switch (i) {								\
	      case -16:	IA64_FETCHADD(_tmp, _v, -16, sizeof(*(v))); break;	\
	      case  -8:	IA64_FETCHADD(_tmp, _v,  -8, sizeof(*(v))); break;	\
	      case  -4:	IA64_FETCHADD(_tmp, _v,  -4, sizeof(*(v))); break;	\
	      case  -1:	IA64_FETCHADD(_tmp, _v,  -1, sizeof(*(v))); break;	\
	      case   1:	IA64_FETCHADD(_tmp, _v,   1, sizeof(*(v))); break;	\
	      case   4:	IA64_FETCHADD(_tmp, _v,   4, sizeof(*(v))); break;	\
	      case   8:	IA64_FETCHADD(_tmp, _v,   8, sizeof(*(v))); break;	\
	      case  16:	IA64_FETCHADD(_tmp, _v,  16, sizeof(*(v))); break;	\
	}									\
	(__typeof__(*v)) (_tmp + (i));	/* return new value */			\
})

/*
 * Atomically add I to V and return TRUE if the resulting value is
 * negative.
 */
static __inline__ int
atomic_add_negative (int i, atomic_t *v)
{
	return ia64_atomic_add(i, v) < 0;
}

#define atomic_add_return(i,v)						\
	((__builtin_constant_p(i) &&					\
	  (   (i ==  1) || (i ==  4) || (i ==  8) || (i ==  16)		\
	   || (i == -1) || (i == -4) || (i == -8) || (i == -16)))	\
	 ? ia64_fetch_and_add(i, &(v)->counter)				\
	 : ia64_atomic_add(i, v))

#define atomic_sub_return(i,v)						\
	((__builtin_constant_p(i) &&					\
	  (   (i ==  1) || (i ==  4) || (i ==  8) || (i ==  16)		\
	   || (i == -1) || (i == -4) || (i == -8) || (i == -16)))	\
	 ? ia64_fetch_and_add(-(i), &(v)->counter)			\
	 : ia64_atomic_sub(i, v))

#define atomic_dec_return(v)		atomic_sub_return(1, (v))
#define atomic_inc_return(v)		atomic_add_return(1, (v))

#define atomic_sub_and_test(i,v)	(atomic_sub_return((i), (v)) == 0)
#define atomic_dec_and_test(v)		(atomic_sub_return(1, (v)) == 0)
#define atomic_inc_and_test(v)		(atomic_add_return(1, (v)) != 0)

#define atomic_add(i,v)			atomic_add_return((i), (v))
#define atomic_sub(i,v)			atomic_sub_return((i), (v))
#define atomic_inc(v)			atomic_add(1, (v))
#define atomic_dec(v)			atomic_sub(1, (v))

/*
 * Macros to force memory ordering.  In these descriptions, "previous"
 * and "subsequent" refer to program order; "visible" means that all
 * architecturally visible effects of a memory access have occurred
 * (at a minimum, this means the memory has been read or written).
 *
 *   wmb():	Guarantees that all preceding stores to memory-
 *		like regions are visible before any subsequent
 *		stores and that all following stores will be
 *		visible only after all previous stores.
 *   rmb():	Like wmb(), but for reads.
 *   mb():	wmb()/rmb() combo, i.e., all previous memory
 *		accesses are visible before all subsequent
 *		accesses and vice versa.  This is also known as
 *		a "fence."
 *
 * Note: "mb()" and its variants cannot be used as a fence to order
 * accesses to memory mapped I/O registers.  For that, mf.a needs to
 * be used.  However, we don't want to always use mf.a because (a)
 * it's (presumably) much slower than mf and (b) mf.a is supported for
 * sequential memory pages only.
 */
#define mb()	__asm__ __volatile__ ("mf" ::: "memory")
#define rmb()	mb()
#define wmb()	mb()

#define IATOMIC_DEFINED		1

#endif /* __ia64__ */

#ifdef __alpha__

/*
 * Atomic operations that C can't guarantee us.  Useful for
 * resource counting etc...
 *
 * But use these as seldom as possible since they are much slower
 * than regular operations.
 */


/*
 * Counter is volatile to make sure gcc doesn't try to be clever
 * and move things around on us. We need to use _exactly_ the address
 * the user gave us, not some alias that contains the same information.
 */
typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	( (atomic_t) { (i) } )

#define atomic_read(v)		((v)->counter)
#define atomic_set(v,i)		((v)->counter = (i))

/*
 * To get proper branch prediction for the main line, we must branch
 * forward to code at the end of this object's .text section, then
 * branch back to restart the operation.
 */

static __inline__ void atomic_add(int i, atomic_t * v)
{
	unsigned long temp;
	__asm__ __volatile__(
	"1:	ldl_l %0,%1\n"
	"	addl %0,%2,%0\n"
	"	stl_c %0,%1\n"
	"	beq %0,2f\n"
	".subsection 2\n"
	"2:	br 1b\n"
	".previous"
	:"=&r" (temp), "=m" (v->counter)
	:"Ir" (i), "m" (v->counter));
}

static __inline__ void atomic_sub(int i, atomic_t * v)
{
	unsigned long temp;
	__asm__ __volatile__(
	"1:	ldl_l %0,%1\n"
	"	subl %0,%2,%0\n"
	"	stl_c %0,%1\n"
	"	beq %0,2f\n"
	".subsection 2\n"
	"2:	br 1b\n"
	".previous"
	:"=&r" (temp), "=m" (v->counter)
	:"Ir" (i), "m" (v->counter));
}

/*
 * Same as above, but return the result value
 */
static __inline__ long atomic_add_return(int i, atomic_t * v)
{
	long temp, result;
	__asm__ __volatile__(
	"1:	ldl_l %0,%1\n"
	"	addl %0,%3,%2\n"
	"	addl %0,%3,%0\n"
	"	stl_c %0,%1\n"
	"	beq %0,2f\n"
	"	mb\n"
	".subsection 2\n"
	"2:	br 1b\n"
	".previous"
	:"=&r" (temp), "=m" (v->counter), "=&r" (result)
	:"Ir" (i), "m" (v->counter) : "memory");
	return result;
}

static __inline__ long atomic_sub_return(int i, atomic_t * v)
{
	long temp, result;
	__asm__ __volatile__(
	"1:	ldl_l %0,%1\n"
	"	subl %0,%3,%2\n"
	"	subl %0,%3,%0\n"
	"	stl_c %0,%1\n"
	"	beq %0,2f\n"
	"	mb\n"
	".subsection 2\n"
	"2:	br 1b\n"
	".previous"
	:"=&r" (temp), "=m" (v->counter), "=&r" (result)
	:"Ir" (i), "m" (v->counter) : "memory");
	return result;
}

#define atomic_dec_return(v) atomic_sub_return(1,(v))
#define atomic_inc_return(v) atomic_add_return(1,(v))

#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)

#define atomic_inc(v) atomic_add(1,(v))
#define atomic_dec(v) atomic_sub(1,(v))

#define mb() \
__asm__ __volatile__("mb": : :"memory")

#define rmb() \
__asm__ __volatile__("mb": : :"memory")

#define wmb() \
__asm__ __volatile__("wmb": : :"memory")

#define IATOMIC_DEFINED		1

#endif /* __alpha__ */

#ifdef __powerpc__

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

#define atomic_read(v)		((v)->counter)
#define atomic_set(v,i)		(((v)->counter) = (i))

extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
extern void atomic_set_mask(unsigned long mask, unsigned long *addr);

#define SMP_ISYNC	"\n\tisync"

static __inline__ void atomic_add(int a, atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%3		# atomic_add\n\
	add	%0,%2,%0\n\
	stwcx.	%0,0,%3\n\
	bne-	1b"
	: "=&r" (t), "=m" (v->counter)
	: "r" (a), "r" (&v->counter), "m" (v->counter)
	: "cc");
}

static __inline__ int atomic_add_return(int a, atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%2		# atomic_add_return\n\
	add	%0,%1,%0\n\
	stwcx.	%0,0,%2\n\
	bne-	1b"
	SMP_ISYNC
	: "=&r" (t)
	: "r" (a), "r" (&v->counter)
	: "cc", "memory");

	return t;
}

static __inline__ void atomic_sub(int a, atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%3		# atomic_sub\n\
	subf	%0,%2,%0\n\
	stwcx.	%0,0,%3\n\
	bne-	1b"
	: "=&r" (t), "=m" (v->counter)
	: "r" (a), "r" (&v->counter), "m" (v->counter)
	: "cc");
}

static __inline__ int atomic_sub_return(int a, atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%2		# atomic_sub_return\n\
	subf	%0,%1,%0\n\
	stwcx.	%0,0,%2\n\
	bne-	1b"
	SMP_ISYNC
	: "=&r" (t)
	: "r" (a), "r" (&v->counter)
	: "cc", "memory");

	return t;
}

static __inline__ void atomic_inc(atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%2		# atomic_inc\n\
	addic	%0,%0,1\n\
	stwcx.	%0,0,%2\n\
	bne-	1b"
	: "=&r" (t), "=m" (v->counter)
	: "r" (&v->counter), "m" (v->counter)
	: "cc");
}

static __inline__ int atomic_inc_return(atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%1		# atomic_inc_return\n\
	addic	%0,%0,1\n\
	stwcx.	%0,0,%1\n\
	bne-	1b"
	SMP_ISYNC
	: "=&r" (t)
	: "r" (&v->counter)
	: "cc", "memory");

	return t;
}

static __inline__ void atomic_dec(atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%2		# atomic_dec\n\
	addic	%0,%0,-1\n\
	stwcx.	%0,0,%2\n\
	bne-	1b"
	: "=&r" (t), "=m" (v->counter)
	: "r" (&v->counter), "m" (v->counter)
	: "cc");
}

static __inline__ int atomic_dec_return(atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%1		# atomic_dec_return\n\
	addic	%0,%0,-1\n\
	stwcx.	%0,0,%1\n\
	bne-	1b"
	SMP_ISYNC
	: "=&r" (t)
	: "r" (&v->counter)
	: "cc", "memory");

	return t;
}

#define atomic_sub_and_test(a, v)	(atomic_sub_return((a), (v)) == 0)
#define atomic_dec_and_test(v)		(atomic_dec_return((v)) == 0)

/*
 * Atomically test *v and decrement if it is greater than 0.
 * The function returns the old value of *v minus 1.
 */
static __inline__ int atomic_dec_if_positive(atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%1		# atomic_dec_if_positive\n\
	addic.	%0,%0,-1\n\
	blt-	2f\n\
	stwcx.	%0,0,%1\n\
	bne-	1b"
	SMP_ISYNC
	"\n\
2:"	: "=&r" (t)
	: "r" (&v->counter)
	: "cc", "memory");

	return t;
}

/*
 * Memory barrier.
 * The sync instruction guarantees that all memory accesses initiated
 * by this processor have been performed (with respect to all other
 * mechanisms that access memory).  The eieio instruction is a barrier
 * providing an ordering (separately) for (a) cacheable stores and (b)
 * loads and stores to non-cacheable memory (e.g. I/O devices).
 *
 * mb() prevents loads and stores being reordered across this point.
 * rmb() prevents loads being reordered across this point.
 * wmb() prevents stores being reordered across this point.
 *
 * We can use the eieio instruction for wmb, but since it doesn't
 * give any ordering guarantees about loads, we have to use the
 * stronger but slower sync instruction for mb and rmb.
 */
#define mb()  __asm__ __volatile__ ("sync" : : : "memory")
#define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
#define wmb()  __asm__ __volatile__ ("eieio" : : : "memory")

#define IATOMIC_DEFINED		1

#endif /* __powerpc__ */

#ifdef __mips__

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)    { (i) }

/*
 * atomic_read - read atomic variable
 * @v: pointer of type atomic_t
 *
 * Atomically reads the value of @v.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_read(v)	((v)->counter)

/*
 * atomic_set - set atomic variable
 * @v: pointer of type atomic_t
 * @i: required value
 *
 * Atomically sets the value of @v to @i.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_set(v,i)	((v)->counter = (i))

/*
 * for MIPS II and better we can use ll/sc instruction, and kernel 2.4.3+
 * will emulate it on MIPS I.
 */

/*
 * atomic_add - add integer to atomic variable
 * @i: integer value to add
 * @v: pointer of type atomic_t
 *
 * Atomically adds @i to @v.  Note that the guaranteed useful range
 * of an atomic_t is only 24 bits.
 */
extern __inline__ void atomic_add(int i, atomic_t * v)
{
	unsigned long temp;

	__asm__ __volatile__(
		".set push                            \n"
		".set mips2                           \n"
		"1:   ll      %0, %1      # atomic_add\n"
		"     addu    %0, %2                  \n"
		"     sc      %0, %1                  \n"
		"     beqz    %0, 1b                  \n"
		".set pop                             \n"
		: "=&r" (temp), "=m" (v->counter)
		: "Ir" (i), "m" (v->counter));
}

/*
 * atomic_sub - subtract the atomic variable
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 *
 * Atomically subtracts @i from @v.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
extern __inline__ void atomic_sub(int i, atomic_t * v)
{
	unsigned long temp;

	__asm__ __volatile__(
		".set push                            \n"
		".set mips2                           \n"
		"1:   ll      %0, %1      # atomic_sub\n"
		"     subu    %0, %2                  \n"
		"     sc      %0, %1                  \n"
		"     beqz    %0, 1b                  \n"
		".set pop                             \n"
		: "=&r" (temp), "=m" (v->counter)
		: "Ir" (i), "m" (v->counter));
}

/*
 * Same as above, but return the result value
 */
extern __inline__ int atomic_add_return(int i, atomic_t * v)
{
	unsigned long temp, result;

	__asm__ __volatile__(
		".set push               # atomic_add_return\n"
		".set noreorder                             \n"
		".set mips2                                 \n"
		"1:   ll      %1, %2                        \n"
		"     addu    %0, %1, %3                    \n"
		"     sc      %0, %2                        \n"
		"     beqz    %0, 1b                        \n"
		"     addu    %0, %1, %3                    \n"
		".set pop                                   \n"
		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
		: "Ir" (i), "m" (v->counter)
		: "memory");

	return result;
}

extern __inline__ int atomic_sub_return(int i, atomic_t * v)
{
	unsigned long temp, result;

	__asm__ __volatile__(
		".set push                                   \n"
		".set mips2                                  \n"
		".set noreorder           # atomic_sub_return\n"
		"1:   ll    %1, %2                           \n"
		"     subu  %0, %1, %3                       \n"
		"     sc    %0, %2                           \n"
		"     beqz  %0, 1b                           \n"
		"     subu  %0, %1, %3                       \n"
		".set pop                                    \n"
		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
		: "Ir" (i), "m" (v->counter)
		: "memory");

	return result;
}

#define atomic_dec_return(v) atomic_sub_return(1,(v))
#define atomic_inc_return(v) atomic_add_return(1,(v))

/*
 * atomic_sub_and_test - subtract value from variable and test result
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 *
 * Atomically subtracts @i from @v and returns
 * true if the result is zero, or false for all
 * other cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)

/*
 * atomic_inc_and_test - increment and test
 * @v: pointer of type atomic_t
 *
 * Atomically increments @v by 1
 * and returns true if the result is zero, or false for all
 * other cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_inc_and_test(v) (atomic_inc_return(1, (v)) == 0)

/*
 * atomic_dec_and_test - decrement by 1 and test
 * @v: pointer of type atomic_t
 *
 * Atomically decrements @v by 1 and
 * returns true if the result is 0, or false for all other
 * cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)

/*
 * atomic_inc - increment atomic variable
 * @v: pointer of type atomic_t
 *
 * Atomically increments @v by 1.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_inc(v) atomic_add(1,(v))

/*
 * atomic_dec - decrement and test
 * @v: pointer of type atomic_t
 *
 * Atomically decrements @v by 1.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_dec(v) atomic_sub(1,(v))

/*
 * atomic_add_negative - add and test if negative
 * @v: pointer of type atomic_t
 * @i: integer value to add
 *
 * Atomically adds @i to @v and returns true
 * if the result is negative, or false when
 * result is greater than or equal to zero.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 *
 * Currently not implemented for MIPS.
 */

#define mb()						\
__asm__ __volatile__(					\
	"# prevent instructions being moved around\n\t"	\
	".set\tnoreorder\n\t"				\
	"# 8 nops to fool the R4400 pipeline\n\t"	\
	"nop;nop;nop;nop;nop;nop;nop;nop\n\t"		\
	".set\treorder"					\
	: /* no output */				\
	: /* no input */				\
	: "memory")
#define rmb() mb()
#define wmb() mb()

#define IATOMIC_DEFINED		1

#endif /* __mips__ */

#ifdef __arm__

/*
 * FIXME: bellow code is valid only for SA11xx
 */

/*
 * Save the current interrupt enable state & disable IRQs
 */
#define local_irq_save(x)					\
	({							\
		unsigned long temp;				\
	__asm__ __volatile__(					\
	"mrs	%0, cpsr		@ local_irq_save\n"	\
"	orr	%1, %0, #128\n"					\
"	msr	cpsr_c, %1"					\
	: "=r" (x), "=r" (temp)					\
	:							\
	: "memory");						\
	})

/*
 * restore saved IRQ & FIQ state
 */
#define local_irq_restore(x)					\
	__asm__ __volatile__(					\
	"msr	cpsr_c, %0		@ local_irq_restore\n"	\
	:							\
	: "r" (x)						\
	: "memory")

#define __save_flags_cli(x) local_irq_save(x)
#define __restore_flags(x) local_irq_restore(x)

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

#define atomic_read(v)	((v)->counter)
#define atomic_set(v,i)	(((v)->counter) = (i))

static __inline__ void atomic_add(int i, volatile atomic_t *v)
{
	unsigned long flags;

	__save_flags_cli(flags);
	v->counter += i;
	__restore_flags(flags);
}

static __inline__ void atomic_sub(int i, volatile atomic_t *v)
{
	unsigned long flags;

	__save_flags_cli(flags);
	v->counter -= i;
	__restore_flags(flags);
}

static __inline__ void atomic_inc(volatile atomic_t *v)
{
	unsigned long flags;

	__save_flags_cli(flags);
	v->counter += 1;
	__restore_flags(flags);
}

static __inline__ void atomic_dec(volatile atomic_t *v)
{
	unsigned long flags;

	__save_flags_cli(flags);
	v->counter -= 1;
	__restore_flags(flags);
}

static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
{
	unsigned long flags;
	int result;

	__save_flags_cli(flags);
	v->counter -= 1;
	result = (v->counter == 0);
	__restore_flags(flags);

	return result;
}

static inline int atomic_add_negative(int i, volatile atomic_t *v)
{
	unsigned long flags;
	int result;

	__save_flags_cli(flags);
	v->counter += i;
	result = (v->counter < 0);
	__restore_flags(flags);

	return result;
}

static __inline__ void atomic_clear_mask(unsigned long mask, unsigned long *addr)
{
	unsigned long flags;

	__save_flags_cli(flags);
	*addr &= ~mask;
	__restore_flags(flags);
}

#define mb() __asm__ __volatile__ ("" : : : "memory")
#define rmb() mb()
#define wmb() mb()

#define IATOMIC_DEFINED		1

#endif /* __arm__ */

#ifndef IATOMIC_DEFINED
/*
 * non supported architecture.
 */
#warning "Atomic operations are not supported on this architecture."

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

#define atomic_read(v)	((v)->counter)
#define atomic_set(v,i)	(((v)->counter) = (i))
#define atomic_add(i,v) (((v)->counter) += (i))
#define atomic_sub(i,v) (((v)->counter) -= (i))
#define atomic_inc(v)   (((v)->counter)++)
#define atomic_dec(v)   (((v)->counter)--)

#define mb()
#define rmb()
#define wmb()

#define IATOMIC_DEFINED		1

#endif /* IATOMIC_DEFINED */

/*
 *  Atomic read/write
 *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
 */

/* Max number of times we must spin on a spin-lock calling sched_yield().
   After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */

#ifndef MAX_SPIN_COUNT
#define MAX_SPIN_COUNT 50
#endif

/* Duration of sleep (in nanoseconds) when we can't acquire a spin-lock
   after MAX_SPIN_COUNT iterations of sched_yield().
   This MUST BE > 2ms.
   (Otherwise the kernel does busy-waiting for real-time threads,
    giving other threads no chance to run.) */

#ifndef SPIN_SLEEP_DURATION
#define SPIN_SLEEP_DURATION 2000001
#endif

typedef struct {
	unsigned int begin, end;
} snd_atomic_write_t;

typedef struct {
	volatile const snd_atomic_write_t *write;
	unsigned int end;
} snd_atomic_read_t;

void snd_atomic_read_wait(snd_atomic_read_t *t);

static inline void snd_atomic_write_init(snd_atomic_write_t *w)
{
	w->begin = 0;
	w->end = 0;
}

static inline void snd_atomic_write_begin(snd_atomic_write_t *w)
{
	w->begin++;
	wmb();
}

static inline void snd_atomic_write_end(snd_atomic_write_t *w)
{
	wmb();
	w->end++;
}

static inline void snd_atomic_read_init(snd_atomic_read_t *r, snd_atomic_write_t *w)
{
	r->write = w;
}

static inline void snd_atomic_read_begin(snd_atomic_read_t *r)
{
	r->end = r->write->end;
	rmb();
}

static inline int snd_atomic_read_ok(snd_atomic_read_t *r)
{
	rmb();
	return r->end == r->write->begin;
}

#endif /* __ALSA_IATOMIC_H */
/*
 * File:    atomic.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "iatomic.h"

#ifdef ATOMIC_TEST

atomic_t g_count = {0};

static void* thread_inc(void* param)
{
	int i = 0;
	for(i = 0; i < 1000000; i++){
		atomic_inc(&g_count);
	}

	return NULL;
}

static void* thread_dec(void* param)
{
	int i = 0;
	for(i = 0; i < 1000000; i++){
		atomic_dec(&g_count);
	}

	return NULL;
}

int main(int argc, char* argv[])
{
	pthread_t inc_tid = 0;
	pthread_t dec_tid = 0;

	pthread_create(&inc_tid, NULL, thread_inc, NULL);
	pthread_create(&dec_tid, NULL, thread_dec, NULL);

	pthread_join(inc_tid, NULL);
	pthread_join(dec_tid, NULL);

	printf("count=%d\n", g_count.counter);

	return 0;
}
#endif/*ATOMIC_TEST*/
all:
	gcc -g -m32 fifo_ring.c  -DFIFO_RING_TEST -o fifo_ring_test -lpthread
	gcc -g -m32 swmr_dlist.c dlist.c -DSWMR_DLIST_TEST -o swmr_dlist_test -lpthread
	gcc -g -m32 atomic.c -lpthread -DATOMIC_TEST -o atomic_test
clean:
	rm -f *test

第五章 组合的威力

5.1 队列

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

typedef void     (*DataDestroyFunc)(void* ctx, void* data);
typedef int      (*DataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DataVisitFunc)(void* ctx, void* data);
typedef int       (*DataHashFunc)(void* data);

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);

#endif/*TYPEDEF_H*/

/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "typedef.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

DList* dlist_create(DataDestroyFunc data_destroy, void* ctx);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	DListNode* first;
	void* data_destroy_ctx;
	DataDestroyFunc data_destroy;
};


static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL) {
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL) {
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL) {
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		SAFE_FREE(node);
	}

	return;
}

DList* dlist_create(DataDestroyFunc data_destroy, void* ctx)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL) {
		thiz->first  = NULL;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0) {
		iter = iter->next;
		index--;
	}

	if(!fail_return_last) {
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
	Ret ret = RET_OK;
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	do
	{
		if((node = dlist_create_node(thiz, data)) == NULL) {
			ret = RET_OOM;
			break;
		}

		if(thiz->first == NULL) {
			thiz->first = node;
			break;
		}

		cursor = dlist_get_node(thiz, index, 1);
		
		if(index < dlist_length(thiz)) {
			node->next = cursor;
			if(cursor->prev != NULL) {
				cursor->prev->next = node;
			}
			cursor->prev = node;
			if(thiz->first == cursor) {
				thiz->first = node;
			}
		} else {
			cursor->next = node;
			node->prev = cursor;
		}
	}while(0);

	return ret;
}

Ret dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
	Ret ret = RET_OK;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 
	
	cursor = dlist_get_node(thiz, index, 0);

	do
	{
		if(cursor == NULL) {
			ret = RET_INVALID_PARAMS;
			break;
		}

		if(cursor != NULL) {
			if(cursor == thiz->first) {
				thiz->first = cursor->next;
			}

			if(cursor->next != NULL) {
				cursor->next->prev = cursor->prev;
			}

			if(cursor->prev != NULL) {
				cursor->prev->next = cursor->next;
			}

			dlist_destroy_node(thiz, cursor);
		}

	}while(0);

	return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS); 

	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL) {
		*data = cursor->data;
	}

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	
	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL) {
		cursor->data = data;
	}

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

size_t dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL, 0);

	iter = thiz->first;

	while(iter != NULL) {
		length++;
		iter = iter->next;
	}

	return length;
}

Ret dlist_foreach(DList* thiz, DataVisitFunc visit, void* ctx)
{
	Ret ret = RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	iter = thiz->first;

	while(iter != NULL && ret != RET_STOP) {
		ret = visit(ctx, iter->data);

		iter = iter->next;
	}

	return ret;
}

int      dlist_find(DList* thiz, DataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	iter = thiz->first;
	while(iter != NULL) {
		if(cmp(ctx, iter->data) == 0)
		{
			break;
		}
		i++;
		iter = iter->next;
	}

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	iter = thiz->first;
	while(iter != NULL) {
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	
	SAFE_FREE(thiz);

	return;
}

#ifdef DLIST_TEST

#include <assert.h>
#include <pthread.h>

static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_dlist(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DList* dlist = dlist_create(NULL, NULL);

	for(i = 0; i < n; i++) {
		assert(dlist_append(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++) {
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n) {
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++) {
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == RET_OK);

	dlist_destroy(dlist);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_dlist();
	test_invalid_params();

	return;
}

#define NR 1000
static void* producer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < NR; i++) {
		assert(dlist_append(dlist, (void*)i) == RET_OK);
	}
	sleep(1);
	for(i = 0; i < NR; i++) {
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
	}
	for(i = 0; i < NR; i++) {
		assert(dlist_insert(dlist, i, (void*)i) == RET_OK);
	}

	return NULL;
}

static void* consumer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 3 * NR; i++) {
		usleep(20);
		assert(dlist_delete(dlist, 0) == RET_OK);
	}

	return NULL;
}

static void* reader(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < NR; i++) {
		int length = dlist_length(dlist);
		dlist_find(dlist, cmp_int, (void*)i);
	}

	return NULL;
}

static void multi_thread_test(void)
{
	pthread_t consumer_tid = 0;
	pthread_t producer_tid = 0;
	pthread_t reader_tid = 0;
	DList* dlist = dlist_create(NULL, NULL);

	pthread_create(&producer_tid, NULL, producer, dlist);
	pthread_create(&consumer_tid, NULL, consumer, dlist);
	pthread_create(&reader_tid, NULL, reader, dlist);

	pthread_join(consumer_tid, NULL);
	pthread_join(producer_tid, NULL);
	pthread_join(reader_tid, NULL);
	printf("length=%d\n", dlist_length(dlist));
	dlist_destroy(dlist);

	return;
}
int main(int argc, char* argv[])
{
	single_thread_test();
	multi_thread_test();

	return 0;
}
#endif
/*
 * File : test_helper.c
 */

static int cmp_int(void* ctx, void* data)
{
	return (int)ctx - (int)data;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}
/*
 * File:    queue.h
 */

#include <stdio.h>
#include "typedef.h"

#ifndef QUEUE_H
#define QUEUE_H

DECLS_BEGIN

struct _Queue;
typedef struct _Queue Queue;

Queue* queue_create(DataDestroyFunc data_destroy, void* ctx);

Ret      queue_head(Queue* thiz, void** data);
Ret      queue_push(Queue* thiz, void* data);
Ret      queue_pop(Queue* thiz);
size_t   queue_length(Queue* thiz);
Ret      queue_foreach(Queue* thiz, DataVisitFunc visit, void* ctx);

void queue_destroy(Queue* thiz);

DECLS_END

#endif/*QUEUE_H*/

/*
 * File:    queue.h
 */

#include "queue.h"
#include "dlist.h"

struct _Queue
{
	DList* dlist;
};

Queue* queue_create(DataDestroyFunc data_destroy, void* ctx)
{
	Queue* thiz = (Queue*)malloc(sizeof(Queue));

	if(thiz != NULL) {
		if((thiz->dlist = dlist_create(data_destroy, ctx)) == NULL) {
			free(thiz);
			thiz = NULL;
		}
	}

	return thiz;
}

Ret      queue_head(Queue* thiz, void** data)
{
	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS);

	return dlist_get_by_index(thiz->dlist, 0, data);
}

Ret      queue_push(Queue* thiz, void* data)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	return dlist_append(thiz->dlist, data);
}

Ret      queue_pop(Queue* thiz)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	return dlist_delete(thiz->dlist, 0);
}

size_t   queue_length(Queue* thiz)
{
	return_val_if_fail(thiz != NULL, 0);

	return dlist_length(thiz->dlist);	
}

Ret      queue_foreach(Queue* thiz, DataVisitFunc visit, void* ctx)
{
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	return dlist_foreach(thiz->dlist, visit, ctx);
}

void queue_destroy(Queue* thiz)
{
	if(thiz != NULL) {
		dlist_destroy(thiz->dlist);
		thiz->dlist = NULL;

		free(thiz);
	}

	return;
}

#ifdef QUEUE_TEST
#include "test_helper.c"
int main(int argc, char* argv[])
{
	int i = 0;
	int n = 1000;
	int ret_data = 0;
	Queue* queue = queue_create(NULL, NULL);		

	for(i = 0; i < n; i++) {
		assert(queue_push(queue, (void*)i) == RET_OK);
		assert(queue_head(queue, (void**)&ret_data) == RET_OK);
		assert(queue_length(queue) == (i+1));
	}

	queue_foreach(queue, print_int, NULL);

	for(i = 0; i < n; i++) {
		assert(queue_head(queue, (void**)&ret_data) == RET_OK);
		assert(ret_data == i );
		assert(queue_length(queue) == (n - i));
		assert(queue_pop(queue) == RET_OK);
	}

	queue_destroy(queue);
	return 0;
}
#endif/*QUEUE_TEST*/
all:
	gcc -g -m32 -DQUEUE_TEST queue.c dlist.c -o queue_test

clean:
	rm -f *test *.exe *.so

5.2 栈

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

typedef void     (*DataDestroyFunc)(void* ctx, void* data);
typedef int      (*DataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DataVisitFunc)(void* ctx, void* data);
typedef int       (*DataHashFunc)(void* data);

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);

#endif/*TYPEDEF_H*/
/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "typedef.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

DList* dlist_create(DataDestroyFunc data_destroy, void* ctx);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	DListNode* first;
	void* data_destroy_ctx;
	DataDestroyFunc data_destroy;
};


static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL)
	{
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL)
	{
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL)
	{
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		SAFE_FREE(node);
	}

	return;
}

DList* dlist_create(DataDestroyFunc data_destroy, void* ctx)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL)
	{
		thiz->first  = NULL;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0)
	{
		iter = iter->next;
		index--;
	}

	if(!fail_return_last)
	{
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
	Ret ret = RET_OK;
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 


	do
	{
		if((node = dlist_create_node(thiz, data)) == NULL)
		{
			ret = RET_OOM;
			break;
		}

		if(thiz->first == NULL)
		{
			thiz->first = node;
			break;
		}

		cursor = dlist_get_node(thiz, index, 1);
		
		if(index < dlist_length(thiz))
		{
			node->next = cursor;
			if(cursor->prev != NULL)
			{
				cursor->prev->next = node;
			}
			cursor->prev = node;
			if(thiz->first == cursor)
			{
				thiz->first = node;
			}
		}
		else
		{
			cursor->next = node;
			node->prev = cursor;
		}
	}while(0);

	return ret;
}

Ret dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
	Ret ret = RET_OK;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 
	
	cursor = dlist_get_node(thiz, index, 0);

	do
	{
		if(cursor == NULL)
		{
			ret = RET_INVALID_PARAMS;
			break;
		}

		if(cursor != NULL)
		{
			if(cursor == thiz->first)
			{
				thiz->first = cursor->next;
			}

			if(cursor->next != NULL)
			{
				cursor->next->prev = cursor->prev;
			}

			if(cursor->prev != NULL)
			{
				cursor->prev->next = cursor->next;
			}

			dlist_destroy_node(thiz, cursor);
		}

	}while(0);

	return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS); 

	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL)
	{
		*data = cursor->data;
	}

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	
	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL)
	{
		cursor->data = data;
	}

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

size_t dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL, 0);

	iter = thiz->first;

	while(iter != NULL)
	{
		length++;
		iter = iter->next;
	}

	return length;
}

Ret dlist_foreach(DList* thiz, DataVisitFunc visit, void* ctx)
{
	Ret ret = RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	iter = thiz->first;

	while(iter != NULL && ret != RET_STOP)
	{
		ret = visit(ctx, iter->data);

		iter = iter->next;
	}

	return ret;
}

int      dlist_find(DList* thiz, DataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	iter = thiz->first;
	while(iter != NULL)
	{
		if(cmp(ctx, iter->data) == 0)
		{
			break;
		}
		i++;
		iter = iter->next;
	}

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	iter = thiz->first;
	while(iter != NULL)
	{
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	
	SAFE_FREE(thiz);

	return;
}

#ifdef DLIST_TEST

#include <assert.h>
#include <pthread.h>

static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_dlist(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DList* dlist = dlist_create(NULL, NULL);

	for(i = 0; i < n; i++)
	{
		assert(dlist_append(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++)
	{
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n)
		{
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == RET_OK);

	dlist_destroy(dlist);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_dlist();
	test_invalid_params();

	return;
}

#define NR 1000
static void* producer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < NR; i++)
	{
		assert(dlist_append(dlist, (void*)i) == RET_OK);
	}
	sleep(1);
	for(i = 0; i < NR; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
	}
	for(i = 0; i < NR; i++)
	{
		assert(dlist_insert(dlist, i, (void*)i) == RET_OK);
	}

	return NULL;
}

static void* consumer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 3 * NR; i++)
	{
		usleep(20);
		assert(dlist_delete(dlist, 0) == RET_OK);
	}

	return NULL;
}

static void* reader(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < NR; i++)
	{
		int length = dlist_length(dlist);
		dlist_find(dlist, cmp_int, (void*)i);
	}

	return NULL;
}

static void multi_thread_test(void)
{
	pthread_t consumer_tid = 0;
	pthread_t producer_tid = 0;
	pthread_t reader_tid = 0;
	DList* dlist = dlist_create(NULL, NULL);

	pthread_create(&producer_tid, NULL, producer, dlist);
	pthread_create(&consumer_tid, NULL, consumer, dlist);
	pthread_create(&reader_tid, NULL, reader, dlist);

	pthread_join(consumer_tid, NULL);
	pthread_join(producer_tid, NULL);
	pthread_join(reader_tid, NULL);
	printf("length=%d\n", dlist_length(dlist));
	dlist_destroy(dlist);

	return;
}
int main(int argc, char* argv[])
{
	single_thread_test();
	multi_thread_test();

	return 0;
}
#endif

/*
 * File : test_helper.c
 */

static int cmp_int(void* ctx, void* data)
{
	return (int)ctx - (int)data;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}
/*
 * File:    stack.c
 */

#include <stdio.h>
#include "typedef.h"

#ifndef STACK_H
#define STACK_H

DECLS_BEGIN

struct _Stack;
typedef struct _Stack Stack;

Stack* stack_create(DataDestroyFunc data_destroy, void* ctx);

Ret      stack_top(Stack* thiz, void** data);
Ret      stack_push(Stack* thiz, void* data);
Ret      stack_pop(Stack* thiz);
size_t   stack_length(Stack* thiz);
Ret      stack_foreach(Stack* thiz, DataVisitFunc visit, void* ctx);

void stack_destroy(Stack* thiz);

DECLS_END

#endif/*STACK_H*/

/*
 * File:    stack.h
 */

#include "stack.h"
#include "dlist.h"

struct _Stack
{
	DList* dlist;
};

Stack* stack_create(DataDestroyFunc data_destroy, void* ctx)
{
	Stack* thiz = (Stack*)malloc(sizeof(Stack));

	if(thiz != NULL)
	{
		if((thiz->dlist = dlist_create(data_destroy, ctx)) == NULL)
		{
			free(thiz);
			thiz = NULL;
		}
	}

	return thiz;
}

Ret      stack_top(Stack* thiz, void** data)
{
	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS);

	return dlist_get_by_index(thiz->dlist, 0, data);
}

Ret      stack_push(Stack* thiz, void* data)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	return dlist_prepend(thiz->dlist, data);
}

Ret      stack_pop(Stack* thiz)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	return dlist_delete(thiz->dlist, 0);
}

size_t   stack_length(Stack* thiz)
{
	return_val_if_fail(thiz != NULL, 0);

	return dlist_length(thiz->dlist);	
}

Ret      stack_foreach(Stack* thiz, DataVisitFunc visit, void* ctx)
{
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	return dlist_foreach(thiz->dlist, visit, ctx);
}

void stack_destroy(Stack* thiz)
{
	if(thiz != NULL)
	{
		dlist_destroy(thiz->dlist);
		thiz->dlist = NULL;

		free(thiz);
	}

	return;
}

#ifdef STACK_TEST

#include "test_helper.c"
int main(int argc, char* argv[])
{
	int i = 0;
	int n = 1000;
	int ret_data = 0;
	Stack* stack = stack_create(NULL, NULL);		

	for(i = 0; i < n; i++)
	{
		assert(stack_push(stack, (void*)i) == RET_OK);
		assert(stack_top(stack, (void**)&ret_data) == RET_OK);
		assert(stack_length(stack) == (i+1));
	}

	stack_foreach(stack, print_int, NULL);

	for(i = 0; i < n; i++)
	{
		assert(stack_top(stack, (void**)&ret_data) == RET_OK);
		assert(ret_data == (n - i - 1));
		assert(stack_length(stack) == (n - i));
		assert(stack_pop(stack) == RET_OK);
	}

	stack_destroy(stack);

	return 0;
}
#endif/*STACK_TEST*/


/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	DListNode* first;
	void* data_destroy_ctx;
	DataDestroyFunc data_destroy;
};


static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL) {
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL) {
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL) {
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		SAFE_FREE(node);
	}

	return;
}

DList* dlist_create(DataDestroyFunc data_destroy, void* ctx)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL) {
		thiz->first  = NULL;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0) {
		iter = iter->next;
		index--;
	}

	if(!fail_return_last) {
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
	Ret ret = RET_OK;
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	do
	{
		if((node = dlist_create_node(thiz, data)) == NULL) {
			ret = RET_OOM;
			break;
		}

		if(thiz->first == NULL) {
			thiz->first = node;
			break;
		}

		cursor = dlist_get_node(thiz, index, 1);
		
		if(index < dlist_length(thiz)) {
			node->next = cursor;
			if(cursor->prev != NULL) {
				cursor->prev->next = node;
			}
			cursor->prev = node;
			if(thiz->first == cursor) {
				thiz->first = node;
			}
		} else {
			cursor->next = node;
			node->prev = cursor;
		}
	}while(0);

	return ret;
}

Ret dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
	Ret ret = RET_OK;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 
	
	cursor = dlist_get_node(thiz, index, 0);

	do
	{
		if(cursor == NULL) {
			ret = RET_INVALID_PARAMS;
			break;
		}

		if(cursor != NULL) {
			if(cursor == thiz->first) {
				thiz->first = cursor->next;
			}

			if(cursor->next != NULL) {
				cursor->next->prev = cursor->prev;
			}

			if(cursor->prev != NULL) {
				cursor->prev->next = cursor->next;
			}

			dlist_destroy_node(thiz, cursor);
		}

	}while(0);

	return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS); 

	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL) {
		*data = cursor->data;
	}

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	
	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL) {
		cursor->data = data;
	}

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

size_t dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL, 0);

	iter = thiz->first;

	while(iter != NULL) {
		length++;
		iter = iter->next;
	}

	return length;
}

Ret dlist_foreach(DList* thiz, DataVisitFunc visit, void* ctx)
{
	Ret ret = RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	iter = thiz->first;

	while(iter != NULL && ret != RET_STOP) {
		ret = visit(ctx, iter->data);

		iter = iter->next;
	}

	return ret;
}

int      dlist_find(DList* thiz, DataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	iter = thiz->first;
	while(iter != NULL) {
		if(cmp(ctx, iter->data) == 0)
		{
			break;
		}
		i++;
		iter = iter->next;
	}

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	iter = thiz->first;
	while(iter != NULL) {
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	
	SAFE_FREE(thiz);

	return;
}

#ifdef DLIST_TEST

#include <assert.h>
#include <pthread.h>

static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_dlist(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DList* dlist = dlist_create(NULL, NULL);

	for(i = 0; i < n; i++) {
		assert(dlist_append(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++) {
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n) {
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++) {
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == RET_OK);

	dlist_destroy(dlist);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_dlist();
	test_invalid_params();

	return;
}

#define NR 1000
static void* producer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < NR; i++) {
		assert(dlist_append(dlist, (void*)i) == RET_OK);
	}
	sleep(1);
	for(i = 0; i < NR; i++) {
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
	}
	for(i = 0; i < NR; i++) {
		assert(dlist_insert(dlist, i, (void*)i) == RET_OK);
	}

	return NULL;
}

static void* consumer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 3 * NR; i++) {
		usleep(20);
		assert(dlist_delete(dlist, 0) == RET_OK);
	}

	return NULL;
}

static void* reader(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < NR; i++) {
		int length = dlist_length(dlist);
		dlist_find(dlist, cmp_int, (void*)i);
	}

	return NULL;
}

static void multi_thread_test(void)
{
	pthread_t consumer_tid = 0;
	pthread_t producer_tid = 0;
	pthread_t reader_tid = 0;
	DList* dlist = dlist_create(NULL, NULL);

	pthread_create(&producer_tid, NULL, producer, dlist);
	pthread_create(&consumer_tid, NULL, consumer, dlist);
	pthread_create(&reader_tid, NULL, reader, dlist);

	pthread_join(consumer_tid, NULL);
	pthread_join(producer_tid, NULL);
	pthread_join(reader_tid, NULL);
	printf("length=%d\n", dlist_length(dlist));
	dlist_destroy(dlist);

	return;
}
int main(int argc, char* argv[])
{
	single_thread_test();
	multi_thread_test();

	return 0;
}
#endif
all:
	gcc -g -DSTACK_TEST stack.c dlist.c -o stack_test

clean:
	rm -f *test *.exe *.so

5.3 离散表

CFILES=dlist.c  
all:
	gcc -g -shared -lpthread $(CFILES) -o libdlist.so
	gcc -g -DDLIST_TEST -lpthread $(CFILES)  -o dlist_test
	gcc -g -DHASH_TABLE_TEST hash_table.c dlist.c -o hash_table_test

clean:
	rm -f *test *.exe *.so

第六章 算法和容器

6.1 容器

1) typedef.h

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

typedef void     (*DataDestroyFunc)(void* ctx, void* data);
typedef int      (*DataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DataVisitFunc)(void* ctx, void* data);
typedef int       (*DataHashFunc)(void* data);

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);

#endif/*TYPEDEF_H*/

2) darray

/*
 * File:    darray.h
 */

#include <stdio.h>
#include "typedef.h"

#ifndef DARRAY_H
#define DARRAY_H

DECLS_BEGIN

struct _DArray;
typedef struct _DArray DArray;

DArray* darray_create(DataDestroyFunc data_destroy, void* ctx);

Ret    darray_insert(DArray* thiz, size_t index, void* data);
Ret    darray_prepend(DArray* thiz, void* data);
Ret    darray_append(DArray* thiz, void* data);
Ret    darray_delete(DArray* thiz, size_t index);
Ret    darray_get_by_index(DArray* thiz, size_t index, void** data);
Ret    darray_set_by_index(DArray* thiz, size_t index, void* data);
size_t darray_length(DArray* thiz);
int    darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx);
Ret    darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx);
Ret    darray_sort(DArray* thiz, SortFunc sort, DataCompareFunc cmp);

void darray_destroy(DArray* thiz);

DECLS_END

#endif/*DARRAY_H*/

/*
 * File:    darray.c
 */

#include <stdlib.h>
#include "darray.h"

struct _DArray
{
	void** data;
	size_t size;
	size_t alloc_size;

	void* data_destroy_ctx;
	DataDestroyFunc data_destroy;
};

static void darray_destroy_data(DArray* thiz, void* data)
{
	if(thiz->data_destroy != NULL) {
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

DArray* darray_create(DataDestroyFunc data_destroy, void* ctx)
{
	DArray* thiz = malloc(sizeof(DArray));

	if(thiz != NULL) {
		thiz->data  = NULL;
		thiz->size  = 0;
		thiz->alloc_size = 0;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

#define MIN_PRE_ALLOCATE_NR 10
static Ret darray_expand(DArray* thiz, size_t need)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	if((thiz->size + need) > thiz->alloc_size) {
		size_t alloc_size = thiz->alloc_size + (thiz->alloc_size>>1) + MIN_PRE_ALLOCATE_NR;

		void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);
		if(data != NULL) {
			thiz->data = data;
			thiz->alloc_size = alloc_size;
		}
	}

	return ((thiz->size + need) <= thiz->alloc_size) ? RET_OK : RET_FAIL;
}

static Ret darray_shrink(DArray* thiz)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	if((thiz->size < (thiz->alloc_size >> 1)) && (thiz->alloc_size > MIN_PRE_ALLOCATE_NR)) {
		size_t alloc_size = thiz->size + (thiz->size >> 1);

		void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);
		if(data != NULL) {
			thiz->data = data;
			thiz->alloc_size = alloc_size;
		}
	}

	return RET_OK;
}

Ret darray_insert(DArray* thiz, size_t index, void* data)
{
	Ret ret = RET_OOM;
	size_t cursor = index;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	cursor = cursor < thiz->size ? cursor : thiz->size;

	if(darray_expand(thiz, 1) == RET_OK) {
		size_t i = 0;
		for(i = thiz->size; i > cursor; i--) {
			thiz->data[i] = thiz->data[i-1];
		}

		thiz->data[cursor] = data;
		thiz->size++;
		
		ret = RET_OK;
	}

	return ret;
}

Ret darray_prepend(DArray* thiz, void* data)
{
	return darray_insert(thiz, 0, data);
}

Ret darray_append(DArray* thiz, void* data)
{
	return darray_insert(thiz, -1, data);
}

Ret darray_delete(DArray* thiz, size_t index)
{
	size_t i = 0;

	return_val_if_fail(thiz != NULL && thiz->size > index, RET_INVALID_PARAMS); 

	darray_destroy_data(thiz, thiz->data[index]);
	for(i = index; (i+1) < thiz->size; i++) {
		thiz->data[i] = thiz->data[i+1];
	}
	thiz->size--;

	darray_shrink(thiz);

	return RET_OK;
}

Ret darray_get_by_index(DArray* thiz, size_t index, void** data)
{

	return_val_if_fail(thiz != NULL && data != NULL && index < thiz->size, 
		RET_INVALID_PARAMS); 

	*data = thiz->data[index];

	return RET_OK;
}

Ret darray_set_by_index(DArray* thiz, size_t index, void* data)
{
	return_val_if_fail(thiz != NULL && index < thiz->size, 
		RET_INVALID_PARAMS); 

	thiz->data[index] = data;

	return RET_OK;
}

size_t   darray_length(DArray* thiz)
{
	return_val_if_fail(thiz != NULL, 0);

	return thiz->size;
}

Ret darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx)
{
	size_t i = 0;	
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	for(i = 0; i < thiz->size; i++) {
		ret = visit(ctx, thiz->data[i]);
	}

	return ret;
}

int      darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx)
{
	size_t i = 0;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	for(i = 0; i < thiz->size; i++) {
		if(cmp(ctx, thiz->data[i]) == 0) {
			break;
		}
	}

	return i;
}

void darray_destroy(DArray* thiz)
{
	size_t i = 0;
	
	if(thiz != NULL) {
		for(i = 0; i < thiz->size; i++) {
			darray_destroy_data(thiz, thiz->data[i]);
		}
		
		SAFE_FREE(thiz->data);
		SAFE_FREE(thiz);
	}

	return;
}

Ret    darray_sort(DArray* thiz, SortFunc sort, DataCompareFunc cmp)
{
	return_val_if_fail(thiz != NULL && sort != NULL && cmp != NULL, RET_INVALID_PARAMS);

	return sort(thiz->data, thiz->size, cmp);
}

#ifdef DARRAY_TEST

#include <assert.h>
#include "test_helper.c"

static void test_int_darray(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DArray* darray = darray_create(NULL, NULL);

	for(i = 0; i < n; i++) {
		assert(darray_append(darray, (void*)i) == RET_OK);
		assert(darray_length(darray) == (i + 1));
		assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(darray_set_by_index(darray, i, (void*)(2*i)) == RET_OK);
		assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(darray_set_by_index(darray, i, (void*)i) == RET_OK);
		assert(darray_find(darray, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++) {
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(darray_length(darray) == (n-i));
		assert(darray_delete(darray, 0) == RET_OK);
		assert(darray_length(darray) == (n-i-1));
		if((i + 1) < n) {
			assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(darray_length(darray) == 0);

	for(i = 0; i < n; i++) {
		assert(darray_prepend(darray, (void*)i) == RET_OK);
		assert(darray_length(darray) == (i + 1));
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(darray_set_by_index(darray, 0, (void*)(2*i)) == RET_OK);
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(darray_set_by_index(darray, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(darray_foreach(darray, check_and_dec_int, &i) == RET_OK);

	darray_destroy(darray);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(darray_length(NULL) == 0);
	assert(darray_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(darray_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(darray_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(darray_find(NULL, NULL, NULL) < 0);
	assert(darray_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_darray();
	test_invalid_params();

	return;
}

int main(int argc, char* argv[])
{
	single_thread_test();

	return 0;
}
#endif
gcc -Wall -Wno-unused-function -g -m32 -DDARRAY_TEST darray.c -o darray_test

3) dlist

/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "typedef.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

DList* dlist_create(DataDestroyFunc data_destroy, void* ctx);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	DListNode* first;
	void* data_destroy_ctx;
	DataDestroyFunc data_destroy;
};

static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL) {
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL) {
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL) {
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		SAFE_FREE(node);
	}

	return;
}

DList* dlist_create(DataDestroyFunc data_destroy, void* ctx)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL) {
		thiz->first  = NULL;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0) {
		iter = iter->next;
		index--;
	}

	if(!fail_return_last) {
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
	Ret ret = RET_OK;
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 


	do
	{
		if((node = dlist_create_node(thiz, data)) == NULL) {
			ret = RET_OOM;
			break;
		}

		if(thiz->first == NULL) {
			thiz->first = node;
			break;
		}

		cursor = dlist_get_node(thiz, index, 1);
		
		if(index < dlist_length(thiz)) {
			node->next = cursor;
			if(cursor->prev != NULL) {
				cursor->prev->next = node;
			}
			cursor->prev = node;
			if(thiz->first == cursor) {
				thiz->first = node;
			}
		} else {
			cursor->next = node;
			node->prev = cursor;
		}
	}while(0);

	return ret;
}

Ret dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
	Ret ret = RET_OK;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 
	
	cursor = dlist_get_node(thiz, index, 0);

	do
	{
		if(cursor == NULL) {
			ret = RET_INVALID_PARAMS;
			break;
		}

		if(cursor != NULL) {
			if(cursor == thiz->first) {
				thiz->first = cursor->next;
			}

			if(cursor->next != NULL) {
				cursor->next->prev = cursor->prev;
			}

			if(cursor->prev != NULL) {
				cursor->prev->next = cursor->next;
			}

			dlist_destroy_node(thiz, cursor);
		}

	}while(0);

	return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS); 

	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL) {
		*data = cursor->data;
	}

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	
	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL) {
		cursor->data = data;
	}

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

size_t dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL, 0);

	iter = thiz->first;

	while(iter != NULL) {
		length++;
		iter = iter->next;
	}

	return length;
}

Ret dlist_foreach(DList* thiz, DataVisitFunc visit, void* ctx)
{
	Ret ret = RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	iter = thiz->first;

	while(iter != NULL && ret != RET_STOP) {
		ret = visit(ctx, iter->data);

		iter = iter->next;
	}

	return ret;
}

int      dlist_find(DList* thiz, DataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	iter = thiz->first;
	while(iter != NULL) {
		if(cmp(ctx, iter->data) == 0) {
			break;
		}
		i++;
		iter = iter->next;
	}

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	iter = thiz->first;
	while(iter != NULL) {
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	
	SAFE_FREE(thiz);

	return;
}

#ifdef DLIST_TEST

#include <unistd.h>
#include <assert.h>
#include <pthread.h>
#include "test_helper.c"

static void test_int_dlist(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DList* dlist = dlist_create(NULL, NULL);

	for(i = 0; i < n; i++) {
		assert(dlist_append(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++) {
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n)
		{
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++) {
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == RET_OK);

	dlist_destroy(dlist);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_dlist();
	test_invalid_params();

	return;
}

#define NR 1000
int main(int argc, char* argv[])
{
	single_thread_test();

	return 0;
}
#endif
gcc -Wall -Wno-unused-function -g -m32 -DDLIST_TEST dlist.c -o dlist_test

4) linear_container_dlist

/*
 * File:    linear_container.h
 */

#ifndef LINEAR_CONTAINER_H
#define LINEAR_CONTAINER_H

#include "typedef.h"

DECLS_BEGIN

struct _LinearContainer;
typedef struct _LinearContainer LinearContainer;

typedef Ret (*LinearContainerInsert)(LinearContainer* thiz, size_t index, void* data);
typedef Ret (*LinearContainerPrepend)(LinearContainer* thiz, void* data);
typedef Ret (*LinearContainerAppend)(LinearContainer* thiz, void* data);
typedef Ret (*LinearContainerDelete)(LinearContainer* thiz, size_t index);
typedef Ret (*LinearContainerGetByIndex)(LinearContainer* thiz, size_t index, void** data);
typedef Ret (*LinearContainerSetByIndex)(LinearContainer* thiz, size_t index, void* data);
typedef size_t (*LinearContainerLength)(LinearContainer* thiz);
typedef int    (*LinearContainerFind)(LinearContainer* thiz, DataCompareFunc cmp, void* ctx);
typedef Ret    (*LinearContainerForeach)(LinearContainer* thiz, DataVisitFunc visit, void* ctx);
typedef void   (*LinearContainerDestroy)(LinearContainer* thiz);

struct _LinearContainer
{
	LinearContainerInsert     insert;
	LinearContainerPrepend    prepend;
	LinearContainerAppend     append;
	LinearContainerDelete     del;
	LinearContainerGetByIndex get_by_index;
	LinearContainerSetByIndex set_by_index;
	LinearContainerLength     length;
	LinearContainerFind       find;
	LinearContainerForeach    foreach;
	LinearContainerDestroy    destroy;

	char priv[0];
};

static inline Ret linear_container_insert(LinearContainer* thiz, size_t index, void* data)
{
	return_val_if_fail(thiz != NULL && thiz->insert != NULL, RET_INVALID_PARAMS);

	return thiz->insert(thiz, index, data);
}

static inline Ret linear_container_prepend(LinearContainer* thiz, void* data)
{
	return_val_if_fail(thiz != NULL && thiz->prepend != NULL, RET_INVALID_PARAMS);

	return thiz->prepend(thiz, data);
}

static inline Ret linear_container_append(LinearContainer* thiz, void* data)
{
	return_val_if_fail(thiz != NULL && thiz->append != NULL, RET_INVALID_PARAMS);

	return thiz->append(thiz, data);
}

static inline Ret linear_container_delete(LinearContainer* thiz, size_t index)
{
	return_val_if_fail(thiz != NULL && thiz->del != NULL, RET_INVALID_PARAMS);

	return thiz->del(thiz, index);
}

static inline Ret linear_container_get_by_index(LinearContainer* thiz, size_t index, void** data)
{
	return_val_if_fail(thiz != NULL && thiz->get_by_index != NULL, RET_INVALID_PARAMS);

	return thiz->get_by_index(thiz, index, data);
}

static inline Ret linear_container_set_by_index(LinearContainer* thiz, size_t index, void* data)
{
	return_val_if_fail(thiz != NULL && thiz->set_by_index != NULL, RET_INVALID_PARAMS);

	return thiz->set_by_index(thiz, index, data);
}

static inline size_t linear_container_length(LinearContainer* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->length != NULL, 0);

	return thiz->length(thiz);
}

static inline int    linear_container_find(LinearContainer* thiz, DataCompareFunc cmp, void* ctx)
{
	return_val_if_fail(thiz != NULL && thiz->find != NULL, -1);

	return thiz->find(thiz, cmp, ctx);
}

static inline Ret    linear_container_foreach(LinearContainer* thiz, DataVisitFunc visit, void* ctx)
{
	return_val_if_fail(thiz != NULL && thiz->foreach != NULL, RET_INVALID_PARAMS);

	return thiz->foreach(thiz, visit, ctx);
}

static inline void   linear_container_destroy(LinearContainer* thiz)
{
	return_if_fail(thiz!= NULL && thiz->destroy != NULL);

	return thiz->destroy(thiz);
}

DECLS_END

#endif/*LINEAR_CONTAINER_H*/

/*
 * File:    linear_container_dlist.h
 */

#ifndef LINEAR_CONTAINER_DLIST_H
#define LINEAR_CONTAINER_DLIST_H

#include "linear_container.h"

DECLS_BEGIN

LinearContainer* linear_container_dlist_create(DataDestroyFunc data_destroy, void* ctx);

DECLS_END

#endif/*LINEAR_CONTAINER_DLIST_H*/

/*
 * File:    linear_container_dlist.c
 */

#include "dlist.h"
#include "linear_container.h"

typedef struct _PrivInfo
{
	DList* dlist;
}PrivInfo;

static Ret linear_container_dlist_insert(LinearContainer* thiz, size_t index, void* data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return dlist_insert(priv->dlist, index, data);
}

static Ret linear_container_dlist_prepend(LinearContainer* thiz, void* data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return dlist_prepend(priv->dlist, data);
}

static Ret linear_container_dlist_append(LinearContainer* thiz, void* data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return dlist_append(priv->dlist, data);
}

static Ret linear_container_dlist_delete(LinearContainer* thiz, size_t index)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return dlist_delete(priv->dlist, index);
}

static Ret linear_container_dlist_get_by_index(LinearContainer* thiz, size_t index, void** data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return dlist_get_by_index(priv->dlist, index, data);
}

static Ret linear_container_dlist_set_by_index(LinearContainer* thiz, size_t index, void* data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return dlist_set_by_index(priv->dlist, index, data);
}

static size_t linear_container_dlist_length(LinearContainer* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return dlist_length(priv->dlist);
}

static int    linear_container_dlist_find(LinearContainer* thiz, DataCompareFunc cmp, void* ctx)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return dlist_find(priv->dlist, cmp, ctx);
}

static Ret    linear_container_dlist_foreach(LinearContainer* thiz, DataVisitFunc visit, void* ctx)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return dlist_foreach(priv->dlist, visit, ctx);
}

static void   linear_container_dlist_destroy(LinearContainer* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	dlist_destroy(priv->dlist);
	free(thiz);

	return;
}

LinearContainer* linear_container_dlist_create(DataDestroyFunc data_destroy, void* ctx)
{
	LinearContainer* thiz = (LinearContainer*)malloc(sizeof(LinearContainer) + sizeof(PrivInfo));

	if(thiz != NULL) {
		PrivInfo* priv = (PrivInfo*)thiz->priv;
		priv->dlist = dlist_create(data_destroy, ctx);

		thiz->insert        =  linear_container_dlist_insert;
		thiz->prepend       =  linear_container_dlist_prepend;
		thiz->append        =  linear_container_dlist_append;
		thiz->del           =  linear_container_dlist_delete;
		thiz->get_by_index  =  linear_container_dlist_get_by_index;
		thiz->set_by_index  =  linear_container_dlist_set_by_index;
		thiz->length        =  linear_container_dlist_length;
		thiz->find          =  linear_container_dlist_find;
		thiz->foreach       =  linear_container_dlist_foreach;
		thiz->destroy       =  linear_container_dlist_destroy;

		if(priv->dlist == NULL) {
			free(thiz);
			thiz = NULL;
		}
	}
	
	return thiz;
}


5) queue

/*
 * File:    queue.h
 */

#include <stdio.h>
#include "typedef.h"
#include "linear_container.h"

#ifndef QUEUE_H
#define QUEUE_H

DECLS_BEGIN

struct _Queue;
typedef struct _Queue Queue;

Queue* queue_create(LinearContainer* container);

Ret      queue_head(Queue* thiz, void** data);
Ret      queue_push(Queue* thiz, void* data);
Ret      queue_pop(Queue* thiz);
size_t   queue_length(Queue* thiz);
Ret      queue_foreach(Queue* thiz, DataVisitFunc visit, void* ctx);

void queue_destroy(Queue* thiz);

DECLS_END

#endif/*QUEUE_H*/

/*
 * File:    queue.c
 */

#include "queue.h"
#include "linear_container.h"

struct _Queue
{
	LinearContainer* linear_container;
};

Queue* queue_create(LinearContainer* container)
{
	Queue* thiz = NULL;
	
	return_val_if_fail(container != NULL, NULL);

	thiz = (Queue*)malloc(sizeof(Queue));

	if(thiz != NULL) {
		thiz->linear_container = container;
	}

	return thiz;
}

Ret      queue_head(Queue* thiz, void** data)
{
	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS);

	return linear_container_get_by_index(thiz->linear_container, 0, data);
}

Ret      queue_push(Queue* thiz, void* data)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	return linear_container_append(thiz->linear_container, data);
}

Ret      queue_pop(Queue* thiz)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	return linear_container_delete(thiz->linear_container, 0);
}

size_t   queue_length(Queue* thiz)
{
	return_val_if_fail(thiz != NULL, 0);

	return linear_container_length(thiz->linear_container);	
}

Ret      queue_foreach(Queue* thiz, DataVisitFunc visit, void* ctx)
{
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	return linear_container_foreach(thiz->linear_container, visit, ctx);
}

void queue_destroy(Queue* thiz)
{
	if(thiz != NULL) {
		linear_container_destroy(thiz->linear_container);
		thiz->linear_container = NULL;

		free(thiz);
	}

	return;
}

#ifdef QUEUE_TEST
#include "test_helper.c"
#include "linear_container_dlist.h"
int main(int argc, char* argv[])
{
	int i = 0;
	int n = 1000;
	int ret_data = 0;
	Queue* queue = queue_create(linear_container_dlist_create(NULL, NULL));		

	for(i = 0; i < n; i++) {
		assert(queue_push(queue, (void*)i) == RET_OK);
		assert(queue_head(queue, (void**)&ret_data) == RET_OK);
		assert(queue_length(queue) == (i+1));
	}

	queue_foreach(queue, print_int, NULL);

	for(i = 0; i < n; i++) {
		assert(queue_head(queue, (void**)&ret_data) == RET_OK);
		assert(ret_data == i );
		assert(queue_length(queue) == (n - i));
		assert(queue_pop(queue) == RET_OK);
	}

	queue_destroy(queue);
	return 0;
}
#endif/*QUEUE_TEST*/
gcc -Wall -Wno-unused-function -g -m32 -DQUEUE_TEST dlist.c linear_container_dlist.c  queue.c -o queue_test

6) linear_container_darray

/*
 * File:    linear_container_darray.h
 */

#ifndef LINEAR_CONTAINER_DARRAY_H
#define LINEAR_CONTAINER_DARRAY_H

#include "linear_container.h"

DECLS_BEGIN

LinearContainer* linear_container_darray_create(DataDestroyFunc data_destroy, void* ctx);

DECLS_END

#endif/*LINEAR_CONTAINER_DARRAY_H*/

/*
 * File:    linear_container_darray.c
 */

#include "darray.h"
#include "linear_container.h"

typedef struct _PrivInfo
{
	DArray* darray;
}PrivInfo;

static Ret linear_container_darray_insert(LinearContainer* thiz, size_t index, void* data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return darray_insert(priv->darray, index, data);
}

static Ret linear_container_darray_prepend(LinearContainer* thiz, void* data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return darray_prepend(priv->darray, data);
}

static Ret linear_container_darray_append(LinearContainer* thiz, void* data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return darray_append(priv->darray, data);
}

static Ret linear_container_darray_delete(LinearContainer* thiz, size_t index)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return darray_delete(priv->darray, index);
}

static Ret linear_container_darray_get_by_index(LinearContainer* thiz, size_t index, void** data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return darray_get_by_index(priv->darray, index, data);
}

static Ret linear_container_darray_set_by_index(LinearContainer* thiz, size_t index, void* data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return darray_set_by_index(priv->darray, index, data);
}

static size_t linear_container_darray_length(LinearContainer* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return darray_length(priv->darray);
}

static int    linear_container_darray_find(LinearContainer* thiz, DataCompareFunc cmp, void* ctx)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return darray_find(priv->darray, cmp, ctx);
}

static Ret    linear_container_darray_foreach(LinearContainer* thiz, DataVisitFunc visit, void* ctx)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return darray_foreach(priv->darray, visit, ctx);
}

static void   linear_container_darray_destroy(LinearContainer* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	darray_destroy(priv->darray);
	free(thiz);

	return;
}

LinearContainer* linear_container_darray_create(DataDestroyFunc data_destroy, void* ctx)
{
	LinearContainer* thiz = (LinearContainer*)malloc(sizeof(LinearContainer) + sizeof(PrivInfo));

	if(thiz != NULL)
	{
		PrivInfo* priv = (PrivInfo*)thiz->priv;
		priv->darray = darray_create(data_destroy, ctx);

		thiz->insert        =  linear_container_darray_insert;
		thiz->prepend       =  linear_container_darray_prepend;
		thiz->append        =  linear_container_darray_append;
		thiz->del           =  linear_container_darray_delete;
		thiz->get_by_index  =  linear_container_darray_get_by_index;
		thiz->set_by_index  =  linear_container_darray_set_by_index;
		thiz->length        =  linear_container_darray_length;
		thiz->find          =  linear_container_darray_find;
		thiz->foreach       =  linear_container_darray_foreach;
		thiz->destroy       =  linear_container_darray_destroy;
	}
	
	return thiz;
}

/*
 * linear_container_test.c
 */

#include <assert.h>
#include "linear_container.h"
#include "test_helper.c"
#include "linear_container_dlist.h"
#include "linear_container_darray.h"

static void test_int_linear_container(LinearContainer* linear_container)
{
	int i = 0;
	int n = 100;
	int data = 0;

	for(i = 0; i < n; i++)
	{
		assert(linear_container_append(linear_container, (void*)i) == RET_OK);
		assert(linear_container_length(linear_container) == (i + 1));
		assert(linear_container_get_by_index(linear_container, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(linear_container_set_by_index(linear_container, i, (void*)(2*i)) == RET_OK);
		assert(linear_container_get_by_index(linear_container, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(linear_container_set_by_index(linear_container, i, (void*)i) == RET_OK);
		assert(linear_container_find(linear_container, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++)
	{
		assert(linear_container_get_by_index(linear_container, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(linear_container_length(linear_container) == (n-i));
		assert(linear_container_delete(linear_container, 0) == RET_OK);
		assert(linear_container_length(linear_container) == (n-i-1));
		if((i + 1) < n)
		{
			assert(linear_container_get_by_index(linear_container, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(linear_container_length(linear_container) == 0);

	for(i = 0; i < n; i++)
	{
		assert(linear_container_prepend(linear_container, (void*)i) == RET_OK);
		assert(linear_container_length(linear_container) == (i + 1));
		assert(linear_container_get_by_index(linear_container, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(linear_container_set_by_index(linear_container, 0, (void*)(2*i)) == RET_OK);
		assert(linear_container_get_by_index(linear_container, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(linear_container_set_by_index(linear_container, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(linear_container_foreach(linear_container, check_and_dec_int, &i) == RET_OK);

	linear_container_destroy(linear_container);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(linear_container_length(NULL) == 0);
	assert(linear_container_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(linear_container_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(linear_container_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(linear_container_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(linear_container_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(linear_container_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(linear_container_find(NULL, NULL, NULL) < 0);
	assert(linear_container_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	LinearContainer* linear_container = linear_container_darray_create(NULL, NULL);
	test_int_linear_container(linear_container);
	linear_container = linear_container_dlist_create(NULL, NULL);
	test_int_linear_container(linear_container);
	test_invalid_params();

	return;
}

int main(int argc, char* argv[])
{
	single_thread_test();

	return 0;
}
all:
	# -Wno-unused-function  发现不使用的函数不警告
	#  darray_test
	gcc -Wall -Wno-unused-function -g -m32 -DDARRAY_TEST darray.c -o darray_test
	#  dlist_test
	gcc -Wall -Wno-unused-function -g -m32 -DDLIST_TEST dlist.c -o dlist_test
	#  queue_test
	gcc -Wall -Wno-unused-function -g -m32 -DQUEUE_TEST dlist.c linear_container_dlist.c  queue.c -o queue_test
	# container_test
	gcc -Wall -Wno-unused-function -g -m32 -shared darray.c  dlist.c  linear_container_darray.c linear_container_dlist.c queue.c -o libcontainer.so
	gcc -Wall -Wno-unused-function -g -m32 linear_container_test.c -L./ -lcontainer -o container_test
clean:
	rm *test *.so

6.2 迭代器

/*
 * File : invert_ng.c
 */

#include "linear_container.h"

Ret invert(LinearContainer* linear_container)
{
	int i = 0;
	int j = 0;
	void* data1 = NULL;
	void* data2 = NULL;

	return_val_if_fail(linear_container != NULL, RET_INVALID_PARAMS);

	j = linear_container_length(linear_container) - 1;
	for(; i < j; i++, j--)
	{
		linear_container_get_by_index(linear_container, i, &data1);
		linear_container_get_by_index(linear_container, j, &data2);
		linear_container_set_by_index(linear_container, i, data2);
		linear_container_set_by_index(linear_container, j, data1);
	}

	return RET_OK;
}

#ifdef INVERT_TEST
#include "test_helper.c"
#include "linear_container_dlist.h"

int main(int argc, char* argv[])
{
	int i = 0;
	int n = 101;

	LinearContainer* linear_container = linear_container_dlist_create(NULL, NULL);
	for(i = 0; i < n; i++)
	{
		linear_container_append(linear_container, (void*)i);
	}
	invert(linear_container);
	i--;
	linear_container_foreach(linear_container, check_and_dec_int, &i); 
	linear_container_destroy(linear_container);

	return 0;
}
#endif/*INVERT_TEST*/
#ifndef ITERATOR_H
#define ITERATOR_H

#include "typedef.h"

DECLS_BEGIN

struct _Iterator;
typedef struct _Iterator Iterator;

typedef Ret  (*IteratorSetFunc)(Iterator* thiz, void* data);
typedef Ret  (*IteratorGetFunc)(Iterator* thiz, void** data);
typedef Ret  (*IteratorNextFunc)(Iterator* thiz);
typedef Ret  (*IteratorPrevFunc)(Iterator* thiz);
typedef Ret  (*IteratorAdvanceFunc)(Iterator* thiz, int offset);
typedef int  (*IteratorOffsetFunc)(Iterator* thiz);
typedef Ret  (*IteratorCloneFunc)(Iterator* thiz, Iterator** cloned);
typedef void (*IteratorDestroyFunc)(Iterator* thiz);

struct _Iterator
{
	IteratorSetFunc     set;
	IteratorGetFunc     get;
	IteratorNextFunc    next;
	IteratorPrevFunc    prev;
	IteratorAdvanceFunc advance;
	IteratorCloneFunc   clone;
	IteratorOffsetFunc  offset;
	IteratorDestroyFunc destroy;

	char priv[0];
};

static inline Ret  iterator_set(Iterator* thiz, void* data)
{
	return_val_if_fail(thiz != NULL && thiz->set != NULL, RET_INVALID_PARAMS);

	return thiz->set(thiz, data);
}

static inline Ret  iterator_get(Iterator* thiz, void** data)
{
	return_val_if_fail(thiz != NULL && thiz->get != NULL, RET_INVALID_PARAMS);

	return thiz->get(thiz, data);
}

static inline Ret  iterator_next(Iterator* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->next != NULL, RET_INVALID_PARAMS);

	return thiz->next(thiz);
}

static inline Ret  iterator_prev(Iterator* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->prev != NULL, RET_INVALID_PARAMS);

	return thiz->prev(thiz);
}

static inline Ret  iterator_advance(Iterator* thiz, int offset)
{
	return_val_if_fail(thiz != NULL && thiz->advance != NULL, RET_INVALID_PARAMS);

	return thiz->advance(thiz, offset);
}

static inline int  iterator_offset(Iterator* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->offset != NULL, -1);

	return thiz->offset(thiz);
}

static inline Ret  iterator_clone(Iterator* thiz, Iterator** cloned)
{
	return_val_if_fail(thiz != NULL && thiz->clone != NULL, RET_INVALID_PARAMS);

	return thiz->clone(thiz, cloned);
}

static inline void iterator_destroy(Iterator* thiz)
{
	return_if_fail(thiz != NULL && thiz->destroy != NULL);

	return thiz->destroy(thiz);
}

DECLS_END

#endif/*ITERATOR_H*/

/*
 * File : dlist_iterator.h
 */

#ifndef DLIST_ITERATOR_H
#define DLIST_ITERATOR_H

#include "dlist.h"
#include "iterator.h"

DECLS_BEGIN

Iterator* dlist_iterator_create(DList* dlist);

DECLS_END

#endif/*DLIST_ITERATOR_H*/

/*
 * File : dlist_iterator.c
 */

#include <string.h>
#include "dlist_iterator.h"

typedef struct _PrivInfo
{
	DList* dlist;
	DListNode* cursor;
	int offset;
}PrivInfo;

static Ret  dlist_iterator_set(Iterator* thiz, void* data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->cursor != NULL && priv->dlist != NULL, RET_INVALID_PARAMS);

	priv->cursor->data = data;

	return RET_OK;
}

static Ret  dlist_iterator_get(Iterator* thiz, void** data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->cursor != NULL && priv->dlist != NULL && data != NULL, RET_INVALID_PARAMS);

	*data = priv->cursor->data;

	return RET_OK;
}

static Ret  dlist_iterator_next(Iterator* thiz)
{
	Ret ret = RET_FAIL;
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->cursor != NULL && priv->dlist != NULL, RET_INVALID_PARAMS);

	if(priv->cursor->next != NULL)
	{
		priv->cursor = priv->cursor->next;
		priv->offset++;

		ret = RET_OK;
	}

	return ret;
}

static Ret  dlist_iterator_prev(Iterator* thiz)
{
	Ret ret = RET_FAIL;
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->cursor != NULL && priv->dlist != NULL, RET_INVALID_PARAMS);

	if(priv->cursor->prev != NULL)
	{
		priv->cursor = priv->cursor->prev;
		priv->offset--;

		ret = RET_OK;
	}

	return RET_OK;
}

static Ret  dlist_iterator_advance(Iterator* thiz, int offset)
{
	int n   = offset;
	Ret ret = RET_FAIL;
	DListNode* iter = NULL;
	PrivInfo*  priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->cursor != NULL && priv->dlist != NULL, RET_INVALID_PARAMS);

	iter = priv->cursor;
	if(offset > 0)
	{
		for(n = offset; n > 0 && iter != NULL; n--)
		{
			iter = iter->next;
		}
	}
	else
	{
		for(n = -offset; n > 0 && iter != NULL; n--)
		{
			iter = iter->prev;
		}
	}

	if(iter != NULL)
	{
		priv->cursor = iter;
		priv->offset += offset;

		ret = RET_OK;
	}

	return ret;
}

static int  dlist_iterator_offset(Iterator* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->cursor != NULL && priv->dlist != NULL, RET_INVALID_PARAMS);

	return priv->offset;
}

static Ret  dlist_iterator_clone(Iterator* thiz, Iterator** cloned)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->cursor != NULL && priv->dlist != NULL, RET_INVALID_PARAMS);

	*cloned = (Iterator*)malloc(sizeof(Iterator) + sizeof(PrivInfo));
	if(*cloned != NULL)
	{
		memcpy(*cloned, thiz, sizeof(Iterator) + sizeof(PrivInfo));
	}

	return *cloned != NULL ? RET_OK : RET_FAIL;
}

static void dlist_iterator_destroy(Iterator* thiz)
{
	if(thiz != NULL)
	{
		free(thiz);
	}

	return;
}

Iterator* dlist_iterator_create(DList* dlist)
{
	Iterator* thiz = NULL;
	return_val_if_fail(dlist != NULL, NULL);

	if((thiz = malloc(sizeof(Iterator) + sizeof(PrivInfo))) != NULL)
	{
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->set      =  dlist_iterator_set;
		thiz->get      =  dlist_iterator_get;
		thiz->next     =  dlist_iterator_next;
		thiz->prev     =  dlist_iterator_prev;
		thiz->advance  =  dlist_iterator_advance;
		thiz->clone    =  dlist_iterator_clone;
		thiz->offset   =  dlist_iterator_offset;
		thiz->destroy  =  dlist_iterator_destroy;

		priv->dlist  = dlist;
		priv->cursor = dlist->first;
		priv->offset = 0;
	}

	return thiz;
}

/*
 * File : darray_iterator.h
 */

#ifndef DARRAY_ITERATOR_H
#define DARRAY_ITERATOR_H

#include "darray.h"
#include "iterator.h"

DECLS_BEGIN

Iterator* darray_iterator_create(DArray* darray);

DECLS_END

#endif/*DARRAY_ITERATOR_H*/

/*
 * File : darray_iterator.c
 */

#include <string.h>
#include "darray_iterator.h"

typedef struct _PrivInfo
{
	DArray* darray;
	int offset;
}PrivInfo;

static Ret  darray_iterator_set(Iterator* thiz, void* data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->darray != NULL, RET_INVALID_PARAMS);

	return darray_set_by_index(priv->darray, priv->offset, data);
}

static Ret  darray_iterator_get(Iterator* thiz, void** data)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->darray != NULL && data != NULL, RET_INVALID_PARAMS);

	return darray_get_by_index(priv->darray, priv->offset, data);
}

static Ret  darray_iterator_next(Iterator* thiz)
{
	Ret ret = RET_FAIL;
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->darray != NULL, RET_INVALID_PARAMS);

	if((priv->offset + 1) < priv->darray->size)
	{
		priv->offset++;
		ret = RET_OK;
	}

	return ret;
}

static Ret  darray_iterator_prev(Iterator* thiz)
{
	Ret ret = RET_FAIL;
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->darray != NULL, RET_INVALID_PARAMS);

	if(priv->offset > 0)
	{
		priv->offset--;

		ret = RET_OK;
	}

	return RET_OK;
}

static Ret  darray_iterator_advance(Iterator* thiz, int offset)
{
	int new_offset = 0;
	Ret ret = RET_FAIL;
	PrivInfo*  priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->darray != NULL, RET_INVALID_PARAMS);

	new_offset = priv->offset + offset;
	if(new_offset >= 0 && new_offset < priv->darray->size)
	{
		priv->offset = new_offset;
	}

	return ret;
}

static int  darray_iterator_offset(Iterator* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->darray != NULL, RET_INVALID_PARAMS);

	return priv->offset;
}

static Ret  darray_iterator_clone(Iterator* thiz, Iterator** cloned)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	return_val_if_fail(priv->darray != NULL, RET_INVALID_PARAMS);

	*cloned = (Iterator*)malloc(sizeof(Iterator) + sizeof(PrivInfo));
	if(*cloned != NULL)
	{
		memcpy(*cloned, thiz, sizeof(Iterator) + sizeof(PrivInfo));
	}

	return *cloned != NULL ? RET_OK : RET_FAIL;
}

static void darray_iterator_destroy(Iterator* thiz)
{
	if(thiz != NULL)
	{
		free(thiz);
	}

	return;
}

Iterator* darray_iterator_create(DArray* darray)
{
	Iterator* thiz = NULL;
	return_val_if_fail(darray != NULL, NULL);

	if((thiz = malloc(sizeof(Iterator) + sizeof(PrivInfo))) != NULL)
	{
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->set      =  darray_iterator_set;
		thiz->get      =  darray_iterator_get;
		thiz->next     =  darray_iterator_next;
		thiz->prev     =  darray_iterator_prev;
		thiz->advance  =  darray_iterator_advance;
		thiz->clone    =  darray_iterator_clone;
		thiz->offset   =  darray_iterator_offset;
		thiz->destroy  =  darray_iterator_destroy;

		priv->darray  = darray;
		priv->offset = 0;
	}

	return thiz;
}

/*
 * File : invert.c
 */

#include "iterator.h"

Ret invert(Iterator* forward, Iterator* backward)
{
	void* data1 = NULL;
	void* data2 = NULL;
	return_val_if_fail(forward != NULL && backward != NULL, RET_INVALID_PARAMS);

	for(; iterator_offset(forward) < iterator_offset(backward); iterator_next(forward), iterator_prev(backward))
	{
		iterator_get(forward, &data1);
		iterator_get(backward, &data2);
		iterator_set(forward, data2);
		iterator_set(backward, data1);
	}

	return RET_OK;
}

#ifdef INVERT_TEST
#include "dlist.h"
#include "dlist_iterator.h"
#include "test_helper.c"

int main(int argc, char* argv[])
{
	int i = 0;
	int n = 101;
	int last = n - 1;
	DList* dlist = dlist_create(NULL, NULL);

	for(i = 0; i < n; i++)
	{
		dlist_append(dlist, (void*)i);
	}

	Iterator* forward = dlist_iterator_create(dlist);
	Iterator* backward = dlist_iterator_create(dlist);

	iterator_advance(backward, last);
	invert(forward, backward);
	dlist_foreach(dlist, check_and_dec_int, &last);
	iterator_destroy(forward);
	iterator_destroy(backward);
	dlist_destroy(dlist);

	return 0;
}
#endif/*INVERT_TEST*/
all:
	gcc -Wall -m32 -g -DDARRAY_TEST darray.c -o darray_test
	gcc -Wall -m32 -g -DDLIST_TEST dlist.c -o dlist_test
	gcc -Wall -m32 -g -shared darray.c  dlist.c  linear_container_darray.c linear_container_dlist.c -o libcontainer.so
	gcc -Wall -m32 -g linear_container_test.c -L./ -lcontainer -o container_test
	gcc -Wall -m32 -g invert_ng.c -DINVERT_TEST -L./ -lcontainer -o invert_ng_test
	gcc -Wall -m32 -g invert.c -DINVERT_TEST -L./ -lcontainer -o invert_test
clean:
	rm *test *.so

6.3 动态绑定

/*
 * File : call_cos.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(int argc, char **argv)
{
	void *handle = NULL;
	double (*cosine)(double) = NULL;
	/*加载共享库*/
	handle = dlopen("libm.so", RTLD_LAZY);
	/*通过函数名找到函数指针*/
	*(void **) (&cosine) = dlsym(handle, "cos");
	/*调用函数*/
	printf("%f\n", (*cosine)(2.0));
	/*卸载共享库*/
	dlclose(handle);

	return 0;
}
/*
 * File:    module.h
 */

#ifndef MODULE_H
#define MODULE_H
#include "typedef.h"

DECLS_BEGIN

struct _Module;
typedef struct _Module Module;

typedef enum _ModuleFlags
{
	MODULE_FLAGS_NONE,
	MODULE_FLAGS_DELAY = 1
}ModuleFlags;

Module* module_create(const char* file_name, ModuleFlags flags);
void*   module_sym(Module* thiz, const char* func_name);
void    module_destroy(Module* thiz);

DECLS_END

#endif/*MODULE_H*/

/*
 * File:    module_linux.h
 */

#include <dlfcn.h>
#include "module.h"

struct _Module
{
	void* handle;
};

Module* module_create(const char* file_name, ModuleFlags flags)
{
	Module* thiz = NULL;
	return_val_if_fail(file_name != NULL, NULL);
	
	if((thiz = malloc(sizeof(Module))) != NULL)
	{
		thiz->handle = dlopen(file_name, flags & MODULE_FLAGS_DELAY ? RTLD_LAZY : RTLD_NOW);
		if(thiz->handle == NULL)
		{
			free(thiz);
			thiz = NULL;
			printf("%s\n", dlerror());
		}
	}

	return thiz;
}

void*   module_sym(Module* thiz, const char* func_name)
{
	return_val_if_fail(thiz != NULL && thiz->handle != NULL && func_name != NULL, NULL);

	dlerror();
	return dlsym(thiz->handle, func_name);
}

void    module_destroy(Module* thiz)
{
	if(thiz != NULL)
	{
		if(thiz->handle != NULL)
		{
			dlclose(thiz->handle);
		}
		
		free(thiz);
	}
	
	return;
}

/*
 * File : module_test.c
 */

#include <stdio.h>
#include "module.h"

int main(int argc, char* argv[])
{
	if(argc != 3) {
		printf("%s module function\n", argv[0]);

		return 0;
	}

	Module* module = module_create(argv[1], 0);
	if(module != NULL) {
		void* func = module_sym(module, argv[2]);
		printf("func=%p\n", func);
		module_destroy(module);
	} else {
		printf("load %s failed\n", argv[1]);
	}

	return 0;
}
all:
	gcc -Wall -m32 -g -DDARRAY_TEST darray.c -o darray_test
	gcc -Wall -m32 -g -DDLIST_TEST dlist.c -o dlist_test
	gcc -Wall -m32 -g -shared darray.c  dlist.c  linear_container_darray.c linear_container_dlist.c queue.c -o libcontainer.so
	gcc -Wall -m32 -g linear_container_test.c -L./ -lcontainer -o container_test
	gcc -Wall -m32 -g queue.c linear_container_dlist.c dlist.c -DQUEUE_TEST -o queue_test
	gcc -Wall -m32 -g module_linux.c module_test.c -ldl -o module_test
	gcc -Wall -m32 -g module_linux.c queue.c queue_test.c -ldl -o queue_dynamic_test
	gcc -m32 -g call_cos.c -ldl -o call_cos

clean:
	rm *test *.so call_cos

第七章 工程管理

7.1 Hello World

1) 目录结构

hellowrold/
         |--- Makefile.am
         |
         |--- src/
               |
               |--- Makefile.am
               |--- main.c

2) helloworld/main.c

#include <stdio.h>

int main(int argc, char* argv[])
{
	printf("Hello World!\n");

	return 0;
}

3) 创建Makefile模板

Makefile.am

SUBDIRS=src  #子目录,如果有多个子目录,用空格分开.
dist_doc_DATA = README

src/Makefile.am

bin_PROGRAMS=hello      # 表示要产生的可执行文件,有多个可执行文件用空格分开; 前缀缀 bin 表示可执行文件的安装路径为bin。
hello_SOURCES=main.c    # 表示生成可执行文件需要的源文件,有多个源文件用空格分开。

4) 创建autoconf的模板

$ autoscan

在helloworld下运行 auttoscan 生成文件 configure.scan,

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT

改名为 configure.ac

$ mv configure.scan  configure.scan

修改 configure.ac

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([helloworld], [1.0], [jxm_zn@163.com])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])


#  ./configure  --enable-debug 时,  CFLAGS="${CFLAGS} -g -O0"
#  ./configure                 时,  CFLAGS="-m32 -g -O2"
AC_ARG_ENABLE([debug],
	      [AS_HELP_STRING([--enable-debug],[debug program(default is no)])],
	      [CFLAGS="${CFLAGS} -g -O0"],
	      [CFLAGS="-m32 -g -O2"]
	    )

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT

configure.ac 是由一系列的宏组成,这些宏最终有命令m4展开,得到一个脚本文件 configure , configure 的主要功能都是探测系统配置,然后根据这些配置来生成相应的Makefile文件. 比如 AC_PROG_CC 是用来检测编译器的. AC_CONFIG_FILESAC_OUTPUT 是用来产生Makefile和其他数据文件的.

5) 生成configure脚本

$ touch README
$ autoreconf --install

6) 生成最终的Makefile

$ ./configure

configure 有以下两个常用的参数。

--prefix : 用来制定安装目录,linux默认安装目录是 /usr/local

--host   : 用于交叉编译,比如x86的PC机上编译在ARM板上运行的程序.

eg:
    ./configure --prefix=/home/jxm/work/arm-root/usr/ --host=arm-linux

7) 编译与安装

$ make -j4 && make install

7.2 函数库

└── base
    ├── AUTHORS
    ├── ChangeLog
    ├── Makefile.am
    ├── NEWS
    ├── README
    ├── autogen.sh
    ├── base.pc.in
    ├── configure.ac
    └── src
        ├── Makefile.am
        ├── darray.c
        ├── darray.h
        ├── darray_iterator.c
        ├── darray_iterator.h
        ├── dlist.c
        ├── dlist.h
        ├── dlist_iterator.c
        ├── dlist_iterator.h
        ├── hash_table.c
        ├── hash_table.h
        ├── invert.c
        ├── invert_ng.c
        ├── iterator.h
        ├── linear_container.h
        ├── linear_container_darray.c
        ├── linear_container_darray.h
        ├── linear_container_dlist.c
        ├── linear_container_dlist.h
        ├── linear_container_test.c
        ├── queue.c
        ├── queue.h
        ├── sort.c
        ├── sort.h
        ├── stack.c
        ├── stack.h
        ├── test_helper.c
        └── typedef.h

1)创建工程

Makefile.am

SUBDIRS=src

pkgconfigdir=${libdir}/pkgconfig
pkgconfig_DATA=base.pc

src/Makefile.am

# 函数库名称
lib_LTLIBRARIES=libbase.la

# 生成libbase.la 所需要的源文件
libbase_la_SOURCES= darray.c \
	darray.h \
	dlist.c \
	dlist.h \
	darray_iterator.h \
	dlist_iterator.h \
	hash_table.c \
	hash_table.h \
	invert.c \
	iterator.h \
	linear_container_darray.c \
	linear_container_darray.h \
	linear_container_dlist.c \
	linear_container_dlist.h \
	linear_container.h \
	queue.c \
	queue.h \
	sort.c \
	sort.h \
	stack.c \
	stack.h \
	typedef.h 

# 指定libbase_la连接所需要的关键字
libbase_la_LDFLAGS=-lpthread

#不需要安装的可执行文件
noinst_PROGRAMS=darray_test dlist_test

darray_test_SOURCES=darray.c
darray_test_CFLAGS=-DDARRAY_TEST

dlist_test_SOURCES=dlist.c
dlist_test_CFLAGS=-DDLIST_TEST

# 头文件安装目录
basedir=$(includedir)/base

# 需要安装的头文件
# xxx_HEADERS 与  xxxdir 配套使用
base_HEADERS=darray.h dlist.h iterator.h linear_container_dlist.h typedef.h \
	darray_iterator.h  dlist_iterator.h  linear_container_darray.h  \
	linear_container.h

EXTRA_DIST=\
	linear_container_test.c \
	invert_ng.c \
	darray_iterator.c \
	dlist_iterator.c \
	test_helper.c 

base.pc.in

prefix=@prefix@
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include

Name: @PACKAGE_NAME@
Description: a basic library.
Version: @VERSION@
Requires: 
Libs: -L${libdir} -lbase
Cflags: -I${includedir}/base

configure.ac

$ autoscan
$ mv configure.scan configure.ac
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([base], [0.1], [cjiangxumin@gmail.com])
AC_CONFIG_SRCDIR([src/sort.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])

#  ./configure  --enable-debug 时,  CFLAGS="${CFLAGS} -g -O0"
#  ./configure                 时,  CFLAGS="-m32 -g -O2"
AC_ARG_ENABLE([debug],
	      [AS_HELP_STRING([--enable-debug],[debug program(default is no)])],
	      [CFLAGS="${CFLAGS} -m3 -g -O0"],
	      [CFLAGS="-m32 -g -O2"]
	    )

# Checks for programs.
AM_PROG_AR
AC_PROG_CC
AC_PROG_LIBTOOL  # 检查 libtool

# Checks for libraries.
# FIXME: Replace `main' with a function in `-lpthread':
AC_CHECK_LIB([pthread], [main])

# Checks for header files.
#AC_HEADER_STDC
AC_CHECK_HEADERS([stdlib.h string.h unistd.h])  #检查头文件是否存在

# Checks for typedefs, structures, and compiler characteristics.
AC_C_INLINE
AC_TYPE_SIZE_T

# Checks for library functions.
AC_FUNC_MALLOC  #检查标准malloc函数是否存在
AC_FUNC_REALLOC

AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT(base.pc)

2)编译与安装

# autogen
autoreconf --install

# build
./configure --prefix=/tmp/usr
make && make install

3)pkg-config 简单使用

# show info
# apt-get install -y pkg-config
export PKG_CONFIG_PATH=/tmp/usr/lib/pkgconfig
pkg-config --list-all
pkg-config --cflags --libs base

7.3 应用程序

└── appdemo
    ├── AUTHORS
    ├── ChangeLog
    ├── Makefile.am
    ├── NEWS
    ├── README
    ├── autogen.sh
    ├── configure.ac
    └── src
        ├── Makefile.am
        └── main.c

1) 创建工程

Makefile.am

SUBDIRS=src

src/Makefile.am

bin_PROGRAMS=appdemo
appdemo_SOURCES=main.c
appdemo_CFLAGS=@BASE_CFLAGS@
appdemo_LDFLAGS=@BASE_LIBS@
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([appdemo], [0.1], [cjiangxumin@gmail.com])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])

#  ./configure  --enable-debug 时,  CFLAGS="${CFLAGS} -g -O0"
#  ./configure                 时,  CFLAGS="-m32 -g -O2"
AC_ARG_ENABLE([debug],
	      [AS_HELP_STRING([--enable-debug],[debug program(default is no)])],
	      [CFLAGS="${CFLAGS} -m3 -g -O0"],
	      [CFLAGS="-m32 -g -O2"]
	    )


AM_PROG_AR
# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LIBTOOL   # 添加, 解决:appdemo/src/main.c:5: undefined reference to `dlist_create'

# Checks for libraries.
PKG_CHECK_MODULES(BASE, ["base"]) # 检查软件包base, 通过调用pkg-config,生成BASE_CFLAGS,BASE_LIBS
AC_SUBST(BASE_CFLAGS)   # 把所有对BASE_CFLAGS的引用替换成实际的参数,即把Makefile.am中的@BASE_CFLAGS@替换成实际值
AC_SUBST(BASE_LIBS)

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT

2) 编译与安装

# autogen
$ autoreconf --install

# build
$ export PKG_CONFIG_PATH=/tmp/usr/lib/pkgconfig
$ ./configure --prefix=/tmp/usr
$ make && make install

3) 发布软件

# 发布软件包
$ make dist  # 或者 make distcheck

第八章 内存管理

第九章 从计算机的角度思考问题

第十章 文本处理

10.1 状态机

#include <ctype.h>
#include <stdio.h>

#define IS_WORD_CHAR(c)	(isalpha(c) || isdigit(c))

int count_word(const char* text)
{
	enum _State
	{
		STAT_INIT,
		STAT_IN_WORD,
		STAT_OUT_WORD,
	}state = STAT_INIT;

	int count = 0;
	const char* p = text;

	for(p = text; *p != '\0'; p++){
		switch(state){
			case STAT_INIT:{
				if(IS_WORD_CHAR(*p)){
					state = STAT_IN_WORD;
				}else{
					state = STAT_OUT_WORD;
				}
				break;
			}
			case STAT_IN_WORD:{
				if(!IS_WORD_CHAR(*p)){
					count++;
					state = STAT_OUT_WORD;
				}
				break;
			}
			case STAT_OUT_WORD:{
				if(IS_WORD_CHAR(*p)){
					state = STAT_IN_WORD;
				}
				break;
			}
			default:break;
		}
	}

	if(state == STAT_IN_WORD){
		count++;
	}

	return count;
}

#ifdef COUNT_WORD_TEST
#include <assert.h>

int main(int argc, char* argv[])
{
	assert(count_word("") == 0);
	assert(count_word(" ") == 0);
	assert(count_word("it") == 1);
	assert(count_word("it ") == 1);
	assert(count_word("it is") == 2);
	assert(count_word("it is used to count words.") == 6);
	assert(count_word("it is used to count words. is it easy?") == 9);

	return 0;
}
#endif/*COUNT_WORD_TEST*/

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define IS_WORD_CHAR(c)	(isalpha(c) || isdigit(c))

typedef void (*OnWordFunc)(void* ctx, const char* word);

int word_segmentation(const char* text, OnWordFunc on_word, void* ctx)
{
	enum _State{
		STAT_INIT,
		STAT_IN_WORD,
		STAT_OUT_WORD,
	}state = STAT_INIT;

	int count = 0;
	char* copy_text = strdup(text);
	char* p = copy_text;
	char* word = copy_text;

	for(p = copy_text; *p != '\0'; p++){
		switch(state){
			case STAT_INIT:{
				if(IS_WORD_CHAR(*p)){
					word = p;
					state = STAT_IN_WORD;
				}
				break;
			}
			case STAT_IN_WORD:{
				if(!IS_WORD_CHAR(*p)){
					count++;
					*p = '\0';
					on_word(ctx, word);
					state = STAT_OUT_WORD;
				}
				break;
			}
			case STAT_OUT_WORD:{
				if(IS_WORD_CHAR(*p)){
					word = p;
					state = STAT_IN_WORD;
				}
				break;
			}
			default:break;
		}
	}

	if(state == STAT_IN_WORD){
		count++;
		on_word(ctx, word);
	}

	free(copy_text);

	return count;
}

#ifdef WORD_SEGMENTATION_TEST
#include <assert.h>

void on_word(void* ctx, const char* word)
{
	printf("%s\n", word);

	return;
}

int main(int argc, char* argv[])
{
	assert(word_segmentation("it is used to word segmentation. is it easy?", on_word, NULL) == 9);

	return 0;
}
#endif/*WORD_SEGMENTATION_TEST*/

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef void (*OnTokenFunc)(void* ctx, int index, const char* token);

#define IS_DELIM(c) (strchr(delims, c) != NULL)
int parse_token(const char* text, const char* delims, OnTokenFunc on_token, void* ctx)
{
	enum _State{
		STAT_INIT,
		STAT_IN,
		STAT_OUT,
	}state = STAT_INIT;

	int   count     = 0;
	char* copy_text = strdup(text);
	char* p         = copy_text;
	char* token     = copy_text;

	for(p = copy_text; *p != '\0'; p++){
		switch(state){
			case STAT_INIT:
			case STAT_OUT:{
				if(!IS_DELIM(*p)){
					token = p;
					state = STAT_IN;
				}
				break;
			}
			case STAT_IN:{
				if(IS_DELIM(*p)){
					*p = '\0';
					on_token(ctx, count++, token);
					state = STAT_OUT;
				}
				break;
			}
			default:break;
		}
	}

	if(state == STAT_IN){
		on_token(ctx, count++, token);
	}

	on_token(ctx, -1, NULL);
	free(copy_text);

	return count;
}

#ifdef PARSE_TOKEN_TEST
#include <assert.h>

void on_token(void* ctx, int index, const char* token)
{
	printf("[%d] %s\n", index, token);

	return;
}

int main(int argc, char* argv[])
{
	assert(parse_token("it is used to token segmentation. is it easy?", " .?", on_token, NULL) == 9);

	assert(parse_token("/backup/tools/jdk1.5.0_18/bin/"":/usr/lib/qt-3.3/bin:/usr/kerberos/bin:"
			   "/backup/tools/jdk1.5.0_18/bin/:/usr/lib/ccache:/usr/local/bin:/usr/bin:"
			   "/bin:/home/lixianjing/bin", ":", on_token, NULL) == 9
	      );
	assert(parse_token("/backup/tools/jdk1.5.0_18/bin/", "/", on_token, NULL) == 4);

	return 0;
}
#endif/*COUNT_TEST*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

const char* strtrim(char* str)
{
	char* p = NULL;

	p = str + strlen(str) - 1;

	while(p != str && isspace(*p)){
		*p = '\0';
		p--;
	}

	p = str;
	while(*p != '\0' && isspace(*p)) p++;

	if(p != str){
		char* s = p;
		char* d = str;
		while(*s != '\0'){
			*d = *s;
			d++;
			s++;
		}
		*d = '\0';
	}

	return str;
}

static void ini_parse_internal(char* buffer, char comment_char, char delim_char)
{
	char* p = buffer;
	char* group_start = NULL;
	char* key_start   = NULL;
	char* value_start = NULL;
	
	enum _State{
		STAT_NONE = 0, /*空白状态*/
		STAT_GROUP,
		STAT_KEY,
		STAT_VALUE, 
		STAT_COMMENT /*注释状态*/
	}state = STAT_NONE;

	for(p = buffer; *p != '\0'; p++){
		switch(state){
			case STAT_NONE:{
				if(*p == '['){
					state = STAT_GROUP;
					group_start = p + 1;
				}else if(*p == comment_char){
					state = STAT_COMMENT;
				}else if(!isspace(*p)){
					state = STAT_KEY;
					key_start = p;
				}
				break;
			}
			case STAT_GROUP:{
				if(*p == ']'){
					*p = '\0';
					state = STAT_NONE;
					strtrim(group_start);
					printf("[%s]\n", group_start);
				}
				break;
			}
			case STAT_COMMENT:{
				if(*p == '\n'){
					state = STAT_NONE;
					break;
				}
				break;
			}
			case STAT_KEY:{
				if(*p == delim_char || (delim_char == ' ' && *p == '\t')){
					*p = '\0';
					state = STAT_VALUE;
					value_start = p + 1;
				}
				break;
			}
			case STAT_VALUE:{
				if(*p == '\n' || *p == '\r'){
					*p = '\0';
					state = STAT_NONE;
					strtrim(key_start);
					strtrim(value_start);
					printf("%s%c%s\n", key_start, delim_char, value_start);
				}
				break;
			}
			default:break;
		}
	}

	if(state == STAT_VALUE)
	{
		strtrim(key_start);
		strtrim(value_start);
		printf("%s%c%s\n", key_start, delim_char, value_start);
	}

	return;
}

#ifdef INI_PARSER_TEST

int main(int argc, char* argv[])
{
	char* buffer = strdup("[lixianjing]\nname=lixianjing\ngender=male\n[zhangshan]\nname=zhangshan\ngender=male\nage=100");
	ini_parse_internal(buffer, '#', '=');
	free(buffer);

	return 0;
}
#endif/*INI_PARSER_TEST*/

#ifndef XML_PARSER_H
#define XML_PARSER_H
struct _XmlParser;
typedef struct _XmlParser XmlParser;

XmlParser* xml_parser_create(void);
void xml_parser_parse(XmlParser* thiz, const char* xml);
void xml_parser_destroy(XmlParser* thiz);

#endif/*XML_PARSER_H*/

/*
 * File:    xml_parser.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "xml_parser.h"

#define MAX_ATTR_NR 64

struct _XmlParser
{
	const char* read_ptr;

	int   attrs_nr;
	char* attrs[2*MAX_ATTR_NR+1];

	char* buffer;
	int buffer_used;
	int buffer_total;

};

static const char* strtrim(char* str);
static void xml_parser_parse_entity(XmlParser* thiz);
static void xml_parser_parse_start_tag(XmlParser* thiz);
static void xml_parser_parse_end_tag(XmlParser* thiz);
static void xml_parser_parse_comment(XmlParser* thiz);
static void xml_parser_parse_pi(XmlParser* thiz);
static void xml_parser_parse_text(XmlParser* thiz);
static void xml_parser_reset_buffer(XmlParser* thiz);

XmlParser* xml_parser_create(void)
{
	return (XmlParser*)calloc(1, sizeof(XmlParser));
}

void xml_parser_parse(XmlParser* thiz, const char* xml)
{
	enum _State{
		STAT_NONE,
		STAT_AFTER_LT,
		STAT_START_TAG,
		STAT_END_TAG,
		STAT_TEXT,
		STAT_PRE_COMMENT1,
		STAT_PRE_COMMENT2,
		STAT_COMMENT,
		STAT_PROCESS_INSTRUCTION,
	}state = STAT_NONE;

	thiz->read_ptr = xml;

	for(; *thiz->read_ptr != '\0'; thiz->read_ptr++){
		char c = thiz->read_ptr[0];

		switch(state){
			case STAT_NONE:{

				if(c == '<'){
					xml_parser_reset_buffer(thiz);
					state = STAT_AFTER_LT;
				}
				else if(!isspace(c)){
					state = STAT_TEXT;
				}
				break;
			}
			case STAT_AFTER_LT: {
				if(c == '?'){
					state = STAT_PROCESS_INSTRUCTION;
				}
				else if(c == '/'){
					state = STAT_END_TAG;
				}
				else if(c == '!'){
					state = STAT_PRE_COMMENT1;
				}
				else if(isalpha(c) || c == '_'){
					state = STAT_START_TAG;
				}
				else{}
				break;
			}
			case STAT_START_TAG:{
				xml_parser_parse_start_tag(thiz);
				state = STAT_NONE;
				break;
			}
			case STAT_END_TAG:{
				xml_parser_parse_end_tag(thiz);
				state = STAT_NONE;
				break;
			}
			case STAT_PROCESS_INSTRUCTION:{
				xml_parser_parse_pi(thiz);
				state = STAT_NONE;
				break;
			}
			case STAT_TEXT:{
				xml_parser_parse_text(thiz);
				state = STAT_NONE;
				break;
			}
			case STAT_PRE_COMMENT1:{
				if(c == '-'){
					state = STAT_PRE_COMMENT2;
				}
				else{
				}
				break;
			}
			case STAT_PRE_COMMENT2:{
				if(c == '-'){
					state = STAT_COMMENT;
				}
				else
				{
				}
			}
			case STAT_COMMENT:{
				xml_parser_parse_comment(thiz);	
				state = STAT_NONE;
				break;
			}
			default:break;
		}

		if(*thiz->read_ptr == '\0'){
			break;
		}
	}

	return;
}

static void xml_parser_reset_buffer(XmlParser* thiz)
{
	thiz->buffer_used = 0;
	thiz->attrs_nr = 0;
	thiz->attrs[0] = NULL;

	return;
}

static int xml_parser_strdup(XmlParser* thiz, const char* start, size_t length)
{
	int offset = -1;

	if((thiz->buffer_used + length) >= thiz->buffer_total){
		size_t length = thiz->buffer_total+(thiz->buffer_total>>1) + 128;
		char* buffer = realloc(thiz->buffer, length);
		if(buffer != NULL){
			thiz->buffer = buffer;
			thiz->buffer_total = length;
		}
	}

	if((thiz->buffer_used + length) >= thiz->buffer_total){
		return offset;
	}

	offset = thiz->buffer_used;
	strncpy(thiz->buffer + offset, start, length);
	thiz->buffer[offset + length] = '\0';
	strtrim(thiz->buffer+offset);
	thiz->buffer_used += length + 1;

	return offset;
}

static void xml_parser_parse_attrs(XmlParser* thiz, char end_char)
{
	int i = 0;
	enum _State{
		STAT_PRE_KEY,
		STAT_KEY,
		STAT_PRE_VALUE,
		STAT_VALUE,
		STAT_END,
	}state = STAT_PRE_KEY;

	char value_end = '\"';
	const char* start = thiz->read_ptr;

	thiz->attrs_nr = 0;
	for(; *thiz->read_ptr != '\0' && thiz->attrs_nr < MAX_ATTR_NR; thiz->read_ptr++){
		char c = *thiz->read_ptr;
	
		switch(state){
			case STAT_PRE_KEY:{
				if(c == end_char || c == '>'){
					state = STAT_END;
				}
				else if(!isspace(c)){
					state = STAT_KEY;
					start = thiz->read_ptr;
				}
			}
			case STAT_KEY:{
				if(c == '='){
					thiz->attrs[thiz->attrs_nr++] = (char*)xml_parser_strdup(thiz, start, thiz->read_ptr - start);
					state = STAT_PRE_VALUE;
				}

				break;
			}
			case STAT_PRE_VALUE:{
				if(c == '\"' || c == '\''){
					state = STAT_VALUE;
					value_end = c;
					start = thiz->read_ptr + 1;
				}
				break;
			}
			case STAT_VALUE:{
				if(c == value_end){
					thiz->attrs[thiz->attrs_nr++] = (char*)xml_parser_strdup(thiz, start, thiz->read_ptr - start);
					state = STAT_PRE_KEY;
				}
			}
			default:break;
		}

		if(state == STAT_END){
			break;
		}
	}
	
	for(i = 0; i < thiz->attrs_nr; i++){
		thiz->attrs[i] = thiz->buffer + (size_t)(thiz->attrs[i]);
	}
	thiz->attrs[thiz->attrs_nr] = NULL;

	return;
}

static void xml_parser_parse_start_tag(XmlParser* thiz)
{
	enum _State{
		STAT_NAME,
		STAT_ATTR,
		STAT_END,
	}state = STAT_NAME;

	char* tag_name = NULL;
	const char* start = thiz->read_ptr - 1;

	for(; *thiz->read_ptr != '\0'; thiz->read_ptr++){
		char c = *thiz->read_ptr;
	
		switch(state){
			case STAT_NAME:{
				if(isspace(c) || c == '>' || c == '/'){
					tag_name = (char*)xml_parser_strdup(thiz, start, thiz->read_ptr - start);
					state = (c != '>' && c != '/') ? STAT_ATTR : STAT_END;
				}
				break;
			}
			case STAT_ATTR:{
				xml_parser_parse_attrs(thiz, '/');
				state = STAT_END;

				break;
			}
			default:break;
		}

		if(state == STAT_END){
			break;
		}
	}
	
	tag_name = thiz->buffer + (size_t)tag_name;
	
	if(thiz->read_ptr[0] == '/'){
	}

	for(; *thiz->read_ptr != '>' && *thiz->read_ptr != '\0'; thiz->read_ptr++);

	return;
}

static void xml_parser_parse_end_tag(XmlParser* thiz)
{
	char* tag_name = NULL;
	const char* start = thiz->read_ptr;
	for(; *thiz->read_ptr != '\0'; thiz->read_ptr++){
		if(*thiz->read_ptr == '>'){
			tag_name = thiz->buffer + xml_parser_strdup(thiz, start, thiz->read_ptr-start);
			break;
		}
	}
	
	return;
}

static void xml_parser_parse_comment(XmlParser* thiz)
{
	enum _State{
		STAT_COMMENT,
		STAT_MINUS1,
		STAT_MINUS2,
	}state = STAT_COMMENT;

	const char* start = ++thiz->read_ptr;
	for(; *thiz->read_ptr != '\0'; thiz->read_ptr++){
		char c = *thiz->read_ptr;

		switch(state){
			case STAT_COMMENT:{
				if(c == '-'){
					state = STAT_MINUS1;
				}
				break;
			}
			case STAT_MINUS1:{
				if(c == '-'){
					state = STAT_MINUS2;
				}else{
					state = STAT_COMMENT;
				}
				break;
			}
			case STAT_MINUS2:{
				if(c == '>'){
					return;
				}else{
					state = STAT_COMMENT;
				}
			}
			default:break;
		}
	}

	return;
}

static void xml_parser_parse_pi(XmlParser* thiz)
{
	enum _State{
		STAT_NAME,
		STAT_ATTR,
		STAT_END
	}state = STAT_NAME;

	char* tag_name = NULL;
	const char* start = thiz->read_ptr;

	for(; *thiz->read_ptr != '\0'; thiz->read_ptr++){
		char c = *thiz->read_ptr;
	
		switch(state){
			case STAT_NAME:{
				if(isspace(c) || c == '>'){
					tag_name = (char*)xml_parser_strdup(thiz, start, thiz->read_ptr - start);
					state = c != '>' ? STAT_ATTR : STAT_END;
				}

				break;
			}
			case STAT_ATTR:{
				xml_parser_parse_attrs(thiz, '?');
				state = STAT_END;
				break;
			}
			default:break;
		}

		if(state == STAT_END)
		{
			break;
		}
	}
	
	tag_name = thiz->buffer + (size_t)tag_name;

	for(; *thiz->read_ptr != '>' && *thiz->read_ptr != '\0'; thiz->read_ptr++);

	return;
}

static void xml_parser_parse_text(XmlParser* thiz)
{
	const char* start = thiz->read_ptr - 1;
	for(; *thiz->read_ptr != '\0'; thiz->read_ptr++){
		char c = *thiz->read_ptr;

		if(c == '<'){
			if(thiz->read_ptr > start){
			}
			thiz->read_ptr--;
			return;
		}
		else if(c == '&'){
			xml_parser_parse_entity(thiz);
		}
	}

	return;
}

static void xml_parser_parse_entity(XmlParser* thiz)
{
	/*TODO*/

	return;
}

void xml_parser_destroy(XmlParser* thiz)
{
	if(thiz != NULL){
		free(thiz->buffer);
		free(thiz);
	}

	return;
}

static const char* strtrim(char* str)
{
	char* p = NULL;

	p = str + strlen(str) - 1;

	while(p != str && isspace(*p)){
		*p = '\0';
		p--;
	}

	p = str;
	while(*p != '\0' && isspace(*p)) p++; 
	if(p != str){
		char* s = p;
		char* d = str;
		while(*s != '\0'){
			*d = *s;
			d++;
			s++;
		}
		*d = '\0';
	}

	return str;
}

#ifdef XML_PARSER_TEST
#define XML "<?xml version=\"1.0\" encoding=\"utf-8\"?> \
<!--comment--> <br/> <p>ppp</p> <br />\
<programmer name=\"lixianjing\" blog=\"http://www.limodev.cn/blog\">text</programmer>"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>


char* read_file(const char* file_name){
	char* buffer = NULL;
	FILE* fp = fopen(file_name, "r");

	if(fp != NULL){
		struct stat st = {0};
		if(stat(file_name, &st) == 0){
			buffer = malloc(st.st_size + 1);
			fread(buffer, st.st_size, 1, fp);
			buffer[st.st_size] = '\0';
		}
	}

	return buffer;
}

int main(int argc, char* argv[])
{
	XmlParser* thiz = xml_parser_create();
	if(argc > 1){
		char* buffer = read_file(argv[1]);
		xml_parser_parse(thiz, buffer);
		free(buffer);
	}else{
		xml_parser_parse(thiz, XML);
	}
	xml_parser_destroy(thiz);

	return 0;
}
#endif/*XML_PARSER_TEST*/

all:
	gcc -g -m32 -Wall count_word.c -DCOUNT_WORD_TEST -o count_word_test
	gcc -g -m32 -Wall word_segmentation.c -DWORD_SEGMENTATION_TEST -o word_segmentation_test
	gcc -g -m32 -Wall parse_token.c -DPARSE_TOKEN_TEST -o parse_token_test
	gcc -g -m32 -Wall ini_parser.c -DINI_PARSER_TEST -o ini_parser_test
	gcc -g -m32 -Wall xml_parser.c -DXML_PARSER_TEST -o xml_parser_test

clean:
	rm -f *test

10.2 Builder模式

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

typedef void  (*DataDestroyFunc)(void* ctx, void* data);
typedef int   (*DataCompareFunc)(void* ctx, void* data);
typedef Ret   (*DataVisitFunc)(void* ctx, void* data);
typedef int   (*DataHashFunc)(void* data);

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);

#define MAX_ATTR_NR 64

#endif/*TYPEDEF_H*/
/*
 * File:    xml_builder.h
 */

#include "typedef.h"

#ifndef XML_BUILDER_H
#define XML_BUILDER_H

DECLS_BEGIN

struct _XmlBuilder;
typedef struct _XmlBuilder XmlBuilder;

typedef void (*XmlBuilderOnStartElementFunc)(XmlBuilder* thiz, const char* tag, const char** attrs);
typedef void (*XmlBuilderOnEndElementFunc)(XmlBuilder* thiz, const char* tag);
typedef void (*XmlBuilderOnTextFunc)(XmlBuilder* thiz, const char* text, size_t length);
typedef void (*XmlBuilderOnCommentFunc)(XmlBuilder* thiz, const char* text, size_t length);
typedef void (*XmlBuilderOnPiElementFunc)(XmlBuilder* thiz, const char* tag, const char** attrs);
typedef void (*XmlBuilderOnErrorFunc)(XmlBuilder* thiz, int line, int row, const char* message);
typedef void (*XmlBuilderDestroyFunc)(XmlBuilder* thiz);

struct _XmlBuilder
{
	XmlBuilderOnStartElementFunc on_start_element;
	XmlBuilderOnEndElementFunc   on_end_element;
	XmlBuilderOnTextFunc         on_text;
	XmlBuilderOnCommentFunc      on_comment;
	XmlBuilderOnPiElementFunc    on_pi_element;
	XmlBuilderOnErrorFunc        on_error;
	XmlBuilderDestroyFunc        destroy;

	char priv[1];
};

static inline void xml_builder_on_start_element(XmlBuilder* thiz, const char* tag, const char** attrs)
{
	return_if_fail(thiz != NULL && thiz->on_start_element != NULL);

	thiz->on_start_element(thiz, tag, attrs);

	return;
}

static inline void xml_builder_on_end_element(XmlBuilder* thiz, const char* tag)
{
	return_if_fail(thiz != NULL && thiz->on_end_element != NULL);

	thiz->on_end_element(thiz, tag);

	return;
}

static inline void xml_builder_on_text(XmlBuilder* thiz, const char* text, size_t length)
{
	return_if_fail(thiz != NULL && thiz->on_text != NULL);

	thiz->on_text(thiz, text, length);

	return;
}

static inline void xml_builder_on_comment(XmlBuilder* thiz, const char* text, size_t length)
{
	return_if_fail(thiz != NULL);

	if(thiz->on_comment != NULL){
		thiz->on_comment(thiz, text, length);
	}

	return;
}

static inline void xml_builder_on_pi_element(XmlBuilder* thiz, const char* tag, const char** attrs)
{
	return_if_fail(thiz != NULL);
	
	if(thiz->on_pi_element != NULL){
		thiz->on_pi_element(thiz, tag, attrs);
	}

	return;
}

static inline void xml_builder_on_error(XmlBuilder* thiz, int line, int row, const char* message)
{
	return_if_fail(thiz != NULL);

	if(thiz->on_error != NULL){
		thiz->on_error(thiz, line, row, message);
	}

	return;
}

static inline void xml_builder_destroy(XmlBuilder* thiz)
{
	if(thiz != NULL && thiz->destroy != NULL){
		thiz->destroy(thiz);
	}

	return;
}

DECLS_END

#endif/*XML_BUILDER_H*/

/*
 * File:    xml_builder_dump.h
 */

#ifndef XML_BUILDER_DUMP_H
#define XML_BUILDER_DUMP_H
#include "xml_builder.h"

DECLS_BEGIN

XmlBuilder* xml_builder_dump_create(FILE* fp);

DECLS_END

#endif/*XML_BUILDER_DUMP_H*/

/*
 * File:    xml_builder_dump.c
 */

#include "xml_builder_dump.h"

typedef struct _PrivInfo
{
	FILE* fp;
}PrivInfo;

static void xml_builder_dump_on_start_element(XmlBuilder* thiz, const char* tag, const char** attrs)
{
	int i = 0;
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	fprintf(priv->fp, "<%s", tag);

	for(i = 0; attrs != NULL && attrs[i] != NULL && attrs[i + 1] != NULL; i += 2){
		fprintf(priv->fp, " %s=\"%s\"", attrs[i], attrs[i + 1]);
	}
	fprintf(priv->fp, ">");

	return;
}

static void xml_builder_dump_on_end_element(XmlBuilder* thiz, const char* tag)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	fprintf(priv->fp, "</%s>\n", tag);

	return;
}

static void xml_builder_dump_on_text(XmlBuilder* thiz, const char* text, size_t length)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	fwrite(text, length, 1, priv->fp);

	return;
}

static void xml_builder_dump_on_comment(XmlBuilder* thiz, const char* text, size_t length)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	fprintf(priv->fp, "<!--");
	fwrite(text, length, 1, priv->fp);
	fprintf(priv->fp, "-->\n");

	return;
}

static void xml_builder_dump_on_pi_element(XmlBuilder* thiz, const char* tag, const char** attrs)
{
	int i = 0;
	PrivInfo* priv = (PrivInfo*)thiz->priv;
	fprintf(priv->fp, "<?%s", tag);

	for(i = 0; attrs != NULL && attrs[i] != NULL && attrs[i + 1] != NULL; i += 2)
	{
		fprintf(priv->fp, " %s=\"%s\"", attrs[i], attrs[i + 1]);
	}
	fprintf(priv->fp, "?>\n");

	return;
}

static void xml_builder_dump_on_error(XmlBuilder* thiz, int line, int row, const char* message)
{
	fprintf(stderr, "(%d,%d) %s\n", line, row, message);

	return;
}

static void xml_builder_dump_destroy(XmlBuilder* thiz)
{
	if(thiz != NULL){
		free(thiz);
	}

	return;
}

XmlBuilder* xml_builder_dump_create(FILE* fp)
{
	XmlBuilder* thiz = (XmlBuilder*)calloc(1, sizeof(XmlBuilder));

	if(thiz != NULL){
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->on_start_element = xml_builder_dump_on_start_element;
		thiz->on_end_element   = xml_builder_dump_on_end_element;
		thiz->on_text          = xml_builder_dump_on_text;
		thiz->on_comment       = xml_builder_dump_on_comment;
		thiz->on_pi_element    = xml_builder_dump_on_pi_element;
		thiz->on_error         = xml_builder_dump_on_error;
		thiz->destroy          = xml_builder_dump_destroy;

		priv->fp = fp != NULL ? fp : stdout;
	}

	return thiz;
}

#ifdef XML_BUILDER_DUMP_TEST
int main(int argc, char* argv[])
{
	const char* pi_attrs[] = {"version", "1.0", "encoding", "utf-8", NULL};
	const char* root_attrs[] = {"name", "lixianjing", "blog", "http://www.limodev.cn/blog",NULL};

	XmlBuilder* thiz = xml_builder_dump_create(stdout);

	xml_builder_on_pi_element(thiz, "xml", pi_attrs);
	xml_builder_on_comment(thiz,"comment", 6);
	xml_builder_on_start_element(thiz, "programmer", root_attrs);
	xml_builder_on_text(thiz,"text", 4);
	xml_builder_on_end_element(thiz, "programmer");

	xml_builder_destroy(thiz);

	return 0;
}
#endif/*XML_BUILDER_DUMP_TEST*/

all:
	gcc -g -m32 -Wall -DXML_BUILDER_DUMP_TEST xml_builder_dump.c -o xml_builder_dump_test
	gcc -g -m32 -Wall -DXML_PARSER_TEST xml_parser.c xml_builder_dump.c xml_builder_tree.c xml_tree.c xml_parser_test.c -o xml_parser_test
	gcc -g -m32 -Wall -DXML_TREE_TEST xml_tree.c xml_builder_dump.c -o xml_tree_test
	gcc -g -m32 -Wall -DXML_BUILDER_TREE_TEST xml_builder_tree.c xml_tree.c xml_builder_dump.c -o xml_builder_tree_test
clean:
	rm -f *test

10.3 管道过滤器模式

第十一章

第十二章 其他

宏定义中的特殊参数(#、##、...和__VA_ARGS__)

#

作用:宏展开(即宏替换)后,# 可以立即把其后的宏替换部分原封不动地进行字符串化.

##

名称:预处理拼接符,或者称其为宏拼接符
作用:用于类似函数的宏的替换部分,还可以用于类似对象的宏的替换部分。
      ##放在宏的替换部分的前面,用于宏展开(即宏替换)后,立即将宏中位于
      ##右边的宏替换部分与该宏中位于##左边的部分相拼接至一个整体。

#define XNAME(n) x##n
  // 宏调用 int XNAME(4) = 1;
  // 宏展开(即宏替换)后,我们得到: int x4 = 1;
  // 这也就体现出了##对其左右部分(即左x和右4)的拼接作用,最终拼接成x4:
#include <stdio.h>

#define P(A)      printf("%s:%d\n",#A,A);
#define SQUARE(x) printf("The square of "#x" is %d.\n", ((x)*(x)));

#define XNAME(n) x##n

int  main() 
{ 
	int a = 1, b = 2;
	int y =4;

	P(a);
	P(b);
	P(a+b);

	// #x被替换成字符串"y"    
	SQUARE(y); // printf("square of " "y" " is %d.\n",(y)*(y))
	// #x被替换成字符串"6-3" 
	SQUARE(6-3); // printf("square of " "6-3" " is %d.\n",(6-3)*(6-3))
	// #x被替换成字符串"y+3" 
        SQUARE(y+3); // printf("square of " "y+3" " is %d.\n",(y+3)*(y+3)) 

	printf("\n");
	int XNAME(_1)  = 4 ;
        SQUARE(x_1); // printf("square of " "x_4" " is %d.\n",(x_4)*(x_4)) 
        SQUARE(XNAME(_1)); // printf("square of " "x_4" " is %d.\n",(x_4)*(x_4)) 

}
在GNU C中,宏可以接受可变数目的参数,就象函数一样,例如:

    #define pr_debug(fmt,arg...) \
            printk(KERN_DEBUG fmt, ##arg)

用可变参数宏(variadic macros)传递可变参数表
你可能很熟悉在函数中使用可变参数表,如:

    void printf(const char* format, ...);
直到最近,可变参数表还是只能应用在真正的函数中,不能使用在宏中。

C99编译器标准终于改变了这种局面,
它允许你可以定义可变参数宏(variadic macros),这样你就可以使用拥有可以变化的参数表的宏。
可变参数宏就像下面这个样子:

    #define debug(...) printf(__VA_ARGS__)

缺省号代表一个可以变化的参数表。使用保留名 __VA_ARGS__ 把参数传递给宏。
当宏的调用展开时,实际的参数就传递给 printf()了。例如:

    Debug("Y = %d\n", y);

而预处理器会把宏的调用替换成:

    printf("Y = %d\n", y);

因为debug()是一个可变参数宏,你能在每一次调用中传递不同数目的参数:


    debug("test");    // 一个参数

可变参数宏不被ANSI/ISO C++ 所正式支持。因此,你应当检查你的编译器,看它是否支持这项技术。


用GCC和C99的可变参数宏, 更方便地打印调试信息

gcc的预处理提供的可变参数宏定义真是好用:


    #ifdef DEBUG
    #define dbgprint(format,args...) \
        fprintf(stderr, format, ##args)
    #else
        #define dbgprint(format,args...)
    #endif

如此定义之后,代码中就可以用dbgprint了,例如dbgprint("%s", __FILE__);

下面是C99的方法:

    #define dgbmsg(fmt,...)  printf(fmt,__VA_ARGS__)

新的C99规范支持了可变参数的宏
具体使用如下:

以下内容为程序代码:

    #include <stdarg.h>
    #include <stdio.h>
    #define LOGSTRINGS(fm, ...) printf(fm,__VA_ARGS__)
    int main()
    {
        LOGSTRINGS("hello, %d ", 10);
        return 0;
    }

但现在似乎只有gcc才支持。

可变参数的宏里的'##'操作说明带有可变参数的宏(Macros with a Variable Number of Arguments)
在1999年版本的ISO C 标准中,宏可以象函数一样,定义时可以带有可变参数。
宏的语法和函数的语法类似。下面有个例子:

    #define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)

这里,'...'指可变参数。
这类宏在被调用时,它(这里指'...')被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。
当被调用时,在宏体(macro body)中,那些符号序列集合将代替里面的__VA_ARGS__标识符。更多的信息可以参考CPP手册。
GCC始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,
如同其它参数一样。例如下面的例子:


    #define debug(format, args...) fprintf (stderr, format, args)

这和上面举的那个ISO C定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。
GNU CPP还有两种更复杂的宏扩展,支持上面两种格式的定义格式。
在标准C里,你不能省略可变参数,但是你却可以给它传递一个空的参数。例如,下面的宏调用在ISO C里是非法的,因为字符串后面没有逗号:
    debug ("A message")
GNU CPP在这种情况下可以让你完全的忽略可变参数。在上面的例子中,
编译器仍然会有问题(complain),因为宏展开后,里面的字符串后面会有个多余的逗号。

为了解决这个问题,CPP使用一个特殊的'##'操作。书写格式为:

    #define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)

这里,如果可变参数被忽略或为空,'##' 操作将使预处理器(preprocessor)去除掉它前面的那个逗号。
如果你在宏调用时,确实提供了一些可变参数,GNU CPP也会工作正常,它会把这些可变参数放到逗号的后面。

像其它的pasted macro参数一样,这些参数不是宏的扩展。
##还可以起到替换作用
如:

    #define FUN(IName)  IName##_ptr

这里将会把IName变成实际数据.

怎样写参数个数可变的宏
一种流行的技巧是用一个单独的用括弧括起来的的 ``参数" 定义和调用宏,
参数在 宏扩展的时候成为类似 printf() 那样的函数的整个参数列表。

    #define DEBUG(args) ( printf("DEBUG: "), printf args)

    if (n != 0) DEBUG(("n is %d\n", n));

明显的缺陷是调用者必须记住使用一对额外的括弧。
gcc 有一个扩展可以让函数式的宏接受可变个数的参数。
但这不是标准。另一种 可能的解决方案是根据参数个数使用多个宏 (DEBUG1, DEBUG2, 等等),
或者用逗号玩个这样的花招:

    #define DEBUG(args) (printf("DEBUG: "), printf(args))

    #define _ ,

    DEBUG("i = %d" _ i);

C99 引入了对参数个数可变的函数式宏的正式支持。在宏 ``原型" 的末尾加上符号 ... (就像在参数可变的函数定义中), 宏定义中的伪宏 __VA_ARGS__ 就会在调用是 替换成可变参数。
最后, 你总是可以使用真实的函数, 接受明确定义的可变参数

如果你需要替换宏, 使用一个 函数和一个非函数式宏, 如 #define printf myprintf

Indices and tables