Source FILE: CAlgCommon.h
#ifndef _C_ALG_COMMON_H_
#define _C_ALG_COMMON_H_
#include <string.h>
#include <stdlib.h>
#ifndef __cplusplus
#define inline __inline
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
CALG_ENUM_NEXT = 0,
CALG_ENUM_REPEAT ,
CALG_ENUM_STOP
}CAlgEnum;
typedef CAlgEnum (*Alg_IteRator_F)(void* elem);
typedef int (*Alg_Cmp_F)(const void* left, const void* right, unsigned int size);
#ifdef __cplusplus
}
#endif
#endif
//end of file
Source File: CAlgList.h
#ifndef _C_ALG_LIST_H_
#define _C_ALG_LIST_H_
#include <string.h>
#include <stdlib.h>
#include "CAlgCommon.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _CAlgNode{
void * curr_data;
struct _CAlgNode * prev;
struct _CAlgNode * next;
}CAlgNode;
typedef struct {
CAlgNode* head;
CAlgNode* tail;
int elem_count;
unsigned int elem_size;
}CAlgList;
static inline void CAlgList_ReSet(CAlgList* l, unsigned int elem_size)
{
l->head = l->tail = NULL;
l->elem_count = 0;
l->elem_size = elem_size;
}
static inline void CAlgList_Insert(CAlgList* l, CAlgNode* prev, CAlgNode* n)
{
n->prev = prev;
if(prev)
{
n->next = prev->next;
prev->next = n;
}
else
{
n->next = l->head;
l->head = n;
}
if(n->next)
n->next->prev = n;
if(prev == l->tail)
l->tail = n;
l->elem_count ++;
}
static inline CAlgNode* CAlgList_AddHead(CAlgList* l, CAlgNode* n)
{
CAlgList_Insert(l, NULL, n);
return l->head;
}
static inline CAlgNode* CAlgList_AddTail(CAlgList* l, CAlgNode* n)
{
CAlgList_Insert(l, l->tail, n);
return l->tail;
}
static inline CAlgNode* CAlgList_Find(CAlgList* l, void* data, Alg_Cmp_F node_cmp)
{
CAlgNode* tmp = l->head;
if(node_cmp == NULL)
node_cmp = memcmp;
while(tmp)
{
if(0 == node_cmp(tmp->curr_data, data, l->elem_size))
return tmp;
tmp = tmp->next;
}
return NULL;
}
static inline int CAlgList_RemoveNode(CAlgList* l, CAlgNode* n)
{
if( NULL == n) return -1;
if(n == l->head)
l->head = l->head->next;
if(n == l->tail)
l->tail = l->tail->prev;
if(n->prev)
n->prev->next = n->next;
if(n->next)
n->next->prev = n->prev;
if(n)
l->elem_count --;
return 0;
}
static inline CAlgNode* CAlgList_RemoveHead(CAlgList* l)
{
CAlgNode* head = l->head;
CAlgList_RemoveNode(l, l->head);
return head;
}
static inline CAlgNode* CAlgList_RemoveTail(CAlgList* l)
{
CAlgNode* tail = l->tail;
CAlgList_RemoveNode(l, l->tail);
return tail;
}
#define ALGLIST_FOREACH(alglist, node) do{\
node = alglist->head;\
for(; NULL != node; node=node->next){
#define ALGLIST_FOREACH_END() }}while(0);
static inline int CAlgList_Enum(const CAlgList* l, Alg_IteRator_F it, int reverse)
{
int count = 0u;
CAlgNode* tmp ;
CAlgEnum rc ;
if(reverse)
tmp = l->tail;
else
tmp = l->head;
while(tmp)
{
count ++;
rc = it(tmp->curr_data);
if(rc == CALG_ENUM_REPEAT)
continue;
else if(rc == CALG_ENUM_STOP)
return count;
if(reverse)
tmp = tmp->prev;
else
tmp = tmp->next;
}
return count;
}
#ifdef __cplusplus
}
#endif
#endif//end of file
单元测试:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "CAlgList.h"
typedef struct {
int a;
int b;
}CAlgListNodeData;
#define MAX_NODE_ELEM 10000000
static CAlgListNodeData* g_NodeDataPool = NULL;
static CAlgNode* g_CAlgNodes = NULL;
static CAlgList* g_CAlgList = NULL;
extern "C" CAlgEnum TestAlgList_Enum(void* elem)
{
CAlgListNodeData* e = (CAlgListNodeData*)elem;
printf("%5d, a=%5d, b=%5d\n", e - g_NodeDataPool, e->a, e->b);
return CALG_ENUM_NEXT;
}
extern "C" CAlgEnum TestAlgList_EnumNothing(void* elem)
{
return CALG_ENUM_NEXT;
}
extern "C" static int TestAlgList_node_cmp(const void* left, const void* right, unsigned int size)
{
CAlgListNodeData* l, *r;
l = (CAlgListNodeData*)left;
r = (CAlgListNodeData*)right;
if (l->a != r->a)
return l->a - r->a;
return l->b - r->b;
}
void TestAlgList_Init()
{
g_NodeDataPool = (CAlgListNodeData*)malloc(sizeof(CAlgListNodeData)*MAX_NODE_ELEM);
g_CAlgNodes = (CAlgNode*)malloc(sizeof(CAlgNode)*MAX_NODE_ELEM);
g_CAlgList = (CAlgList*)malloc(sizeof(CAlgList));
CAlgList_ReSet(g_CAlgList, sizeof(CAlgListNodeData));
}
void TestAlgList_Free()
{
free(g_NodeDataPool);
g_NodeDataPool = NULL;
free(g_CAlgNodes);
g_CAlgNodes = NULL;
free(g_CAlgList);
g_CAlgList = NULL;
}
void TestAlgList_AddAll_Pointer(int add_tail)
{
CAlgNode* n = g_CAlgNodes;
CAlgListNodeData* d = g_NodeDataPool;
int i;
for(i=0; i<MAX_NODE_ELEM; i++)
{
d->a = i+1;
d->b = i+2;
n[i].curr_data = (void*)d;
if(add_tail)
CAlgList_AddTail(g_CAlgList, &n[i]);
else
CAlgList_AddHead(g_CAlgList, &n[i]);
d++;
assert(g_CAlgList->elem_count == i +1);
}
i=0;
n = g_CAlgList->head;
do{
if(n == g_CAlgList->head)
{
assert(n->prev == NULL);
}
if(n == g_CAlgList->tail)
{
assert(n->next == NULL);
}
d = (CAlgListNodeData*)n->curr_data;
if(add_tail){
assert(d->a == i+1);
assert(d->b == i+2);
}
else
{
assert(d->a == MAX_NODE_ELEM - i);
assert(d->b == MAX_NODE_ELEM - i +1);
}
i++;
}while(n=n->next);
assert(i == MAX_NODE_ELEM);
assert(g_CAlgList->elem_count == MAX_NODE_ELEM);
}
void TestAlgList_RemoveHead()
{
CAlgNode* n = g_CAlgNodes;
CAlgListNodeData* d;
int i;
for(i=0; i<MAX_NODE_ELEM; i++)
{
n = CAlgList_RemoveHead( g_CAlgList);
d = (CAlgListNodeData*)n->curr_data;
assert(d->a == i+1);
assert(d->b == i+2);
assert(g_CAlgList->elem_count == MAX_NODE_ELEM - i -1);
}
assert(g_CAlgList->head == NULL);
assert(g_CAlgList->tail == NULL);
}
void TestAlgList_RemoveTail()
{
CAlgNode* n = g_CAlgNodes;
CAlgListNodeData* d;
int i;
for(i=0; i<MAX_NODE_ELEM; i++)
{
n = CAlgList_RemoveTail( g_CAlgList);
d = (CAlgListNodeData*)n->curr_data;
assert(d->a == i+1);
assert(d->b == i+2);
assert(g_CAlgList->elem_count == MAX_NODE_ELEM - i - 1);
}
assert(g_CAlgList->head == NULL);
assert(g_CAlgList->tail == NULL);
}
void TestAlgList_Insert_Remove()
{
const int node_num = 10;
CAlgNode* n = g_CAlgNodes;
CAlgListNodeData* d = g_NodeDataPool;
int i;
CAlgListNodeData tmp;
//list empty find fail
for(i=0; i<node_num/2; i++)
{
d = &g_NodeDataPool[node_num/2+i];
tmp.a = i+1;
tmp.b = i+2;
n = CAlgList_Find(g_CAlgList, &tmp, TestAlgList_node_cmp);
assert(n == NULL);
}
//list empty remove fail
assert (NULL == CAlgList_RemoveTail( g_CAlgList));
assert (NULL == CAlgList_RemoveHead( g_CAlgList));
assert (g_CAlgList->elem_count == 0);
//add node_num/2 nodes
for(i=0; i<node_num/2; i++)
{
d = &g_NodeDataPool[i];
d->a = i+1;
d->b = i+2;
g_CAlgNodes[i].curr_data = (void*)d;
CAlgList_AddTail( g_CAlgList, &g_CAlgNodes[i]);
assert(g_CAlgList->elem_count == i +1);
}
assert(g_CAlgList->elem_count == node_num/2);
printf("add 5 nodes using CAlgList_AddTail()\n");
CAlgList_Enum(g_CAlgList,TestAlgList_Enum,0);
//insert node_num/2 nodes into the list
//1, 2, 3, 4, 5
//1,1001, 2,1002, 3,1003, 4,1004, 5,1005
for(i=0; i<node_num/2; i++)
{
d = &g_NodeDataPool[node_num/2+i];
tmp.a = i+1;
tmp.b = i+2;
n = CAlgList_Find( g_CAlgList, &tmp, TestAlgList_node_cmp);
assert(n != NULL);
d->a = 1000+i+1;
d->b = 2000+i+1;
g_CAlgNodes[node_num/2+i].curr_data = d;
CAlgList_Insert(g_CAlgList, n, &g_CAlgNodes[node_num/2+i]);
}
printf("\nafter add 5 nodes using CAlgList_Insert()\n");
CAlgList_Enum(g_CAlgList,TestAlgList_Enum,0);
i=0;
n = g_CAlgList->head;
do{
if(n == g_CAlgList->head)
{
assert(n->prev == NULL);
}
if(n == g_CAlgList->tail)
{
assert(n->next == NULL);
}
d = (CAlgListNodeData*)n->curr_data;
if((i % 2) == 0)
{
assert(d->a == i/2+1);
assert(d->b == i/2+2);
}
else
{
assert(d->a == 1000+i/2+1);
assert(d->b == 2000+i/2+1);
}
i++;
}while(n=n->next);
assert(i == node_num);
assert(g_CAlgList->elem_count == node_num);
//remove node 1001,1002,1003,1004,1005
//before 1,1001, 2,1002, 3,1003, 4,1004, 5,1005
//after 1, 2, 3, 4, 5
for(i=0; i<node_num/2; i++)
{
tmp.a = 1000+i+1;
tmp.b = 2000+i+1;
n = CAlgList_Find( g_CAlgList, &tmp, TestAlgList_node_cmp);
assert(n != NULL);
assert(0 == CAlgList_RemoveNode( g_CAlgList, n));
}
printf("\nafter remove 5 nodes using CAlgList_RemoveNode\n");
CAlgList_Enum(g_CAlgList,TestAlgList_Enum,0);
assert(g_CAlgList->elem_count == node_num/2);
i=0;
n = g_CAlgList->head;
do{
if(n == g_CAlgList->head)
{
assert(n->prev == NULL);
}
if(n == g_CAlgList->tail)
{
assert(n->next == NULL);
}
d = (CAlgListNodeData*)n->curr_data;
assert(d->a == i+1);
assert(d->b == i+2);
i++;
}while(n=n->next);
//remove head 1
//after 2, 3, 4, 5
n = CAlgList_RemoveHead( g_CAlgList);
assert(n != NULL && g_CAlgList->elem_count > 2);
d = (CAlgListNodeData*)n->curr_data;
assert(d->a == 1);
assert(d->b == 2);
//remove tail 5
//after 2, 3, 4,
n = CAlgList_RemoveTail( g_CAlgList);
assert(n != NULL && g_CAlgList->elem_count > 2);
d = (CAlgListNodeData*)n->curr_data;
assert(d->a == 5);
assert(d->b == 6);
assert(g_CAlgList->elem_count == 3);
i=1;
n = g_CAlgList->head;
do{
if(n == g_CAlgList->head)
{
assert(n->prev == NULL);
}
if(n == g_CAlgList->tail)
{
assert(n->next == NULL);
}
d = (CAlgListNodeData*)n->curr_data;
assert(d->a == i+1);
assert(d->b == i+2);
i++;
}while(n=n->next);
assert(i == 4);
printf("\nafter CAlgList_RemoveHead && CAlgList_RemoveTail\n");
CAlgList_Enum(g_CAlgList,TestAlgList_Enum,0);
//remove all
while(CAlgList_RemoveHead( g_CAlgList))
printf("remove...\n");
assert(g_CAlgList->elem_count == 0);
}
#include <Windows.h>
void TestAlgList_Run()
{
SYSTEMTIME st1, st2;
FILETIME ft1, ft2; //100ns
CAlgNode* n;
int i;
TestAlgList_Init();
//test add head
GetLocalTime(&st1);
TestAlgList_AddAll_Pointer(1);
GetLocalTime(&st2);
SystemTimeToFileTime(&st1, &ft1);
SystemTimeToFileTime(&st2, &ft2);
printf("%s using %u.%03ums to add head %d nodes %02u:%02u:%02u.%03u - %02u:%02u:%02u.%03u\n",
__FILE__,
(ft2.dwLowDateTime-ft1.dwLowDateTime)/10000,
(ft2.dwLowDateTime-ft1.dwLowDateTime)/10, MAX_NODE_ELEM,
st1.wHour,st1.wMinute,st1.wSecond,st1.wMilliseconds,
st2.wHour,st2.wMinute,st2.wSecond,st2.wMilliseconds);
//iterate all elements
GetLocalTime(&st1);
CAlgList_Enum(g_CAlgList,TestAlgList_EnumNothing,0);
GetLocalTime(&st2);
SystemTimeToFileTime(&st1, &ft1);
SystemTimeToFileTime(&st2, &ft2);
printf("%s using %u.%03ums to iterate %d nodes %02u:%02u:%02u.%03u - %02u:%02u:%02u.%03u\n",
__FILE__,
(ft2.dwLowDateTime-ft1.dwLowDateTime)/10000,
(ft2.dwLowDateTime-ft1.dwLowDateTime)/10, MAX_NODE_ELEM,
st1.wHour,st1.wMinute,st1.wSecond,st1.wMilliseconds,
st2.wHour,st2.wMinute,st2.wSecond,st2.wMilliseconds);
i=0;
GetLocalTime(&st1);
ALGLIST_FOREACH(g_CAlgList, n);
i++;
ALGLIST_FOREACH_END();
GetLocalTime(&st2);
SystemTimeToFileTime(&st1, &ft1);
SystemTimeToFileTime(&st2, &ft2);
printf("%s using %u.%03ums to iterate %d nodes %02u:%02u:%02u.%03u - %02u:%02u:%02u.%03u\n",
__FILE__,
(ft2.dwLowDateTime-ft1.dwLowDateTime)/10000,
(ft2.dwLowDateTime-ft1.dwLowDateTime)/10, i,
st1.wHour,st1.wMinute,st1.wSecond,st1.wMilliseconds,
st2.wHour,st2.wMinute,st2.wSecond,st2.wMilliseconds);
//CAlgList_Enum(CAlgList_GetAlgFunc(),g_CAlgList,TestAlgList_Enum,0);
//remove all
TestAlgList_RemoveHead();
//test add tail
GetLocalTime(&st1);
TestAlgList_AddAll_Pointer(0);
GetLocalTime(&st2);
SystemTimeToFileTime(&st1, &ft1);
SystemTimeToFileTime(&st2, &ft2);
printf("%s using %u.%03ums to add tail %d nodes %02u:%02u:%02u.%03u - %02u:%02u:%02u.%03u\n",
__FILE__,
(ft2.dwLowDateTime-ft1.dwLowDateTime)/10000,
(ft2.dwLowDateTime-ft1.dwLowDateTime)/10, MAX_NODE_ELEM,
st1.wHour,st1.wMinute,st1.wSecond,st1.wMilliseconds,
st2.wHour,st2.wMinute,st2.wSecond,st2.wMilliseconds);
//CAlgList_Enum(CAlgList_GetAlgFunc(),g_CAlgList,TestAlgList_Enum,1);
TestAlgList_RemoveTail();
//test find and insert
CAlgList_ReSet(g_CAlgList, sizeof(CAlgListNodeData));
TestAlgList_Insert_Remove();
TestAlgList_Free();
}