diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am index 72550f3d..b0d5d5c3 100644 --- a/qse/include/qse/cmn/Makefile.am +++ b/qse/include/qse/cmn/Makefile.am @@ -2,7 +2,7 @@ pkgincludedir = $(includedir)/qse/cmn pkginclude_HEADERS = \ mem.h xma.h fma.h chr.h str.h lda.h htb.h rbt.h \ - rex.h sll.h dll.h opt.h tio.h \ + rex.h sll.h gdl.h dll.h opt.h tio.h \ fio.h pio.h sio.h time.h misc.h main.h stdio.h if ENABLE_CXX diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in index 2d0a093d..93c24dd9 100644 --- a/qse/include/qse/cmn/Makefile.in +++ b/qse/include/qse/cmn/Makefile.in @@ -52,8 +52,9 @@ CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = am__pkginclude_HEADERS_DIST = mem.h xma.h fma.h chr.h str.h lda.h \ - htb.h rbt.h rex.h sll.h dll.h opt.h tio.h fio.h pio.h sio.h \ - time.h misc.h main.h stdio.h Mmgr.hpp StdMmgr.hpp Mmged.hpp + htb.h rbt.h rex.h sll.h gdl.h dll.h opt.h tio.h fio.h pio.h \ + sio.h time.h misc.h main.h stdio.h Mmgr.hpp StdMmgr.hpp \ + Mmged.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ @@ -221,8 +222,8 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ pkginclude_HEADERS = mem.h xma.h fma.h chr.h str.h lda.h htb.h rbt.h \ - rex.h sll.h dll.h opt.h tio.h fio.h pio.h sio.h time.h misc.h \ - main.h stdio.h $(am__append_1) + rex.h sll.h gdl.h dll.h opt.h tio.h fio.h pio.h sio.h time.h \ + misc.h main.h stdio.h $(am__append_1) all: all-am .SUFFIXES: diff --git a/qse/include/qse/cmn/dll.h b/qse/include/qse/cmn/dll.h index 76280dbf..c895e561 100644 --- a/qse/include/qse/cmn/dll.h +++ b/qse/include/qse/cmn/dll.h @@ -1,5 +1,5 @@ /* - * $Id: dll.h 352 2010-08-31 13:20:34Z hyunghwan.chung $ + * $Id: dll.h 354 2010-09-03 12:50:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -21,162 +21,216 @@ #ifndef _QSE_CMN_DLL_H_ #define _QSE_CMN_DLL_H_ +/** @file + * This file defines a doubly linked list interface. + */ + #include #include +#include -/** - * The qse_dll_nhdr_t type defines a common node header fields used internally. - */ -typedef struct qse_dll_nhdr_t qse_dll_nhdr_t; -struct qse_dll_nhdr_t -{ - qse_dll_nhdr_t* next; - qse_dll_nhdr_t* prev; -}; - -#define __QSE_DLL_WRAP(x) do { x } while(0) +#define QSE_DLL_DEFINE(list_type,node_type,data_define,manage_define) \ + typedef struct list_type list_type; \ + typedef struct node_type node_type; \ + struct node_type \ + { \ + node_type* prev; \ + node_type* next; \ + data_define \ + }; \ + struct list_type \ + { \ + node_type gdl; \ + qse_size_t size; \ + manage_define \ + } #define QSE_DLL_TYPE(data_type) qse_dll_ ## data_type ## _t #define QSE_DLL_NODE_TYPE(data_type) qse_dll_ ## data_type ## _node_t /** - * The QSE_DLL_DEFINE macro defines a new doubly-linked list type for data + * The QSE_DLL_DEFINE_SIMPLE macro defines a doubly-linked list type for data * of the @a data_type type. */ -#define QSE_DLL_DEFINE(data_type) \ - typedef struct QSE_DLL_TYPE(data_type) QSE_DLL_TYPE(data_type); \ - typedef struct QSE_DLL_NODE_TYPE(data_type) QSE_DLL_NODE_TYPE(data_type); \ - struct QSE_DLL_NODE_TYPE(data_type) \ - { \ - QSE_DLL_NODE_TYPE(data_type)* next; \ - QSE_DLL_NODE_TYPE(data_type)* prev; \ - data_type data; \ - }; \ - struct QSE_DLL_TYPE(data_type) \ - { \ - QSE_DLL_NODE_TYPE(data_type) link; \ - } +#define QSE_DLL_DEFINE_SIMPLE(data_type) \ + QSE_DLL_DEFINE ( \ + QSE_DLL_TYPE(data_type), \ + QSE_DLL_NODE_TYPE(data_type), \ + data_type data;, \ + ) /** - * The QSE_DLL_DEFINE macro defines a new doubly-linked list type for data + * The QSE_DLL_DEFINE_MANAGED macro defines a doubly-linked list type for data * of the @a data_type type. */ #define QSE_DLL_DEFINE_MANAGED(data_type,manage_type) \ - typedef struct QSE_DLL_TYPE(data_type) QSE_DLL_TYPE(data_type); \ - typedef struct QSE_DLL_NODE_TYPE(data_type) QSE_DLL_NODE_TYPE(data_type); \ - struct QSE_DLL_NODE_TYPE(data_type) \ - { \ - QSE_DLL_NODE_TYPE(data_type)* next; \ - QSE_DLL_NODE_TYPE(data_type)* prev; \ - data_type data; \ - }; \ - struct QSE_DLL_TYPE(data_type) \ - { \ - QSE_DLL_NODE_TYPE(data_type) link; \ + QSE_DLL_DEFINE ( \ + QSE_DLL_TYPE(data_type), \ + QSE_DLL_NODE_TYPE(data_type), \ + data_type data;, \ manage_type data; \ - } + ) -#define QSE_DLL_INIT(dll) __QSE_DLL_WRAP ( \ - (dll)->link.next = &(dll)->link; \ - (dll)->link.prev = &(dll)->link; \ -) +#define QSE_DLL_INIT(dll) \ + QSE_BLOCK ( \ + QSE_GDL_INIT(&(dll)->gdl); \ + (dll)->size = 0; \ + ) -#define QSE_DLL_FINI(dll) __QSE_DLL_WRAP ( \ - while (!QSE_DLL_ISEMPTY(dll)) QSE_DLL_DELHEAD(dll); \ -) +#define QSE_DLL_FINI(dll) QSE_DLL_CLEAR(dll) -#define QSE_DLL_CHAIN(dll,p,x,n) __QSE_DLL_WRAP ( \ - register qse_dll_nhdr_t* __qse_dll_chain_prev = (qse_dll_nhdr_t*)(p); \ - register qse_dll_nhdr_t* __qse_dll_chain_next = (qse_dll_nhdr_t*)(n); \ - (x)->prev = (void*)__qse_dll_chain_prev; \ - (x)->next = (void*)__qse_dll_chain_next; \ - __qse_dll_chain_next->prev = (void*)(x); \ - __qse_dll_chain_prev->next = (void*)(x); \ -) +#define QSE_DLL_CHAIN(dll,p,x,n) \ + QSE_BLOCK ( \ + QSE_GDL_CHAIN ((qse_gdl_t*)p, (qse_gdl_t*)x, (qse_gdl_t*)n); \ + (dll)->size++; \ + ) -#define QSE_DLL_UNCHAIN(dll,x) __QSE_DLL_WRAP ( \ - register qse_dll_nhdr_t* __qse_dll_unchain_prev = \ - (qse_dll_nhdr_t*)((x)->prev); \ - register qse_dll_nhdr_t* __qse_dll_unchain_next = \ - (qse_dll_nhdr_t*)((x)->next); \ - __qse_dll_unchain_next->prev = __qse_dll_unchain_prev; \ - __qse_dll_unchain_prev->next = __qse_dll_unchain_next; \ -) +#define QSE_DLL_UNCHAIN(dll,x) \ + QSE_BLOCK ( \ + QSE_GDL_UNCHAIN ((qse_gdl_t*)x); \ + (dll)->size--; \ + ) -#define QSE_DLL_HEADNODE(dll) ((dll)->link.next) -#define QSE_DLL_TAILNODE(dll) ((dll)->link.prev) -#define QSE_DLL_NEXTNODE(dll,p) ((p)->next) -#define QSE_DLL_PREVNODE(dll,p) ((p)->prev) -#define QSE_DLL_ISVALIDNODE(dll,p) ((p) != &(dll)->link) +#define QSE_DLL_CLEAR(dll) \ + QSE_BLOCK ( \ + while (!QSE_DLL_ISEMPTY(dll)) QSE_DLL_DELHEAD(dll); \ + ) -#define QSE_DLL_ISEMPTY(dll) (QSE_DLL_HEADNODE(dll) == &(dll)->link) -#define QSE_DLL_ADDHEAD(dll,x) QSE_DLL_CHAIN(dll,&(dll)->link,x,QSE_DLL_HEADNODE(dll)) -#define QSE_DLL_ADDTAIL(dll,x) QSE_DLL_CHAIN(dll,QSE_DLL_TAILNODE(dll),x,&(dll)->link) -#define QSE_DLL_DELHEAD(dll) QSE_DLL_UNCHAIN(dll,QSE_DLL_HEADNODE(dll)) -#define QSE_DLL_DELTAIL(dll) QSE_DLL_UNCHAIN(dll,QSE_DLL_TAILNODE(dll)) - -/* - * Doubly Linked List +/** + * The QSE_DLL_ISEMPTY macro determines if a list @a dll is empty */ +#define QSE_DLL_ISEMPTY(dll) QSE_GDL_ISEMPTY(&(dll)->gdl) + +/** + * The QSE_DLL_ISMEMBER macro determines if a node @a x is a member + * of a list @a dll. + */ +#define QSE_DLL_ISMEMBER(dll,x) ((x) != &(dll)->gdl) + +#define QSE_DLL_HEAD(dll) QSE_GDL_HEAD(&(dll)->gdl) +#define QSE_DLL_TAIL(dll) QSE_GDL_TAIL(&(dll)->gdl) +#define QSE_DLL_SIZE(dll) ((dll)->size) + +/** + * The QSE_DLL_ADDHEAD macro add a member node @a x to the head of + * the list @a dll. + */ +#define QSE_DLL_ADDHEAD(dll,x) \ + QSE_DLL_CHAIN(dll,&(dll)->gdl,x,QSE_DLL_HEAD(dll)) + +/** + * The QSE_DLL_ADDHEAD macro add a member node @a x to the tail of + * the list @a dll. + */ +#define QSE_DLL_ADDTAIL(dll,x) \ + QSE_DLL_CHAIN(dll,QSE_DLL_TAIL(dll),x,&(dll)->gdl) + +/** + * The QSE_DLL_DELHEAD macro deletes the head node. + */ +#define QSE_DLL_DELHEAD(dll) \ + QSE_DLL_UNCHAIN(dll,QSE_DLL_HEAD(dll)) + +/** + * The QSE_DLL_DELTAIL macro deletes the tail node. + */ +#define QSE_DLL_DELTAIL(dll) \ + QSE_DLL_UNCHAIN(dll,QSE_DLL_TAIL(dll)) + + +/* ----------- more general implementation below ----------------- */ +enum qse_dll_walk_t +{ + QSE_DLL_WALK_STOP = 0, + QSE_DLL_WALK_FORWARD = 1, + QSE_DLL_WALK_BACKWARD = 2 +}; +typedef enum qse_dll_walk_t qse_dll_walk_t; + typedef struct qse_dll_t qse_dll_t; typedef struct qse_dll_node_t qse_dll_node_t; /* data copier */ -typedef void* (*qse_dll_copier_t) (qse_dll_t* dll, void* dptr, qse_size_t dlen); +typedef void* (*qse_dll_copier_t) ( + qse_dll_t* dll, + void* dptr, + qse_size_t dlen +); /* data freeer */ -typedef void (*qse_dll_freeer_t) (qse_dll_t* dll, void* dptr, qse_size_t dlen); +typedef void (*qse_dll_freeer_t) ( + qse_dll_t* dll, + void* dptr, + qse_size_t dlen +); + +/** + * The qse_dll_comper_t type defines a key comparator that is called when + * the list needs to compare data. A doubly linked list is created with a + * default comparator that performs bitwise comparison. + * + * The comparator must return 0 if the data are the same and a non-zero + * integer otherwise. + */ +typedef int (*qse_dll_comper_t) ( + qse_dll_t* dll, /**< doubly linked list */ + const void* dptr1, /**< data pointer */ + qse_size_t dlen1, /**< data length */ + const void* dptr2, /**< data pointer */ + qse_size_t dlen2 /**< data length */ +); /* node visitor */ -typedef int (*qse_dll_walker_t) ( - qse_dll_t* dll, qse_dll_node_t* node, void* arg); - -struct qse_dll_t -{ - qse_mmgr_t* mmgr; - - qse_dll_copier_t copier; - qse_dll_freeer_t freeer; - - qse_size_t size; - qse_dll_node_t* head; - qse_dll_node_t* tail; -}; +typedef qse_dll_walk_t (*qse_dll_walker_t) ( + qse_dll_t* dll, + qse_dll_node_t* node, + void* ctx +); +/** + * The qse_dll_node_t type defines a doubly linked list node. + */ struct qse_dll_node_t { - void* dptr; /* pointer to the beginning of data */ - qse_size_t dlen; /* length of data in bytes */ - qse_dll_node_t* next; /* pointer to the next node */ - qse_dll_node_t* prev; /* pointer to the prev node */ + /* the first two fields in sync with qse_gdl_t */ + qse_dll_node_t* prev; + qse_dll_node_t* next; + + void* dptr; /**< data pointer */ + qse_size_t dlen; /**< data length */ }; - -enum qse_dll_walk_t +/** + * The qse_dll_t type defines a doubly linked list. + */ +struct qse_dll_t { - QSE_DLL_WALK_STOP = 0, - QSE_DLL_WALK_FORWARD = 1 + QSE_DEFINE_COMMON_FIELDS (dll) + + qse_dll_node_t gdl; + qse_size_t size; + + qse_byte_t scale; + qse_dll_copier_t copier; + qse_dll_freeer_t freeer; + qse_dll_comper_t comper; }; -#define QSE_DLL_COPIER_INLINE qse_dll_copyinline +#define QSE_DLL_COPIER_SIMPLE ((qse_dll_copier_t)1) +#define QSE_DLL_COPIER_INLINE ((qse_dll_copier_t)2) -#define QSE_DLL_HEAD(dll) ((dll)->head) -#define QSE_DLL_TAIL(dll) ((dll)->tail) -#define QSE_DLL_SIZE(dll) ((dll)->size) +#define QSE_DLL_SCALE(dll) ((dll)->scale) +#define QSE_DLL_DPTR(node) ((node)->dptr) +#define QSE_DLL_DLEN(node) ((node)->dlen) -#define QSE_DLL_DPTR(n) ((n)->dptr) -#define QSE_DLL_DLEN(n) ((n)->dlen) -#define QSE_DLL_NEXT(n) ((n)->next) -#define QSE_DLL_PREV(n) ((n)->prev) #ifdef __cplusplus extern "C" { #endif -/* - * NAME: creates a doubly linked list with extension area - * - * DESCRIPTION: +QSE_DEFINE_COMMON_FUNCTIONS (dll) + +/** * The qse_dll_open() function creates an empty doubly linked list. * If the memory manager mmgr is QSE_NULL, the function gets the default * memory manager with QSE_MMGR_GETMMGR() and uses it if it is not QSE_NULL. @@ -185,141 +239,175 @@ extern "C" { * after initializing the main area. The extension initializer is passed * the pointer to the doubly linked list created. * - * RETURNS: + * @return * the pointer to a newly created doubly linked list on success. * QSE_NULL on failure. - * - * WARNING: - * In the debug build, it fails the assertion if QSE_MMGR_SETMMGR() returns - * QSE_NULL when QSE_NULL is passed as the first parameter. In the release - * build, it returns QSE_NULL if such a thing happens. */ - qse_dll_t* qse_dll_open ( - qse_mmgr_t* mmgr /* memory manager */ , - qse_size_t ext /* size of extension area in bytes */ + qse_mmgr_t* mmgr, /**< memory manager */ + qse_size_t xtnsize /**< size of extension area in bytes */ ); -/* - * NAME destroys a singly linked list +/** + * The qse_dll_close() function destroys a doubly linked list. */ void qse_dll_close ( - qse_dll_t* dll /* a singly linked list */ + qse_dll_t* dll /** doubly linked list */ ); -/* - * NAME deletes all elements of a singly linked list +/** + * The qse_dll_init() function initializes a statically declared list. */ -void qse_dll_clear ( - qse_dll_t* dll /* a singly linked list */ +qse_dll_t* qse_dll_init ( + qse_dll_t* dll, /**< doubly linked list */ + qse_mmgr_t* mmgr /**< memory manager */ ); -/* - * NAME specifies how to clone an element - * - * DESCRIPTION - * A special copier QSE_DLL_COPIER_INLINE is provided. This copier enables - * you to copy the data inline to the internal node. No freeer is invoked - * when the node is freeed. - * - * You may set the copier to QSE_NULL to perform no special operation - * when the data pointer is rememebered. +/** + * The qse_dll_fini() function finalizes a statically initialized list. + */ +void qse_dll_fini ( + qse_dll_t* dll /**< doubly linked list */ +); + +/** + * The qse_dll_getscale() function gets the scale factor + */ +int qse_dll_getscale ( + qse_dll_t* dll /**< doubly linked list */ +); + +/** + * The qse_dll_setscale() function sets the scale factor of the data length. + * A scale factor determines the actual length of data in bytes. A doubly + * linked list created with a scale factor of 1. The scale factor should be + * larger than 0 and less than 256. + */ +void qse_dll_setscale ( + qse_dll_t* dll, /**< doubly linked list */ + int scale /**< scale factor */ +); + +/** + * The qse_dll_setcopier() function changes the element copier. + * A special copier QSE_DLL_COPIER_INLINE is provided. This copier enables + * you to copy the data inline to the internal node. No freeer is invoked + * when the node is freeed. You may set the copier to QSE_NULL to perform + * no special operation when the data pointer is rememebered. */ void qse_dll_setcopier ( - qse_dll_t* dll /* a singly linked list */, - qse_dll_copier_t copier /* a element copier */ + qse_dll_t* dll, /**< doubly linked list */ + qse_dll_copier_t copier /**< element copier */ ); +/** + * The qse_dll_getcopier() function returns the element copier. + */ qse_dll_copier_t qse_dll_getcopier ( - qse_dll_t* dll /* a singly linked list */ + qse_dll_t* dll /**< doubly linked list */ ); -/* - * NAME specifies how to destroy an element - * - * DESCRIPTION - * The freeer is called when a node containing the element is destroyed. +/** + * The qse_dll_setfreeer() function changes the element freeer. + * The freeer is called when a node containing the element is destroyed. */ void qse_dll_setfreeer ( - qse_dll_t* dll /* a singly linked list */, - qse_dll_freeer_t freeer /* a element freeer */ + qse_dll_t* dll, /**< doubly linked list */ + qse_dll_freeer_t freeer /**< element freeer */ ); +/** + * The qse_dll_getfreeer() function returns the element freeer. + */ qse_dll_freeer_t qse_dll_getfreeer ( - qse_dll_t* dll /* a singly linked list */ + qse_dll_t* dll /**< doubly linked list */ ); -/* - * NAME Gets the pointer to the extension area - * RETURN the pointer to the extension area - */ -void* qse_dll_getxtn ( - qse_dll_t* dll /* a singly linked list */ -); - -/* - * NAME: get the pointer to the memory manager in use - */ -qse_mmgr_t* qse_dll_getmmgr ( - qse_dll_t* dll /* a singly linked list */ -); - -void qse_dll_setmmgr (qse_dll_t* dll, qse_mmgr_t* mmgr); - -/* - * NAME Gets the number of elements held in a singly linked list - * RETURN the number of elements the list holds +/** + * The qse_dll_getsize() function returns the number of the data nodes held + * in a doubly linked list. */ qse_size_t qse_dll_getsize ( - qse_dll_t* dll /* a singly linked list */ + qse_dll_t* dll /**< doubly linked list */ ); -/* - * NAME Gets the head(first) node - * RETURN the tail node of a singly linked list +/** + * The qse_dll_gethead() function gets the head node. You may use the + * #QSE_DLL_HEAD macro instead. */ qse_dll_node_t* qse_dll_gethead ( - qse_dll_t* dll /* a singly linked list */ + qse_dll_t* dll /**< doubly linked list */ ); -/* - * NAME Gets the tail(last) node - * RETURN the tail node of a singly linked list +/** + * The qse_dll_gettail() function gets the head node. You may use the + * #QSE_DLL_TAIL macro instead. */ qse_dll_node_t* qse_dll_gettail ( - qse_dll_t* dll /* a singly linked list */ + qse_dll_t* dll /**< doubly linked list */ ); -/* - * NAME Inserts data before a positional node given - * - * DESCRIPTION - * Inserts data. + +qse_dll_node_t* qse_dll_search ( + qse_dll_t* dll, /**< doubly linked list */ + qse_dll_node_t* pos, /**< positional node */ + const void* dptr, /**< data pointer */ + qse_size_t dlen /**< data length */ +); + +qse_dll_node_t* qse_dll_rsearch ( + qse_dll_t* dll, /**< doubly linked list */ + qse_dll_node_t* pos, /**< positional node */ + const void* dptr, /**< data pointer */ + qse_size_t dlen /**< data length */ +); + +/** + * The qse_dll_insert() function insert an element into a list */ qse_dll_node_t* qse_dll_insert ( - qse_dll_t* dll /* a singly linked list */, - qse_dll_node_t* pos /* a node before which a new node is inserted */, - void* dptr /* the pointer to the data */ , - qse_size_t dlen /* the length of the data in bytes */ + qse_dll_t* dll, /**< doubly linked list */ + qse_dll_node_t* pos, /**< node before which a new node is inserted */ + void* dptr, /**< data pointer */ + qse_size_t dlen /**< data length */ +); + +void qse_dll_delete ( + qse_dll_t* dll, + qse_dll_node_t* pos +); + +/** + * The qse_dll_clear() functions deletes all elements of a list + */ +void qse_dll_clear ( + qse_dll_t* dll /**< doubly linked list */ +); + +void qse_dll_walk ( + qse_dll_t* dll, /**< doubly linked list */ + qse_dll_walker_t walker, /**< user-defined walker function */ + void* ctx /**< pointer to user-defined data */ +); + +void qse_dll_rwalk ( + qse_dll_t* dll, /**< doubly linked list */ + qse_dll_walker_t walker, /**< user-defined walker function */ + void* ctx /**< pointer to user-defined data */ ); qse_dll_node_t* qse_dll_pushhead ( - qse_dll_t* dll /* a singly linked list */, - void* dptr, + qse_dll_t* dll, /* doubly linked list */ + void* dptr, qse_size_t dlen ); qse_dll_node_t* qse_dll_pushtail ( - qse_dll_t* dll /* a singly linked list */, - void* dptr, + qse_dll_t* dll, /* doubly linked list */ + void* dptr, qse_size_t dlen ); -void qse_dll_delete ( - qse_dll_t* dll, - qse_dll_node_t* pos -); - void qse_dll_pophead ( qse_dll_t* dll ); @@ -328,36 +416,6 @@ void qse_dll_poptail ( qse_dll_t* dll ); -/* - * NAME Traverses s singly linked list - * - * DESCRIPTION - * A singly linked list allows uni-directional in-order traversal. - * The qse_dll_walk() function traverses a singly linkked list from its - * head node down to its tail node as long as the walker function returns - * QSE_DLL_WALK_FORWARD. A walker can return QSE_DLL_WALK_STOP to cause - * immediate stop of traversal. - * For each node, the walker function is called and it is passed three - * parameters: the singly linked list, the visiting node, and the - * user-defined data passed as the third parameter in a call to the - * qse_dll_walk() function. - */ -void qse_dll_walk ( - qse_dll_t* dll /* a singly linked list */, - qse_dll_walker_t walker /* a user-defined walker function */, - void* arg /* pointer to user-defined data */ -); - -/* - * Causes a singly linked list to copy in data to a node. - * Use QSE_DLL_COPIER_INLINE instead. - */ -void* qse_dll_copyinline ( - qse_dll_t* dll /* a singly linked list */, - void* data /* pointer to data to copy */ , - qse_size_t len /* length of data in bytes */ -); - #ifdef __cplusplus } #endif diff --git a/qse/include/qse/cmn/gdl.h b/qse/include/qse/cmn/gdl.h new file mode 100644 index 00000000..e186fc84 --- /dev/null +++ b/qse/include/qse/cmn/gdl.h @@ -0,0 +1,70 @@ +/* + * $Id$ + */ + +#ifndef _QSE_CMN_GDL_H_ +#define _QSE_CMN_GDL_H_ + +/** @file + * This file defins a generic double link and provides basic macros to + * manipulate a chain of links. + */ + +/** + * The qse_gdl_t type defines a structure to contain forward and + * backward links. + */ +typedef struct qse_gdl_t qse_gdl_t; +struct qse_gdl_t +{ + qse_gdl_t* prev; + qse_gdl_t* next; +}; + +/** + * The QSE_GDL_INIT macro initializes a host link to be used for internal + * management. + */ +#define QSE_GDL_INIT(host) QSE_BLOCK ( \ + (host)->next = (host); (host)->prev = (host); \ +) + +/** + * The QSE_GDL_CHAIN macro chains a new member node @a x between + * two nodes @a p and @a n. + */ +#define QSE_GDL_CHAIN(p,x,n) qse_gdl_chain(p,x,n) + +/** + * The QSE_GDL_UNCHAIN macro unchains a member node @a x. + */ +#define QSE_GDL_UNCHAIN(x) qse_gdl_unchain(x) + +/** + * The QSE_GDL_ISEMPTY macro checks if the chain is empty. + */ +#define QSE_GDL_ISEMPTY(host) ((host)->next == (host)) + +/** + * The QSE_GDL_HEAD macro get the first node in the chain. + */ +#define QSE_GDL_HEAD(host) ((host)->next) + +/** + * The QSE_GDL_TAIL macro gets the last node in the chain. + */ +#define QSE_GDL_TAIL(host) ((host)->prev) + + +#ifdef __cplusplus +extern "C" { +#endif + +void qse_gdl_chain (qse_gdl_t* p, qse_gdl_t* x, qse_gdl_t* n); +void qse_gdl_unchain (qse_gdl_t* x); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/include/qse/cmn/htb.h b/qse/include/qse/cmn/htb.h index 0991c6bc..456efac8 100644 --- a/qse/include/qse/cmn/htb.h +++ b/qse/include/qse/cmn/htb.h @@ -1,5 +1,5 @@ /* - * $Id: htb.h 341 2010-08-04 07:25:48Z hyunghwan.chung $ + * $Id: htb.h 354 2010-09-03 12:50:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -38,7 +38,7 @@ typedef struct qse_htb_pair_t qse_htb_pair_t; */ enum qse_htb_walk_t { - QSE_HTB_WALK_STOP = 0, + QSE_HTB_WALK_STOP = 0, QSE_HTB_WALK_FORWARD = 1 }; typedef enum qse_htb_walk_t qse_htb_walk_t; diff --git a/qse/include/qse/cmn/map.h b/qse/include/qse/cmn/map.h index d476540b..4dc16b58 100644 --- a/qse/include/qse/cmn/map.h +++ b/qse/include/qse/cmn/map.h @@ -58,7 +58,7 @@ # define qse_map_clear(map) qse_htb_clear(map) # define qse_map_walk(map,walker,ctx) qse_htb_walk(map,walker,ctx) # define QSE_MAP_WALK_STOP QSE_HTB_WALK_STOP -# define QSE_MAP_WALK_FORWARD QSE_HTB_WALK_FORWARD +# define QSE_MAP_WALK_FORWARD QSE_HTB_WALK_FORWARD # define qse_map_walk_t qse_htb_walk_t # define QSE_MAP_KEY QSE_HTB_KEY # define QSE_MAP_VAL QSE_HTB_VAL @@ -111,7 +111,7 @@ # define qse_map_clear(map) qse_rbt_clear(map) # define qse_map_walk(map,walker,ctx) qse_rbt_walk(map,walker,ctx) # define QSE_MAP_WALK_STOP QSE_RBT_WALK_STOP -# define QSE_MAP_WALK_FORWARD QSE_RBT_WALK_FORWARD +# define QSE_MAP_WALK_FORWARD QSE_RBT_WALK_FORWARD # define qse_map_walk_t qse_rbt_walk_t # define QSE_MAP_KEY QSE_RBT_KEY # define QSE_MAP_VAL QSE_RBT_VAL diff --git a/qse/include/qse/cmn/rbt.h b/qse/include/qse/cmn/rbt.h index d4219b29..f18ff390 100644 --- a/qse/include/qse/cmn/rbt.h +++ b/qse/include/qse/cmn/rbt.h @@ -37,7 +37,7 @@ typedef struct qse_rbt_pair_t qse_rbt_pair_t; */ enum qse_rbt_walk_t { - QSE_RBT_WALK_STOP = 0, + QSE_RBT_WALK_STOP = 0, QSE_RBT_WALK_FORWARD = 1 }; typedef enum qse_rbt_walk_t qse_rbt_walk_t; diff --git a/qse/include/qse/cmn/sll.h b/qse/include/qse/cmn/sll.h index 1bd21ea6..2611b02d 100644 --- a/qse/include/qse/cmn/sll.h +++ b/qse/include/qse/cmn/sll.h @@ -1,5 +1,5 @@ /* - * $Id: sll.h 328 2010-07-08 06:58:44Z hyunghwan.chung $ + * $Id: sll.h 354 2010-09-03 12:50:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -25,7 +25,7 @@ #include /** @file - * Singly linked list + * This file provides a singly linked list interface. */ /** @@ -33,13 +33,14 @@ */ enum qse_sll_walk_t { - QSE_SLL_WALK_STOP = 0, /**< stop traversal */ - QSE_SLL_WALK_FORWARD = 1 /**< traverse to the next node */ + QSE_SLL_WALK_STOP = 0, /**< stop traversal */ + QSE_SLL_WALK_FORWARD = 1 /**< traverse to the next node */ }; +typedef enum qse_sll_walk_t qse_sll_walk_t; + typedef struct qse_sll_t qse_sll_t; typedef struct qse_sll_node_t qse_sll_node_t; -typedef enum qse_sll_walk_t qse_sll_walk_t; /** * The qse_sll_copier_t type defines a callback function for node construction. @@ -89,16 +90,15 @@ typedef int (*qse_sll_comper_t) ( * The qse_sll_walker_t type defines a list traversal callback for each node. * The qse_sll_walk() calls a callback function of the type qse_sll_walker_t * for each node until it returns QSE_SLL_WALK_STOP. The walker should return - * QSE_SLL_WALK_FORWARD to let qse_sll_walk() continue visiting the next node. + * QSE_SLL_WALK_FORWARD to let qse_sll_walk() continue visiting the next node. * The third parameter to qse_sll_walk() is passed to the walker as the third * parameter. */ typedef qse_sll_walk_t (*qse_sll_walker_t) ( - qse_sll_t* sll, /* singly linked list */ - qse_sll_node_t* node, /* visited node */ - void* arg /* user-defined data */ + qse_sll_t* sll, /**< singly linked list */ + qse_sll_node_t* node, /**< visited node */ + void* ctx /**< user-defined data */ ); -/******/ /** * The qse_sll_t type defines a singly lnked list. @@ -183,203 +183,128 @@ qse_sll_t* qse_sll_open ( qse_size_t ext /* size of extension area in bytes */ ); -/****f* Common/qse_sll_close - * NAME - * qse_sll_close - destroy a singly linked list - * - * DESCRIPTION - * The qse_sll_close() function destroys a singly linked list freeing up - * the memory. - * - * SYNOPSIS +/** + * The qse_sll_close() function destroys a singly linked list freeing up + * the memory. */ void qse_sll_close ( - qse_sll_t* sll /* a singly linked list */ + qse_sll_t* sll /**< singly linked list */ ); -/******/ -/****f* Common/qse_sll_init - * NAME - * qse_sll_init - initialize a singly linked list - * - * DESCRIPTION - * The qse_sll_init() function initializes a singly linked list. The memory - * should be allocated by a caller and be passed to it. The caller may declare - * a static variable of the qse_sll_t type and pass its address. A memory - * manager still needs to be passed for node manipulation later. +/** + * The qse_sll_init() function initializes a statically declared singly + * linked list. The memory should be allocated by a caller and be passed + * to it. The caller may declare a static variable of the qse_sll_t type + * and pass its address. A memory manager still needs to be passed for + * node manipulation later. * - * RETURN + * @return * The qse_sll_init() function returns the first parameter on success and * QSE_NULL on failure. - * - * SYNOPSIS */ qse_sll_t* qse_sll_init ( - qse_sll_t* sll /* an uninitialized singly linked list */, - qse_mmgr_t* mmgr /* a memory manager */ + qse_sll_t* sll, /* singly linked list */ + qse_mmgr_t* mmgr /* memory manager */ ); -/******/ -/****f* Common/qse_sll_fini - * NAME - * qse_sll_init - deinitialize a singly linked list - * - * SYNOPSIS +/** + * The qse_sll_fini() function finalizes a statically initialized list. */ void qse_sll_fini ( - qse_sll_t* sll /* a singly linked list */ + qse_sll_t* sll /**< singly linked list */ ); -/******/ -/****f* Common/qse_sll_getsize - * NAME - * qse_sll_getsize - get the number of nodes - * - * DESCRIPTION - * The qse_sll_getsize() function returns the number of the data nodes held - * in a singly linked list. - * - * SYNOPSIS - */ -qse_size_t qse_sll_getsize ( - qse_sll_t* sll /* a singly linked list */ -); -/******/ - - -/****f* Common/qse_sll_getscale - * NAME - * qse_sll_getscale - get the scale factor - * - * SYNOPSIS +/** + * The qse_sll_getscale() function gets the scale factor */ int qse_sll_getscale ( - qse_sll_t* sll /* a singly linked list */ + qse_sll_t* sll /**< singly linked list */ ); -/******/ -/****f* Common/qse_sll_setscale - * NAME - * qse_sll_setscale - set the scale factor - * - * DESCRIPTION +/** * The qse_sll_setscale() function sets the scale factor of the data length. * A scale factor determines the actual length of data in bytes. A singly * linked list created with a scale factor of 1. The scale factor should be * larger than 0 and less than 256. - * - * NOTES - * It is a bad idea to change the scale factor when a sll is not empty. - * - * SYNOPSIS */ void qse_sll_setscale ( - qse_sll_t* sll /* a singly linked list */, - int scale /* a scale factor */ + qse_sll_t* sll, /**< singly linked list */ + int scale /**< scale factor */ ); -/******/ -/****f* Common/qse_sll_getcopier - * NAME - * qse_sll_getfreeer - get the data copier - * - * SYNOPSIS +/** + * The qse_sll_getfreeer() function gets the data copier. */ qse_sll_copier_t qse_sll_getcopier ( - qse_sll_t* sll /* a singly linked list */ + qse_sll_t* sll /* singly linked list */ ); -/******/ -/****f* Common/qse_sll_setcopier - * NAME - * qse_sll_setcopier - set a data copier - * - * DESCRIPTION - * A special copier QSE_SLL_COPIER_INLINE is provided. This copier enables - * you to copy the data inline to the internal node. No freeer is invoked - * when the node is freeed. - * - * You may set the copier to QSE_NULL to perform no special operation - * when the data pointer is rememebered. - * - * SYNOPSIS +/** + * The qse_sll_setcopier() function changes the element copier. + * A special copier QSE_SLL_COPIER_INLINE is provided. This copier enables + * you to copy the data inline to the internal node. No freeer is invoked + * when the node is freeed. You may set the copier to QSE_NULL to perform + * no special operation when the data pointer is rememebered. */ void qse_sll_setcopier ( - qse_sll_t* sll /* a singly linked list */, - qse_sll_copier_t copier /* a data copier */ + qse_sll_t* sll, /**< singly linked list */ + qse_sll_copier_t copier /**< data copier */ ); -/******/ -/****f* Common/qse_sll_getfreeer - * NAME - * qse_sll_getfreeer - get the data freeer - * - * SYNOPSIS +/** + * The qse_sll_getfreeer() function returns the element freeer. */ qse_sll_freeer_t qse_sll_getfreeer ( - qse_sll_t* sll /* a singly linked list */ + qse_sll_t* sll /**< singly linked list */ ); -/******/ -/****f* Common/qse_sll_setfreeer - * NAME - * qse_sll_setfreeer - set a data freeer - * - * DESCRIPTION - * The freeer is called when a node containing the element is destroyed. - * - * SYNOPSIS +/** + * The qse_sll_setfreeer() function changes the element freeer. + * The freeer is called when a node containing the element is destroyed. */ void qse_sll_setfreeer ( - qse_sll_t* sll /* a singly linked list */, - qse_sll_freeer_t freeer /* a data freeer */ + qse_sll_t* sll, /**< singly linked list */ + qse_sll_freeer_t freeer /**< data freeer */ ); -/******/ -/****f* Common/qse_sll_getcomper - * NAME - * qse_sll_getcomper - get the data comparator - * - * SYNOPSIS +/** + * The qse_sll_getcomper() function returns the data comparator. */ qse_sll_comper_t qse_sll_getcomper ( - qse_sll_t* sll /* a singly linked list */ + qse_sll_t* sll /**< singly linked list */ ); -/******/ -/****f* Common/qse_sll_setcomper - * NAME - * qse_sll_setcomper - set the data comparator - * - * SYNOPSIS +/** + * The qse_sll_setcomper() function changes the data comparator */ void qse_sll_setcomper ( - qse_sll_t* sll /* a singly linked list */, - qse_sll_comper_t comper /* a comparator */ + qse_sll_t* sll /**< singly linked list */, + qse_sll_comper_t comper /**< comparator */ ); -/******/ -/****f* Common/qse_sll_gethead - * NAME - * qse_sll_gethead - get the head node - * - * SYNOPSIS +/** + * The qse_sll_getsize() function returns the number of the data nodes held + * in a singly linked list. + */ +qse_size_t qse_sll_getsize ( + qse_sll_t* sll /** singly linked list */ +); + +/** + * The qse_sll_gethead() function gets the head node. You may use the + * #QSE_SLL_HEAD macro instead. */ qse_sll_node_t* qse_sll_gethead ( - qse_sll_t* sll /* a singly linked list */ + qse_sll_t* sll /**< a singly linked list */ ); -/******/ -/****f* Common/qse_sll_gettail - * NAME - * qse_sll_gettail - get the tail node - * - * SYNOPSIS +/** + * The qse_sll_gettail() function gets the head node. You may use the + * #QSE_SLL_TAIL macro instead. */ qse_sll_node_t* qse_sll_gettail ( - qse_sll_t* sll /* a singly linked list */ + qse_sll_t* sll /**< singly linked list */ ); -/******/ /** * The qse_sll_search() function traverses a list to find a node containing @@ -387,8 +312,8 @@ qse_sll_node_t* qse_sll_gettail ( * from the next node of the positional node. If the positional node is * QSE_NULL, the traversal begins from the head node. * - * Note that no reverse search is provided because a reverse traversal can not be - * achieved efficiently. + * Note that no reverse search is provided because a reverse traversal can not + * be achieved efficiently. * * @return pointer to the node found. QSE_NULL if no match is found */ @@ -430,31 +355,10 @@ void qse_sll_clear ( qse_sll_t* sll /**< singly linked list */ ); -qse_sll_node_t* qse_sll_pushhead ( - qse_sll_t* sll /**< singly linked list */, - void* dptr, - qse_size_t dlen -); - -qse_sll_node_t* qse_sll_pushtail ( - qse_sll_t* sll /**< singly linked list */, - void* dptr, - qse_size_t dlen -); - - -void qse_sll_pophead ( - qse_sll_t* sll -); - -void qse_sll_poptail ( - qse_sll_t* sll -); - /** * The qse_sll_walk() function traverses a singly linkked list from its * head node down to its tail node as long as the walker function returns - * QSE_SLL_WALK_FORWARD. A walker can return QSE_SLL_WALK_STOP to cause + * QSE_SLL_WALK_FORWARD . A walker can return QSE_SLL_WALK_STOP to cause * immediate stop of traversal. * * For each node, the walker function is called and it is passed three @@ -468,6 +372,26 @@ void qse_sll_walk ( void* ctx /**< the pointer to user-defined data */ ); +qse_sll_node_t* qse_sll_pushhead ( + qse_sll_t* sll /**< singly linked list */, + void* dptr, + qse_size_t dlen +); + +qse_sll_node_t* qse_sll_pushtail ( + qse_sll_t* sll /**< singly linked list */, + void* dptr, + qse_size_t dlen +); + +void qse_sll_pophead ( + qse_sll_t* sll +); + +void qse_sll_poptail ( + qse_sll_t* sll +); + #ifdef __cplusplus } #endif diff --git a/qse/include/qse/cmn/str.h b/qse/include/qse/cmn/str.h index a70b16f1..2cf54b9b 100644 --- a/qse/include/qse/cmn/str.h +++ b/qse/include/qse/cmn/str.h @@ -1,5 +1,5 @@ /* - * $Id: str.h 353 2010-09-01 13:19:59Z hyunghwan.chung $ + * $Id: str.h 354 2010-09-03 12:50:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -25,10 +25,11 @@ #include /** @file - * Various functions, types, macros for string manipulation. + * This file provides various functions, types, macros for string manipulation. + * + * The #qse_cstr_t type and the #qse_xstr_t defined in help you + * deal with a string pointer and length in a structure. * - * The qse_cstr_t type and the qse_xstr_t defined in helps you - * dealing with a string pointer and length. */ #define QSE_STR_LEN(s) ((s)->len) /**< string length */ @@ -170,17 +171,25 @@ qse_size_t qse_strxcpy ( const qse_char_t* str ); +/** + * The qse_strycpy() function copies a length-bounded string into + * a buffer with unknown size. + */ qse_size_t qse_strncpy ( - qse_char_t* buf, - const qse_char_t* str, - qse_size_t len + qse_char_t* buf, /**< buffer with unknown length */ + const qse_char_t* str, /**< length-bounded string */ + qse_size_t len /**< string length */ ); +/** + * The qse_strycpy() function copies a length-bounded string into + * a length-bounded buffer. + */ qse_size_t qse_strxncpy ( - qse_char_t* buf, - qse_size_t bsz, - const qse_char_t* str, - qse_size_t len + qse_char_t* buf, /**< length-bounded buffer */ + qse_size_t bsz, /**< buffer length */ + const qse_char_t* str, /**< length-bounded string */ + qse_size_t len /**< string length */ ); /** @@ -189,13 +198,13 @@ qse_size_t qse_strxncpy ( * buffer. */ qse_size_t qse_strxput ( - qse_char_t* buf, + qse_char_t* buf, qse_size_t bsz, const qse_char_t* str ); qse_size_t qse_strxnput ( - qse_char_t* buf, + qse_char_t* buf, qse_size_t bsz, const qse_char_t* str, qse_size_t len @@ -226,8 +235,8 @@ qse_size_t qse_strfcpy ( * @sa qse_strfcpy, qse_strxfcpy, qse_strxfncpy */ qse_size_t qse_strfncpy ( - qse_char_t* buf, - const qse_char_t* fmt, + qse_char_t* buf, + const qse_char_t* fmt, const qse_cstr_t str[] ); @@ -256,9 +265,9 @@ qse_size_t qse_strxfcpy ( * @sa qse_strfcpy, qse_strfncpy, qse_strxfcpy */ qse_size_t qse_strxfncpy ( - qse_char_t* buf, + qse_char_t* buf, qse_size_t bsz, - const qse_char_t* fmt, + const qse_char_t* fmt, const qse_cstr_t str[] ); @@ -281,11 +290,11 @@ qse_size_t qse_strxfncpy ( * @endcode */ qse_size_t qse_strxsubst ( - qse_char_t* buf, + qse_char_t* buf, qse_size_t bsz, const qse_char_t* fmt, qse_strxsubst_subst_t subst, - void* ctx + void* ctx ); qse_size_t qse_strxcat ( @@ -308,15 +317,15 @@ int qse_strcmp ( int qse_strxcmp ( const qse_char_t* s1, - qse_size_t len1, + qse_size_t len1, const qse_char_t* s2 ); int qse_strxncmp ( const qse_char_t* s1, - qse_size_t len1, + qse_size_t len1, const qse_char_t* s2, - qse_size_t len2 + qse_size_t len2 ); int qse_strcasecmp ( @@ -505,17 +514,25 @@ qse_char_t* qse_strxbeg ( const qse_char_t* sub) ; +/* + * The qse_strbeg() function checks if the a string begins with a substring. + * @return @a str on match, QSE_NULL on no match + */ qse_char_t* qse_strnbeg ( const qse_char_t* str, const qse_char_t* sub, - qse_size_t len + qse_size_t len ); +/* + * The qse_strbeg() function checks if the a string begins with a substring. + * @return @a str on match, QSE_NULL on no match + */ qse_char_t* qse_strxnbeg ( const qse_char_t* str, - qse_size_t len1, + qse_size_t len1, const qse_char_t* sub, - qse_size_t len2 + qse_size_t len2 ); /** @@ -565,25 +582,76 @@ qse_char_t* qse_strxnend ( /* * string conversion */ -int qse_strtoi (const qse_char_t* str); -long qse_strtol (const qse_char_t* str); -unsigned int qse_strtoui (const qse_char_t* str); -unsigned long qse_strtoul (const qse_char_t* str); +int qse_strtoi ( + const qse_char_t* str +); -int qse_strxtoi (const qse_char_t* str, qse_size_t len); -long qse_strxtol (const qse_char_t* str, qse_size_t len); -unsigned int qse_strxtoui (const qse_char_t* str, qse_size_t len); -unsigned long qse_strxtoul (const qse_char_t* str, qse_size_t len); +long qse_strtol ( + const qse_char_t* str +); -qse_int_t qse_strtoint (const qse_char_t* str); -qse_long_t qse_strtolong (const qse_char_t* str); -qse_uint_t qse_strtouint (const qse_char_t* str); -qse_ulong_t qse_strtoulong (const qse_char_t* str); +unsigned int qse_strtoui ( + const qse_char_t* str +); -qse_int_t qse_strxtoint (const qse_char_t* str, qse_size_t len); -qse_long_t qse_strxtolong (const qse_char_t* str, qse_size_t len); -qse_uint_t qse_strxtouint (const qse_char_t* str, qse_size_t len); -qse_ulong_t qse_strxtoulong (const qse_char_t* str, qse_size_t len); +unsigned long qse_strtoul ( + const qse_char_t* str +); + +int qse_strxtoi ( + const qse_char_t* str, + qse_size_t len +); + +long qse_strxtol ( + const qse_char_t* str, + qse_size_t len +); + +unsigned int qse_strxtoui ( + const qse_char_t* str, + qse_size_t len +); + +unsigned long qse_strxtoul ( + const qse_char_t* str, + qse_size_t len +); + +qse_int_t qse_strtoint ( + const qse_char_t* str +); + +qse_long_t qse_strtolong ( + const qse_char_t* str +); + +qse_uint_t qse_strtouint ( + const qse_char_t* str +); + +qse_ulong_t qse_strtoulong ( + const qse_char_t* str +); + +qse_int_t qse_strxtoint ( + const qse_char_t* str, qse_size_t len +); + +qse_long_t qse_strxtolong ( + const qse_char_t* str, + qse_size_t len +); + +qse_uint_t qse_strxtouint ( + const qse_char_t* str, + qse_size_t len +); + +qse_ulong_t qse_strxtoulong ( + const qse_char_t* str, + qse_size_t len +); /** * The qse_strspl() function splits a string into fields. @@ -595,7 +663,6 @@ int qse_strspl ( qse_char_t rquote, qse_char_t escape ); -/******/ /** * The qse_strspltrn() function splits a string translating special diff --git a/qse/include/qse/macros.h b/qse/include/qse/macros.h index 179d3eaf..9210d238 100644 --- a/qse/include/qse/macros.h +++ b/qse/include/qse/macros.h @@ -1,5 +1,5 @@ /* - * $Id: macros.h 348 2010-08-26 06:26:28Z hyunghwan.chung $ + * $Id: macros.h 354 2010-09-03 12:50:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -29,26 +29,35 @@ #if defined(__STDC_VERSION__) && (__STDC_VERSION__>=199901L) # define QSE_INLINE inline +# define QSE_HAVE_INLINE #elif defined(__GNUC__) && defined(__GNUC_GNU_INLINE__) # define QSE_INLINE /*extern*/ inline +# define QSE_HAVE_INLINE #else # define QSE_INLINE +# undef QSE_HAVE_INLINE #endif #if defined(__GNUC__) # define QSE_INLINE_ALWAYS inline __attribute__((__always_inline__)) +# define QSE_HAVE_INLINE_ALWAYS #elif defined(_MSC_VER) || (defined(__CC_ARM) || defined(__ARMCC__)) # define QSE_INLINE_ALWAYS __forceinline +# define QSE_HAVE_INLINE_ALWAYS #else # define QSE_INLINE_ALWAYS QSE_INLINE +# undef QSE_HAVE_INLINE_ALWAYS #endif #if defined(__GNUC__) # define QSE_INLINE_NEVER inline __attribute__((__noinline__)) +# define QSE_HAVE_INLINE_NEVER #elif (defined(__CC_ARM) || defined(__ARMCC__)) # define QSE_INLINE_NEVER __declspec(noinline) +# define QSE_HAVE_INLINE_NEVER #else # define QSE_INLINE_NEVER +# undef QSE_HAVE_INLINE_NEVER #endif @@ -142,14 +151,20 @@ #define QSE_TYPE_MIN(type) \ ((QSE_TYPE_IS_SIGNED(type)? QSE_TYPE_SIGNED_MIN(type): QSE_TYPE_UNSIGNED_MIN(type))) +/** + * The QSE_BLOCK macro encloses one or more statements in a block with + * no side-effect. + */ +#define QSE_BLOCK(code) do { code } while(0) + #define QSE_IS_POWOF2(x) (((x) & ((x) - 1)) == 0) #define QSE_SWAP(x,y,original_type,casting_type) \ - do { \ + QSE_BLOCK ( \ x = (original_type)((casting_type)(x) ^ (casting_type)(y)); \ y = (original_type)((casting_type)(y) ^ (casting_type)(x)); \ x = (original_type)((casting_type)(x) ^ (casting_type)(y)); \ - } while (0) + ) #define QSE_ABS(x) ((x) < 0? -(x): (x)) @@ -162,7 +177,7 @@ #define QSE_END_LOOP(id) QSE_LOOP_CONTINUE(id) } __loop_ ## id ## _end__: #define QSE_REPEAT(n,blk) \ - do { \ + QSE_BLOCK ( \ qse_size_t __qse_repeat_x1__ = (qse_size_t)(n); \ qse_size_t __qse_repeat_x2__ = __qse_repeat_x1__ >> 4; \ __qse_repeat_x1__ &= 15; \ @@ -171,7 +186,8 @@ blk; blk; blk; blk; blk; blk; blk; blk; \ blk; blk; blk; blk; blk; blk; blk; blk; \ } \ - } while (0); + ) + /* number of characters to number of bytes */ #define QSE_NCTONB(x) ((x)*sizeof(qse_char_t)) diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am index 65cda218..bdcd37d9 100644 --- a/qse/lib/cmn/Makefile.am +++ b/qse/lib/cmn/Makefile.am @@ -7,7 +7,7 @@ libqsecmn_la_SOURCES = \ syscall.h mem.h \ mem.c xma.c fma.c chr.c chr_cnv.c rex.c \ str_bas.c str_cnv.c str_dyn.c str_utl.c \ - lda.c htb.c rbt.c sll.c dll.c opt.c \ + lda.c htb.c rbt.c sll.c gdl.c dll.c opt.c \ tio.c tio_get.c tio_put.c \ fio.c pio.c sio.c \ time.c \ diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in index 86f1cbd4..517144ca 100644 --- a/qse/lib/cmn/Makefile.in +++ b/qse/lib/cmn/Makefile.in @@ -75,7 +75,7 @@ LTLIBRARIES = $(lib_LTLIBRARIES) libqsecmn_la_DEPENDENCIES = am_libqsecmn_la_OBJECTS = mem.lo xma.lo fma.lo chr.lo chr_cnv.lo \ rex.lo str_bas.lo str_cnv.lo str_dyn.lo str_utl.lo lda.lo \ - htb.lo rbt.lo sll.lo dll.lo opt.lo tio.lo tio_get.lo \ + htb.lo rbt.lo sll.lo gdl.lo dll.lo opt.lo tio.lo tio_get.lo \ tio_put.lo fio.lo pio.lo sio.lo time.lo misc.lo assert.lo \ main.lo stdio.lo libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS) @@ -264,7 +264,7 @@ libqsecmn_la_SOURCES = \ syscall.h mem.h \ mem.c xma.c fma.c chr.c chr_cnv.c rex.c \ str_bas.c str_cnv.c str_dyn.c str_utl.c \ - lda.c htb.c rbt.c sll.c dll.c opt.c \ + lda.c htb.c rbt.c sll.c gdl.c dll.c opt.c \ tio.c tio_get.c tio_put.c \ fio.c pio.c sio.c \ time.c \ @@ -363,6 +363,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dll.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fma.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@ diff --git a/qse/lib/cmn/dll.c b/qse/lib/cmn/dll.c index 5e94e15a..e5ec58d8 100644 --- a/qse/lib/cmn/dll.c +++ b/qse/lib/cmn/dll.c @@ -1,5 +1,5 @@ /* - * $Id: dll.c 287 2009-09-15 10:01:02Z hyunghwan.chung $ + * $Id: dll.c 354 2010-09-03 12:50:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -21,7 +21,31 @@ #include #include "mem.h" -qse_dll_t* qse_dll_open (qse_mmgr_t* mmgr, qse_size_t ext) +QSE_IMPLEMENT_COMMON_FUNCTIONS (dll) + +#define TOB(dll,len) ((len)*(dll)->scale) + +static int default_comper ( + qse_dll_t* dll, + const void* dptr1, size_t dlen1, + const void* dptr2, size_t dlen2) +{ + if (dlen1 == dlen2) return QSE_MEMCMP (dptr1, dptr2, TOB(dll,dlen1)); + /* it just returns 1 to indicate that they are different. */ + return 1; + +#if 0 + qse_size_t min = (dlen1 < dlen2)? dlen1: dlen2; + int n = QSE_MEMCMP (dptr1, dptr2, TOB(dll,min)); + if (n == 0 && dlen1 != dlen2) + { + n = (dlen1 > dlen2)? 1: -1; + } + return n; +#endif +} + +qse_dll_t* qse_dll_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) { qse_dll_t* dll; @@ -35,56 +59,60 @@ qse_dll_t* qse_dll_open (qse_mmgr_t* mmgr, qse_size_t ext) if (mmgr == QSE_NULL) return QSE_NULL; } - dll = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_dll_t) + ext); + dll = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_dll_t) + xtnsize); if (dll == QSE_NULL) return QSE_NULL; - /* do not zero the extension */ - QSE_MEMSET (dll, 0, QSE_SIZEOF(qse_dll_t)); - dll->mmgr = mmgr; + if (qse_dll_init (dll, mmgr) == QSE_NULL) + { + QSE_MMGR_FREE (mmgr, dll); + return QSE_NULL; + } return dll; } void qse_dll_close (qse_dll_t* dll) { - qse_dll_clear (dll); + qse_dll_fini (dll); QSE_MMGR_FREE (dll->mmgr, dll); } -void qse_dll_clear (qse_dll_t* dll) +qse_dll_t* qse_dll_init (qse_dll_t* dll, qse_mmgr_t* mmgr) { - while (dll->head != QSE_NULL) qse_dll_delete (dll, dll->head); - QSE_ASSERT (dll->tail == QSE_NULL); -} + if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL(); -void* qse_dll_getxtn (qse_dll_t* dll) -{ - return dll + 1; -} + /* do not zero out the xtnsizeension */ + QSE_MEMSET (dll, 0, QSE_SIZEOF(*dll)); -qse_mmgr_t* qse_dll_getmmgr (qse_dll_t* dll) -{ - return dll->mmgr; -} - -void qse_dll_setmmgr (qse_dll_t* dll, qse_mmgr_t* mmgr) -{ dll->mmgr = mmgr; + dll->scale = 1; + + dll->comper = default_comper; + dll->copier = QSE_DLL_COPIER_SIMPLE; + + QSE_DLL_INIT (dll); + return dll; } -qse_size_t qse_dll_getsize (qse_dll_t* dll) +void qse_dll_fini (qse_dll_t* dll) { - return dll->size; + qse_dll_clear (dll); } -qse_dll_node_t* qse_dll_gethead (qse_dll_t* dll) +int qse_dll_getscale (qse_dll_t* dll) { - return dll->head; + return dll->scale; } -qse_dll_node_t* qse_dll_gettail (qse_dll_t* dll) +void qse_dll_setscale (qse_dll_t* dll, int scale) { - return dll->tail; + QSE_ASSERTX (scale > 0 && scale <= QSE_TYPE_MAX(qse_byte_t), + "The scale should be larger than 0 and less than or equal to the maximum value that the qse_byte_t type can hold"); + + if (scale <= 0) scale = 1; + if (scale > QSE_TYPE_MAX(qse_byte_t)) scale = QSE_TYPE_MAX(qse_byte_t); + + dll->scale = scale; } qse_dll_copier_t qse_dll_getcopier (qse_dll_t* dll) @@ -94,6 +122,7 @@ qse_dll_copier_t qse_dll_getcopier (qse_dll_t* dll) void qse_dll_setcopier (qse_dll_t* dll, qse_dll_copier_t copier) { + if (copier == QSE_NULL) copier = QSE_DLL_COPIER_SIMPLE; dll->copier = copier; } @@ -107,11 +136,37 @@ void qse_dll_setfreeer (qse_dll_t* dll, qse_dll_freeer_t freeer) dll->freeer = freeer; } +qse_dll_comper_t qse_dll_getcomper (qse_dll_t* dll) +{ + return dll->comper; +} + +void qse_dll_setcomper (qse_dll_t* dll, qse_dll_comper_t comper) +{ + if (comper == QSE_NULL) comper = default_comper; + dll->comper = comper; +} + +qse_size_t qse_dll_getsize (qse_dll_t* dll) +{ + return QSE_DLL_SIZE(dll); +} + +qse_dll_node_t* qse_dll_gethead (qse_dll_t* dll) +{ + return QSE_DLL_HEAD(dll); +} + +qse_dll_node_t* qse_dll_gettail (qse_dll_t* dll) +{ + return QSE_DLL_TAIL(dll); +} + static qse_dll_node_t* alloc_node (qse_dll_t* dll, void* dptr, qse_size_t dlen) { qse_dll_node_t* n; - if (dll->copier == QSE_NULL) + if (dll->copier == QSE_DLL_COPIER_SIMPLE) { n = QSE_MMGR_ALLOC (dll->mmgr, QSE_SIZEOF(qse_dll_node_t)); if (n == QSE_NULL) return QSE_NULL; @@ -119,10 +174,11 @@ static qse_dll_node_t* alloc_node (qse_dll_t* dll, void* dptr, qse_size_t dlen) } else if (dll->copier == QSE_DLL_COPIER_INLINE) { - n = QSE_MMGR_ALLOC (dll->mmgr, QSE_SIZEOF(qse_dll_node_t) + dlen); + n = QSE_MMGR_ALLOC (dll->mmgr, + QSE_SIZEOF(qse_dll_node_t) + TOB(dll,dlen)); if (n == QSE_NULL) return QSE_NULL; - QSE_MEMCPY (n + 1, dptr, dlen); + QSE_MEMCPY (n + 1, dptr, TOB(dll,dlen)); n->dptr = n + 1; } else @@ -138,51 +194,132 @@ static qse_dll_node_t* alloc_node (qse_dll_t* dll, void* dptr, qse_size_t dlen) } n->dlen = dlen; - n->next = QSE_NULL; - n->prev = QSE_NULL; - return n; } +static QSE_INLINE void free_node (qse_dll_t* dll, qse_dll_node_t* node) +{ + if (dll->freeer != QSE_NULL) + { + /* free the actual data */ + dll->freeer (dll, node->dptr, node->dlen); + } + + /* free the node */ + QSE_MMGR_FREE (dll->mmgr, node); +} + +qse_dll_node_t* qse_dll_search ( + qse_dll_t* dll, qse_dll_node_t* pos, const void* dptr, qse_size_t dlen) +{ + if (pos == QSE_NULL) pos = QSE_DLL_HEAD(dll); + + while (QSE_DLL_ISMEMBER(dll,pos)) + { + if (dll->comper (dll, pos->dptr, pos->dlen, dptr, dlen) == 0) + { + return pos; + } + + pos = pos->next; + } + + return QSE_NULL; +} + +qse_dll_node_t* qse_dll_rsearch ( + qse_dll_t* dll, qse_dll_node_t* pos, const void* dptr, qse_size_t dlen) +{ + if (pos == QSE_NULL) pos = QSE_DLL_TAIL(dll); + + while (QSE_DLL_ISMEMBER(dll,pos)) + { + if (dll->comper (dll, pos->dptr, pos->dlen, dptr, dlen) == 0) + { + return pos; + } + + pos = pos->prev; + } + + return QSE_NULL; +} + qse_dll_node_t* qse_dll_insert ( qse_dll_t* dll, qse_dll_node_t* pos, void* dptr, qse_size_t dlen) { qse_dll_node_t* n = alloc_node (dll, dptr, dlen); - if (n == QSE_NULL) return QSE_NULL; - - if (pos == QSE_NULL) + if (n) { - /* insert at the end */ - if (dll->head == QSE_NULL) + if (pos == QSE_NULL) { - QSE_ASSERT (dll->tail == QSE_NULL); - dll->head = n; + /* insert at the end */ + QSE_DLL_ADDTAIL (dll, n); } - else dll->tail->next = n; - - dll->tail = n; - } - else - { - /* insert in front of the positional node */ - n->next = pos; - if (pos == dll->head) dll->head = n; else { - /* take note of performance penalty */ - qse_dll_node_t* n2 = dll->head; - while (n2->next != pos) n2 = n2->next; - n2->next = n; + /* insert in front of the positional node */ + QSE_DLL_CHAIN (dll, pos->prev, n, pos); } } - dll->size++; return n; } +void qse_dll_delete (qse_dll_t* dll, qse_dll_node_t* pos) +{ + if (pos == QSE_NULL || !QSE_DLL_ISMEMBER(dll,pos)) return; + QSE_DLL_UNCHAIN (dll, pos); + free_node (dll, pos); +} + +void qse_dll_clear (qse_dll_t* dll) +{ + while (!QSE_DLL_ISEMPTY(dll)) + { + qse_dll_delete (dll, QSE_DLL_HEAD(dll)); + } +} + +void qse_dll_walk (qse_dll_t* dll, qse_dll_walker_t walker, void* ctx) +{ + qse_dll_node_t* n = QSE_DLL_HEAD(dll); + qse_dll_walk_t w = QSE_DLL_WALK_FORWARD; + + while (QSE_DLL_ISMEMBER(dll,n)) + { + qse_dll_node_t* nxt = n->next; + qse_dll_node_t* prv = n->prev; + + w = walker (dll, n, ctx); + + if (w == QSE_DLL_WALK_FORWARD) n = nxt; + else if (w == QSE_DLL_WALK_BACKWARD) n = prv; + else break; + } +} + +void qse_dll_rwalk (qse_dll_t* dll, qse_dll_walker_t walker, void* ctx) +{ + qse_dll_node_t* n = QSE_DLL_TAIL(dll); + qse_dll_walk_t w = QSE_DLL_WALK_BACKWARD; + + while (QSE_DLL_ISMEMBER(dll,n)) + { + qse_dll_node_t* nxt = n->next; + qse_dll_node_t* prv = n->prev; + + w = walker (dll, n, ctx); + + if (w == QSE_DLL_WALK_FORWARD) n = nxt; + else if (w == QSE_DLL_WALK_BACKWARD) n = prv; + else break; + } +} + qse_dll_node_t* qse_dll_pushhead (qse_dll_t* dll, void* data, qse_size_t size) { - return qse_dll_insert (dll, dll->head, data, size); + return qse_dll_insert (dll, QSE_DLL_HEAD(dll), data, size); } qse_dll_node_t* qse_dll_pushtail (qse_dll_t* dll, void* data, qse_size_t size) @@ -190,67 +327,16 @@ qse_dll_node_t* qse_dll_pushtail (qse_dll_t* dll, void* data, qse_size_t size) return qse_dll_insert (dll, QSE_NULL, data, size); } -void qse_dll_delete (qse_dll_t* dll, qse_dll_node_t* pos) -{ - if (pos == QSE_NULL) return; /* not a valid node */ - - if (pos == dll->head) - { - /* it is simple to delete the head node */ - dll->head = pos->next; - if (dll->head == QSE_NULL) dll->tail = QSE_NULL; - } - else - { - /* but deletion of other nodes has significant performance - * penalty as it has look for the predecessor of the - * target node */ - qse_dll_node_t* n2 = dll->head; - while (n2->next != pos) n2 = n2->next; - - n2->next = pos->next; - - /* update the tail node if necessary */ - if (pos == dll->tail) dll->tail = n2; - } - - if (dll->freeer != QSE_NULL) - { - /* free the actual data */ - dll->freeer (dll, pos->dptr, pos->dlen); - } - - /* free the node */ - QSE_MMGR_FREE (dll->mmgr, pos); - - /* decrement the number of elements */ - dll->size--; -} - void qse_dll_pophead (qse_dll_t* dll) { - qse_dll_delete (dll, dll->head); + QSE_ASSERT (!QSE_DLL_ISEMPTY(dll)); + QSE_DLL_DELHEAD (dll); } void qse_dll_poptail (qse_dll_t* dll) { - qse_dll_delete (dll, dll->tail); + QSE_ASSERT (!QSE_DLL_ISEMPTY(dll)); + QSE_DLL_DELTAIL (dll); } -void qse_dll_walk (qse_dll_t* dll, qse_dll_walker_t walker, void* arg) -{ - qse_dll_node_t* n = dll->head; - - while (n != QSE_NULL) - { - if (walker(dll,n,arg) == QSE_DLL_WALK_STOP) return; - n = n->next; - } -} - -void* qse_dll_copyinline (qse_dll_t* dll, void* dptr, qse_size_t dlen) -{ - /* this is a dummy copier */ - return QSE_NULL; -} diff --git a/qse/lib/cmn/gdl.c b/qse/lib/cmn/gdl.c new file mode 100644 index 00000000..23015be4 --- /dev/null +++ b/qse/lib/cmn/gdl.c @@ -0,0 +1,33 @@ +/* + * $Id$ + * + Copyright 2006-2009 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#include + +void qse_gdl_chain (qse_gdl_t* p, qse_gdl_t* x, qse_gdl_t* n) +{ + x->prev = p; x->next = n; n->prev = x; p->next = x; +} + +void qse_gdl_unchain (qse_gdl_t* x) +{ + qse_gdl_t* p = x->prev; + qse_gdl_t* n = x->next; + n->prev = p; p->next = n; +} diff --git a/qse/lib/cmn/lda.c b/qse/lib/cmn/lda.c index 6df8bdc1..38093083 100644 --- a/qse/lib/cmn/lda.c +++ b/qse/lib/cmn/lda.c @@ -1,5 +1,5 @@ /* - * $Id: lda.c 348 2010-08-26 06:26:28Z hyunghwan.chung $ + * $Id: lda.c 354 2010-09-03 12:50:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -207,22 +207,22 @@ void qse_lda_setcomper (lda_t* lda, comper_t comper) keeper_t qse_lda_getkeeper (lda_t* lda) { - return lda->keeper; + return lda->keeper; } void qse_lda_setkeeper (lda_t* lda, keeper_t keeper) { - lda->keeper = keeper; + lda->keeper = keeper; } sizer_t qse_lda_getsizer (lda_t* lda) { - return lda->sizer; + return lda->sizer; } void qse_lda_setsizer (lda_t* lda, sizer_t sizer) { - lda->sizer = sizer; + lda->sizer = sizer; } size_t qse_lda_getsize (lda_t* lda) @@ -527,7 +527,7 @@ size_t qse_lda_walk (lda_t* lda, walker_t walker, void* ctx) { if (lda->node[i] != QSE_NULL) { - w = walker (lda, i, ctx); + w = walker (lda, i, ctx); nwalks++; } diff --git a/qse/lib/cmn/sll.c b/qse/lib/cmn/sll.c index df480f23..62e3c07a 100644 --- a/qse/lib/cmn/sll.c +++ b/qse/lib/cmn/sll.c @@ -1,5 +1,5 @@ /* - * $Id: sll.c 348 2010-08-26 06:26:28Z hyunghwan.chung $ + * $Id: sll.c 354 2010-09-03 12:50:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. This file is part of QSE. @@ -44,13 +44,23 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (sll) #define size_t qse_size_t #define mmgr_t qse_mmgr_t -static int comp_data (sll_t* sll, +static int default_comper (sll_t* sll, const void* dptr1, size_t dlen1, const void* dptr2, size_t dlen2) { if (dlen1 == dlen2) return QSE_MEMCMP (dptr1, dptr2, TOB(sll,dlen1)); /* it just returns 1 to indicate that they are different. */ return 1; + +#if 0 + size_t min = (dlen1 < dlen2)? dlen1: dlen2; + int n = QSE_MEMCMP (dptr1, dptr2, TOB(sll,min)); + if (n == 0 && dlen1 != dlen2) + { + n = (dlen1 > dlen2)? 1: -1; + } + return n; +#endif } static node_t* alloc_node (sll_t* sll, void* dptr, size_t dlen) @@ -133,7 +143,7 @@ sll_t* qse_sll_init (sll_t* sll, mmgr_t* mmgr) sll->size = 0; sll->scale = 1; - sll->comper = comp_data; + sll->comper = default_comper; sll->copier = QSE_SLL_COPIER_SIMPLE; return sll; } @@ -187,7 +197,7 @@ comper_t qse_sll_getcomper (sll_t* sll) void qse_sll_setcomper (sll_t* sll, comper_t comper) { - if (comper == QSE_NULL) comper = comp_data; + if (comper == QSE_NULL) comper = default_comper; sll->comper = comper; } @@ -301,6 +311,18 @@ void qse_sll_clear (sll_t* sll) QSE_ASSERT (TAIL(sll) == QSE_NULL); } +void qse_sll_walk (sll_t* sll, walker_t walker, void* ctx) +{ + node_t* n = HEAD(sll); + + while (n != QSE_NULL) + { + qse_sll_node_t* nxt = NEXT(n); + if (walker(sll,n,ctx) == QSE_SLL_WALK_STOP) return; + n = nxt; + } +} + node_t* qse_sll_pushhead (sll_t* sll, void* data, size_t size) { return qse_sll_insert (sll, HEAD(sll), data, size); @@ -321,14 +343,4 @@ void qse_sll_poptail (sll_t* sll) qse_sll_delete (sll, TAIL(sll)); } -void qse_sll_walk (sll_t* sll, walker_t walker, void* ctx) -{ - node_t* n = HEAD(sll); - - while (n != QSE_NULL) - { - if (walker(sll,n,ctx) == QSE_SLL_WALK_STOP) return; - n = NEXT(n); - } -} diff --git a/qse/samples/cmn/Makefile.am b/qse/samples/cmn/Makefile.am index a188f22e..afe80d3c 100644 --- a/qse/samples/cmn/Makefile.am +++ b/qse/samples/cmn/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -DNDEBUG -bin_PROGRAMS = xma fma chr str sll lda htb rbt fio pio sio time main rex01 +bin_PROGRAMS = xma fma chr str sll dll lda htb rbt fio pio sio time main rex01 LDFLAGS = -L../../lib/cmn LDADD = -lqsecmn @@ -10,6 +10,7 @@ fma_SOURCES = fma.c chr_SOURCES = chr.c str_SOURCES = str.c sll_SOURCES = sll.c +dll_SOURCES = dll.c lda_SOURCES = lda.c htb_SOURCES = htb.c rbt_SOURCES = rbt.c diff --git a/qse/samples/cmn/Makefile.in b/qse/samples/cmn/Makefile.in index b0238b5b..a90d27de 100644 --- a/qse/samples/cmn/Makefile.in +++ b/qse/samples/cmn/Makefile.in @@ -35,9 +35,9 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = xma$(EXEEXT) fma$(EXEEXT) chr$(EXEEXT) str$(EXEEXT) \ - sll$(EXEEXT) lda$(EXEEXT) htb$(EXEEXT) rbt$(EXEEXT) \ - fio$(EXEEXT) pio$(EXEEXT) sio$(EXEEXT) time$(EXEEXT) \ - main$(EXEEXT) rex01$(EXEEXT) + sll$(EXEEXT) dll$(EXEEXT) lda$(EXEEXT) htb$(EXEEXT) \ + rbt$(EXEEXT) fio$(EXEEXT) pio$(EXEEXT) sio$(EXEEXT) \ + time$(EXEEXT) main$(EXEEXT) rex01$(EXEEXT) subdir = samples/cmn DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -58,6 +58,10 @@ am_chr_OBJECTS = chr.$(OBJEXT) chr_OBJECTS = $(am_chr_OBJECTS) chr_LDADD = $(LDADD) chr_DEPENDENCIES = +am_dll_OBJECTS = dll.$(OBJEXT) +dll_OBJECTS = $(am_dll_OBJECTS) +dll_LDADD = $(LDADD) +dll_DEPENDENCIES = am_fio_OBJECTS = fio.$(OBJEXT) fio_OBJECTS = $(am_fio_OBJECTS) fio_LDADD = $(LDADD) @@ -123,14 +127,14 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(fma_SOURCES) $(htb_SOURCES) \ - $(lda_SOURCES) $(main_SOURCES) $(pio_SOURCES) $(rbt_SOURCES) \ - $(rex01_SOURCES) $(sio_SOURCES) $(sll_SOURCES) $(str_SOURCES) \ - $(time_SOURCES) $(xma_SOURCES) -DIST_SOURCES = $(chr_SOURCES) $(fio_SOURCES) $(fma_SOURCES) \ +SOURCES = $(chr_SOURCES) $(dll_SOURCES) $(fio_SOURCES) $(fma_SOURCES) \ $(htb_SOURCES) $(lda_SOURCES) $(main_SOURCES) $(pio_SOURCES) \ $(rbt_SOURCES) $(rex01_SOURCES) $(sio_SOURCES) $(sll_SOURCES) \ $(str_SOURCES) $(time_SOURCES) $(xma_SOURCES) +DIST_SOURCES = $(chr_SOURCES) $(dll_SOURCES) $(fio_SOURCES) \ + $(fma_SOURCES) $(htb_SOURCES) $(lda_SOURCES) $(main_SOURCES) \ + $(pio_SOURCES) $(rbt_SOURCES) $(rex01_SOURCES) $(sio_SOURCES) \ + $(sll_SOURCES) $(str_SOURCES) $(time_SOURCES) $(xma_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -280,6 +284,7 @@ fma_SOURCES = fma.c chr_SOURCES = chr.c str_SOURCES = str.c sll_SOURCES = sll.c +dll_SOURCES = dll.c lda_SOURCES = lda.c htb_SOURCES = htb.c rbt_SOURCES = rbt.c @@ -369,6 +374,9 @@ clean-binPROGRAMS: chr$(EXEEXT): $(chr_OBJECTS) $(chr_DEPENDENCIES) @rm -f chr$(EXEEXT) $(LINK) $(chr_OBJECTS) $(chr_LDADD) $(LIBS) +dll$(EXEEXT): $(dll_OBJECTS) $(dll_DEPENDENCIES) + @rm -f dll$(EXEEXT) + $(LINK) $(dll_OBJECTS) $(dll_LDADD) $(LIBS) fio$(EXEEXT): $(fio_OBJECTS) $(fio_DEPENDENCIES) @rm -f fio$(EXEEXT) $(LINK) $(fio_OBJECTS) $(fio_LDADD) $(LIBS) @@ -416,6 +424,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dll.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fma.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Po@am__quote@ diff --git a/qse/samples/cmn/dll.c b/qse/samples/cmn/dll.c new file mode 100644 index 00000000..315a442d --- /dev/null +++ b/qse/samples/cmn/dll.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include + + +#define R(f) \ + do { \ + qse_printf (QSE_T("== %s ==\n"), QSE_T(#f)); \ + if (f() == -1) return -1; \ + } while (0) + +static qse_dll_walk_t walk_dll (qse_dll_t* dll, qse_dll_node_t* n, void* arg) +{ + qse_printf (QSE_T("[%.*s]\n"), (int)QSE_DLL_DLEN(n), QSE_DLL_DPTR(n)); + return QSE_DLL_WALK_FORWARD; +} + +static qse_dll_walk_t rwalk_dll (qse_dll_t* dll, qse_dll_node_t* n, void* arg) +{ + qse_printf (QSE_T("[%.*s]\n"), (int)QSE_DLL_DLEN(n), QSE_DLL_DPTR(n)); + return QSE_DLL_WALK_BACKWARD; +} + +static int test1 () +{ + qse_dll_t* s1; + qse_dll_node_t* p; + qse_char_t* x[] = + { + QSE_T("this is so good"), + QSE_T("what the hack"), + QSE_T("do you like it?") + }; + int i; + + s1 = qse_dll_open (QSE_MMGR_GETDFL(), 0); + if (s1 == QSE_NULL) + { + qse_printf (QSE_T("cannot open a string\n")); + return -1; + } + + qse_dll_setcopier (s1, QSE_DLL_COPIER_INLINE); + qse_dll_setscale (s1, QSE_SIZEOF(qse_char_t)); + + for (i = 0; i < QSE_COUNTOF(x); i++) + { + qse_dll_pushtail (s1, x[i], qse_strlen(x[i])); + } + qse_printf (QSE_T("s1 holding [%d] nodes\n"), QSE_DLL_SIZE(s1)); + qse_dll_walk (s1, walk_dll, QSE_NULL); + + + p = qse_dll_search (s1, QSE_NULL, x[0], qse_strlen(x[0])); + if (p != QSE_NULL) + { + qse_dll_delete (s1, p); + } + qse_printf (QSE_T("s1 holding [%d] nodes\n"), QSE_DLL_SIZE(s1)); + qse_dll_walk (s1, walk_dll, QSE_NULL); + + qse_dll_close (s1); + return 0; +} + +static int test2 () +{ + qse_dll_t* s1; + qse_dll_node_t* p; + qse_char_t* x[] = + { + QSE_T("this is so good"), + QSE_T("what the hack"), + QSE_T("do you like it?") + }; + int i; + + s1 = qse_dll_open (QSE_MMGR_GETDFL(), 0); + if (s1 == QSE_NULL) + { + qse_printf (QSE_T("cannot open a string\n")); + return -1; + } + + qse_dll_setcopier (s1, QSE_DLL_COPIER_INLINE); + qse_dll_setscale (s1, QSE_SIZEOF(qse_char_t)); + + for (i = 0; i < QSE_COUNTOF(x); i++) + { + qse_dll_pushtail (s1, x[i], qse_strlen(x[i])); + } + qse_printf (QSE_T("s1 holding [%d] nodes\n"), QSE_DLL_SIZE(s1)); + qse_dll_rwalk (s1, rwalk_dll, QSE_NULL); + + + p = qse_dll_search (s1, QSE_NULL, x[0], qse_strlen(x[0])); + if (p != QSE_NULL) + { + qse_dll_delete (s1, p); + } + qse_printf (QSE_T("s1 holding [%d] nodes\n"), QSE_DLL_SIZE(s1)); + qse_dll_rwalk (s1, rwalk_dll, QSE_NULL); + + qse_dll_close (s1); + return 0; +} + +typedef struct item_t item_t; +struct item_t +{ + int a; + int b; +}; +QSE_DLL_DEFINE_SIMPLE (item_t); + +static int test3 () +{ + qse_size_t n; + QSE_DLL_TYPE(item_t) ii; + QSE_DLL_NODE_TYPE(item_t) x[30]; + QSE_DLL_NODE_TYPE(item_t)* p; + + QSE_DLL_INIT(&ii); + + for (n = 0; n < QSE_COUNTOF(x); n++) + { + x[n].data.a = n; + x[n].data.b = n * 2; + } + + for (n = 0; n < QSE_COUNTOF(x)/2; n++) + { + QSE_DLL_ADDHEAD (&ii, &x[n]); + } + + for (; n < QSE_COUNTOF(x); n++) + { + QSE_DLL_ADDTAIL (&ii, &x[n]); + } + + qse_printf (QSE_T("total %d items\n"), (int)QSE_DLL_SIZE (&ii)); + for (p = QSE_DLL_HEAD(&ii); QSE_DLL_ISMEMBER(&ii,p); p = p->next) + { + qse_printf (QSE_T("%d %d\n"), p->data.a, p->data.b); + } + + QSE_DLL_UNCHAIN (&ii, QSE_DLL_TAIL(&ii)->prev); + QSE_DLL_DELHEAD (&ii); + qse_printf (QSE_T("total %d items. printing in reverse\n"), (int)QSE_DLL_SIZE (&ii)); + for (p = QSE_DLL_TAIL(&ii); QSE_DLL_ISMEMBER(&ii,p); p = p->prev) + { + qse_printf (QSE_T("%d %d\n"), p->data.a, p->data.b); + } + QSE_DLL_FINI (&ii); + return 0; +} + +int main () +{ + R (test1); + R (test2); + R (test3); + return 0; +}