178 lines
5.5 KiB
C
178 lines
5.5 KiB
C
/** \file
|
|
* \brief Type safe list handling
|
|
*
|
|
* The definition and implementation make use of macros extensively to create
|
|
* a list type and related functions for any node type.
|
|
* <b>However, accessing the list does not use macros.</b>
|
|
* The list is implemented as a singly linked list. Sequential appending
|
|
* to the tail is fast, because the list structure contains
|
|
* a pointer to the anchor of the last accessed node.
|
|
*
|
|
* For a local list, mclist.c must be included after
|
|
* the declaration of the node type and after defining the macro MC_NAME
|
|
* and optionally MC_TYPE and MC_NEXT.
|
|
*
|
|
* For a public list, in the header file mclist.h must be included after
|
|
* the declaration of the node type and after defining the macro MC_NAME
|
|
* and optionally MC_TYPE. In the implementation mclist.c
|
|
* must be included after defining the macro MC_NAME and MC_IMPLEMENTATION
|
|
* and optionally MC_TYPE and MC_NEXT.
|
|
*
|
|
* MC_NAME has one parameter and describes how to combine the list name
|
|
* with the function names.
|
|
*
|
|
* MC_TYPE defines the node type. If undeclared it defaults to a pointer
|
|
* to the name.
|
|
*
|
|
* MC_NEXT indicates the name of the link. It defaults to 'next'.
|
|
*
|
|
* MC_IMPLEMENTATION has no value and must be defined when the list type
|
|
* was already declared. Typically this is done in a header file including mclist.h.
|
|
*
|
|
* The macros MC_NAME, MC_TYPE, MC_NEXT and MC_IMPLEMENTATION are undefined
|
|
* within mclist.c and mclist.h and must be redefined for every list.
|
|
*
|
|
* \par Usage example
|
|
* \code
|
|
* // declare the Node type
|
|
* typedef struct Node {
|
|
* struct Node *next;
|
|
* char *name;
|
|
* } Node;
|
|
*
|
|
* // this declaration leads to a list type 'NodeList' and fucntions names 'Node<fun>'
|
|
* #define MC_NAME(T) Node##T
|
|
* // the following line is not needed as 'next' is the default for the link
|
|
* #define MC_NEXT next
|
|
* // the following line is not needed as 'Node *' is the default for the type in this case
|
|
* #define MC_TYPE Node *
|
|
* // inside mclist.c, the list type is declared and the related functions are implemented
|
|
* #include "mclist.c"
|
|
*
|
|
* int main(void) {
|
|
* // declare and init the list
|
|
* NodeList list={NULL};
|
|
*
|
|
* // create a node
|
|
* Node *node;
|
|
* node = malloc(sizeof(*node));
|
|
* node->name = "First";
|
|
*
|
|
* // add node at the end of the list
|
|
* NodeAdd(&list, node);
|
|
*
|
|
* // print the names of all list nodes
|
|
* for (node = NodeFirst(&list); node != NULL; node = NodeNext(&list)) {
|
|
* printf("%s\n", node->name);
|
|
* }
|
|
*
|
|
* // alternative form not touching the list position
|
|
* // only for the case, where no insert or take function is used inside the loop
|
|
* for (node = list.head; node != NULL; node = node->next) {
|
|
* printf("%s\n", node->name);
|
|
* }
|
|
*
|
|
* // remove the node with the name "First"
|
|
* for (node = NodeFirst(&list); node != NULL; node = NodeNext(&list)) {
|
|
* if (strcmp(node->name, "First") == 0) {
|
|
* free(NodeTake(&list));
|
|
* }
|
|
* }
|
|
* }
|
|
* \endcode
|
|
*/
|
|
#ifndef MC_TYPE
|
|
/** \brief default node type
|
|
*/
|
|
#define MC_TYPE MC_NAME()*
|
|
#endif
|
|
|
|
#ifndef MC_List_TYPE
|
|
#define MC_List_TYPE MC_NAME(List)
|
|
#define MC_First_FUN MC_NAME(First)
|
|
#define MC_This_FUN MC_NAME(This)
|
|
#define MC_Next_FUN MC_NAME(Next)
|
|
#define MC_End_FUN MC_NAME(End)
|
|
#define MC_Insert_FUN MC_NAME(Insert)
|
|
#define MC_Add_FUN MC_NAME(Add)
|
|
#define MC_Take_FUN MC_NAME(Take)
|
|
#define MC_Delete_FUN MC_NAME(Delete)
|
|
#endif
|
|
|
|
typedef struct MC_List_TYPE {
|
|
MC_TYPE head;
|
|
MC_TYPE *ptr;
|
|
} MC_List_TYPE;
|
|
|
|
/** \brief move to first node and get it
|
|
* \param list the list
|
|
* \return the node or NULL when the list is empty
|
|
*
|
|
* Actual position on return: at the first node
|
|
*/
|
|
MC_TYPE MC_First_FUN(MC_List_TYPE * list);
|
|
|
|
/** \brief get the node at the current position
|
|
* \param list the list
|
|
* \return the node or NULL when the list is empty or the position is at end
|
|
*
|
|
* Actual position on return: not changed (= at the returned node)
|
|
*/
|
|
MC_TYPE MC_This_FUN(MC_List_TYPE * list);
|
|
|
|
/** \brief get the node after the current node
|
|
* \param list the list
|
|
* \return the node or NULL when the list is empty or the position is at end
|
|
*
|
|
* Actual position on return: incremented (= at the returned node or at end)
|
|
*/
|
|
MC_TYPE MC_Next_FUN(MC_List_TYPE * list);
|
|
|
|
/** \brief move the position to the end
|
|
* \param list the list
|
|
*
|
|
* Actual position on return: at end
|
|
*/
|
|
void MC_End_FUN(MC_List_TYPE * list);
|
|
|
|
/** \brief insert at the current position, i.e. before the current node
|
|
* \param list the list
|
|
* \param node the node to be inserted
|
|
*
|
|
* Actual position on return: at the inserted node
|
|
*/
|
|
void MC_Insert_FUN(MC_List_TYPE * list, MC_TYPE node);
|
|
|
|
/** \brief add at the end of the list
|
|
* \param list the list
|
|
* \param node the node to be added
|
|
*
|
|
* Actual position on return: at the inserted node (before the last node, not at end!)
|
|
*/
|
|
void MC_Add_FUN(MC_List_TYPE * list, MC_TYPE node);
|
|
|
|
/** \brief remove the node at the current position
|
|
* \param list the list
|
|
* \return the removed node or NULL when the list is empty or the position is at end
|
|
*
|
|
* Actual position on return: after the taken node
|
|
*
|
|
* Note: it is the responsibility of the caller to free the node if it is not used
|
|
* anymore
|
|
*/
|
|
MC_TYPE MC_Take_FUN(MC_List_TYPE * list);
|
|
|
|
/** \brief remove and delete all nodes
|
|
* \param list the list
|
|
* \param deleteFunc the kill function of the node
|
|
*
|
|
* Calls the kill function for every node. The list is
|
|
* empty on return.
|
|
*/
|
|
void MC_Delete_FUN(MC_List_TYPE * list, void (*deleteFunc) (MC_TYPE node));
|
|
|
|
#ifndef MC_DO_NOT_UNDEF
|
|
#undef MC_NAME
|
|
#undef MC_TYPE
|
|
#endif
|