438 lines
11 KiB
C
438 lines
11 KiB
C
/*
|
|
* $Id: dll.h 556 2011-08-31 15:43:46Z hyunghwan.chung $
|
|
*
|
|
Copyright 2006-2011 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef _QSE_CMN_DLL_H_
|
|
#define _QSE_CMN_DLL_H_
|
|
|
|
/** @file
|
|
* This file defines a doubly linked list interface.
|
|
*/
|
|
|
|
#include <qse/types.h>
|
|
#include <qse/macros.h>
|
|
#include <qse/cmn/gdl.h>
|
|
|
|
#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_SIMPLE macro defines a doubly-linked list type for data
|
|
* of the @a data_type type.
|
|
*/
|
|
#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_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) \
|
|
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_BLOCK ( \
|
|
QSE_GDL_INIT(&(dll)->gdl); \
|
|
(dll)->size = 0; \
|
|
)
|
|
|
|
#define QSE_DLL_FINI(dll) QSE_DLL_CLEAR(dll)
|
|
|
|
#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_BLOCK ( \
|
|
QSE_GDL_UNCHAIN ((qse_gdl_t*)x); \
|
|
(dll)->size--; \
|
|
)
|
|
|
|
#define QSE_DLL_CLEAR(dll) \
|
|
QSE_BLOCK ( \
|
|
while (!QSE_DLL_ISEMPTY(dll)) QSE_DLL_DELHEAD(dll); \
|
|
)
|
|
|
|
/**
|
|
* 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) ((const qse_size_t)(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
|
|
);
|
|
|
|
/* data freeer */
|
|
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 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
|
|
{
|
|
/* the first two fields in sync with qse_gdl_t */
|
|
qse_dll_node_t* prev;
|
|
qse_dll_node_t* next;
|
|
/* data */
|
|
qse_xptl_t val;
|
|
};
|
|
|
|
/**
|
|
* The qse_dll_t type defines a doubly linked list.
|
|
*/
|
|
struct qse_dll_t
|
|
{
|
|
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_SIMPLE ((qse_dll_copier_t)1)
|
|
#define QSE_DLL_COPIER_INLINE ((qse_dll_copier_t)2)
|
|
|
|
#define QSE_DLL_SCALE(dll) ((const int)(dll)->scale)
|
|
|
|
#define QSE_DLL_DPTR(node) ((node)->val.ptr)
|
|
#define QSE_DLL_DLEN(node) ((node)->val.len)
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
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.
|
|
* The extension area is allocated when the positive extension size extension
|
|
* is specified. It calls the extension initialization function initializer
|
|
* after initializing the main area. The extension initializer is passed
|
|
* the pointer to the doubly linked list created.
|
|
*
|
|
* @return
|
|
* the pointer to a newly created doubly linked list on success.
|
|
* QSE_NULL on failure.
|
|
*/
|
|
qse_dll_t* qse_dll_open (
|
|
qse_mmgr_t* mmgr, /**< memory manager */
|
|
qse_size_t xtnsize /**< size of extension area in bytes */
|
|
);
|
|
|
|
/**
|
|
* The qse_dll_close() function destroys a doubly linked list.
|
|
*/
|
|
void qse_dll_close (
|
|
qse_dll_t* dll /** doubly linked list */
|
|
);
|
|
|
|
/**
|
|
* The qse_dll_init() function initializes a statically declared list.
|
|
*/
|
|
int qse_dll_init (
|
|
qse_dll_t* dll, /**< doubly linked list */
|
|
qse_mmgr_t* mmgr /**< memory manager */
|
|
);
|
|
|
|
/**
|
|
* 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, /**< 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 /**< doubly linked list */
|
|
);
|
|
|
|
/**
|
|
* 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, /**< 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 /**< doubly linked list */
|
|
);
|
|
|
|
/**
|
|
* The qse_dll_getcomper() function returns the data comparator.
|
|
*/
|
|
qse_dll_comper_t qse_dll_getcomper (
|
|
qse_dll_t* dll /**< doubly linked list */
|
|
);
|
|
|
|
/**
|
|
* The qse_dll_setcomper() function changes the data comparator
|
|
*/
|
|
void qse_dll_setcomper (
|
|
qse_dll_t* dll, /**< doubly linked list */
|
|
qse_dll_comper_t comper /**< comparator */
|
|
);
|
|
|
|
/**
|
|
* 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 /**< doubly 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 /**< doubly 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 /**< doubly linked list */
|
|
);
|
|
|
|
|
|
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, /**< 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, /* doubly linked list */
|
|
void* dptr,
|
|
qse_size_t dlen
|
|
);
|
|
|
|
qse_dll_node_t* qse_dll_pushtail (
|
|
qse_dll_t* dll, /* doubly linked list */
|
|
void* dptr,
|
|
qse_size_t dlen
|
|
);
|
|
|
|
void qse_dll_pophead (
|
|
qse_dll_t* dll
|
|
);
|
|
|
|
void qse_dll_poptail (
|
|
qse_dll_t* dll
|
|
);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|