Macros For Typesafe List Handling


Defines

#define GWEN_LIST_ADD(typ, sr, head)
#define GWEN_LIST_DEL(typ, sr, head)
#define GWEN_LIST_ELEMENT(t)
#define GWEN_LIST_FINI(t, element)
#define GWEN_LIST_FUNCTION_DEFS(t, pr)   GWEN_LIST_FUNCTION_LIB_DEFS(t, pr, GWEN_DUMMY_EMPTY_ARG)
#define GWEN_LIST_FUNCTION_LIB_DEFS(t, pr, decl)
#define GWEN_LIST_FUNCTIONS(t, pr)
#define GWEN_LIST_INIT(t, element)   element->listPtr=0;
#define GWEN_LIST_INSERT(typ, sr, head)

Detailed Description

The macros of this group facilitates typesafe use of lists.

Let's assume you have a structure type called MYSTRUCT and you want to manage lists of them. Let's further assume that you want the functions dealing with that struct have prefixes like MyStruct (as in MyStruct_new) The header file would look like this:

 / * mystruct.h * /

 #ifndef MYSTRUCT_H
 #define MYSTRUCT_H

 typedef struct MYSTRUCT MYSTRUCT;

 GWEN_LIST_FUNCTION_DEFS(MYSTRUCT, MyStruct);

 struct {
   GWEN_LIST_ELEMENT(MYSTRUCT);
   int myData;
 }


 MYSTRUCT *MyStruct_new(int myData);
 void MyStruct_free(MYSTRUCT *myStruct);

 #endif

This defines all necessary data and function prototypes needed for list management.

The code file would look quite similar to the following:

 / * mystruct.c * /

 GWEN_LIST_FUNCTIONS(MYSTRUCT, MyStruct)

 MYSTRUCT *MyStruct_new(int myData) {
   MYSTRUCT *pMyStruct;

   pMyStruct=(MYSTRUCT*)malloc(sizeof(MYSTRUCT));
   memset(pMyStruct, 0, sizeof(MYSTRUCT));

   GWEN_LIST_INIT(MYSTRUCT, pMyStruct)

   pMyStruct->myData=myData;
   return pMyStruct;
 }

 void MyStruct_free(MYSTRUCT *pMyStruct) {
   if (pMyStruct) {
     pMyStruct->myData=0;
     GWEN_LIST_FINI(MYSTRUCT, pMyStruct)
     free(pMyStruct);
   }
 }
Please note the three macros used in the code file:

Note: When writing these macro code lines, the original ISO C89 standard for the C language does not allow terminating the macro statement with a semicolon ';'. Any recent compiler will probably silently ignore such an extra ';', but you should be aware that this can cause problems once one of your users tries to compile this with a different compiler. Therefore these code lines should end directly with the closing parentheses.

The list management code assumes that there is a function called (in this example) MyStruct_free() (or generally: TYPEPREFIX_free). This is used when destroying a list of MYSTRUCT elements. In this case all elements still enlisted are destroyed upon destruction of the list.


Define Documentation

#define GWEN_LIST_ADD typ,
sr,
head   ) 
 

Value:

{\
  typ *curr;                \
                            \
  assert(sr);               \
  assert(head);             \
                            \
  curr=*head;               \
  if (!curr) {              \
    *head=sr;               \
  }                         \
  else {                    \
    while(curr->next) {     \
      curr=curr->next;      \
    }                       \
    curr->next=sr;          \
  }\
  }

#define GWEN_LIST_DEL typ,
sr,
head   ) 
 

Value:

{\
  typ *curr;                   \
                               \
  assert(sr);                  \
  assert(head);                \
  curr=*head;                  \
  if (curr) {                  \
    if (curr==sr) {            \
      *head=curr->next;        \
    }                          \
    else {                     \
      while(curr->next!=sr) {  \
        curr=curr->next;       \
      }                        \
      if (curr)                \
        curr->next=sr->next;   \
    }                          \
  }                            \
  sr->next=0;\
  }

#define GWEN_LIST_ELEMENT  ) 
 

Value:

t *next; \
  t##_LIST *listPtr;
Use this inside the declaration of a struct for which you want to create lists.

#define GWEN_LIST_FINI t,
element   ) 
 

Value:

if (element) { \
  if (element->listPtr) {\
  GWEN_LIST_DEL(t, element, &(element->listPtr->first)) \
  element->listPtr->count--;\
  element->listPtr=0;\
  }\
  }
Use this in your code file (*.c) inside the fini code for the struct you want to use in lists (in GWEN these are the functions which end with "_free".

#define GWEN_LIST_FUNCTION_DEFS t,
pr   )     GWEN_LIST_FUNCTION_LIB_DEFS(t, pr, GWEN_DUMMY_EMPTY_ARG)
 

Use this in public header files to define some prototypes for list functions. Let's assume the type of your list elements is "MYTYPE" and you want to use the prefix "MyType_" for the list functions. The following function prototypes will then be created:

  • void MyType_List_Add(MYTYPE *element, MYTYPE_LIST *list);
    Adds a MYTYPE struct to the given list.
  • void MyType_List_Del(MYTYPE *element);
    Removes a MyType struct from the list it is enlisted to.
  • MYTYPE *MyType_List_First(MYTYPE *element);
    Returns the first member of the given list.
  • MYTYPE* MyType_List_Next(const MYTYPE *element);
    Returns a pointer to the object followed by the given one.
  • void MyType_List_Clear(MYTYPE *element);
    Frees all entries of the given list. This function assumes that there is a function Mytype_free().
  • MYTYPE_LIST *MyType_List_new();
    Creates a new list of elements of MYTYPE type.
  • void MyType_List_free(MYTYPE_LIST *l);
    Clears and frees a list of elements of MYTYPE type. All objects inside the list are freed.

This macro should be used in applications, not in libraries. In libraries please use the macro GWEN_LIST_FUNCTION_LIB_DEFS.

#define GWEN_LIST_FUNCTION_LIB_DEFS t,
pr,
decl   ) 
 

Value:

typedef struct t##_LIST_ELEMENT {\
  GWEN_TYPE_UINT32 id;\
  t *nextObject;\
  } t##_LIST__ELEMENT;\
  \
  typedef struct t##_LIST {\
  t *first;\
  GWEN_TYPE_UINT32 count;\
  GWEN_TYPE_UINT32 id;\
  } t##_LIST; \
  \
  decl void pr##_List_AddList(t##_LIST *dst, t##_LIST *l); \
  decl void pr##_List_Add(t *element, t##_LIST *list); \
  decl void pr##_List_Insert(t *element, t##_LIST *list); \
  decl void pr##_List_Del(t *element); \
  decl t* pr##_List_First(const t##_LIST *l); \
  decl t* pr##_List_Last(const t##_LIST *l); \
  decl void pr##_List_Clear(t##_LIST *l); \
  decl t##_LIST* pr##_List_new(); \
  decl void pr##_List_free(t##_LIST *l); \
  decl t* pr##_List_Next(const t *element); \
  decl t* pr##_List_Previous(const t *element); \
  decl GWEN_TYPE_UINT32 pr##_List_GetCount(const t##_LIST *l);
Use this in public header files to define some prototypes for list functions. Let's assume the type of your list elements is "MYTYPE" and you want to use the prefix "MyType_" for the list functions. The following function prototypes will then be created:
  • void MyType_List_Add(MYTYPE *element, MYTYPE_LIST *list);
    Adds a MYTYPE struct to the given list.
  • void MyType_List_Del(MYTYPE *element);
    Removes a MyType struct from the list it is enlisted to.
  • MYTYPE *MyType_List_First(MYTYPE *element);
    Returns the first member of the given list.
  • MYTYPE* MyType_List_Next(const MYTYPE *element);
    Returns a pointer to the object followed by the given one.
  • void MyType_List_Clear(MYTYPE *element);
    Frees all entries of the given list. This function assumes that there is a function Mytype_free().
  • MYTYPE_LIST *MyType_List_new();
    Creates a new list of elements of MYTYPE type.
  • void MyType_List_free(MYTYPE_LIST *l);
    Clears and frees a list of elements of MYTYPE type. All objects inside the list are freed.

This macro should be used in libraries with the __declspec(dllexport) declaration as the decl argument.

#define GWEN_LIST_FUNCTIONS t,
pr   ) 
 

Use this inside your code files (*.c). Actually implements the functions for which the prototypes have been defined via GWEN_LIST_FUNCTION_DEFS.

#define GWEN_LIST_INIT t,
element   )     element->listPtr=0;
 

Use this in your code file (*.c) inside the init code for the struct you want to use in lists (in GWEN these are the functions which end with "_new".

#define GWEN_LIST_INSERT typ,
sr,
head   ) 
 

Value:

{\
  typ *curr;                \
                            \
  assert(sr);               \
  assert(head);             \
                            \
  curr=*head;               \
  if (!curr) {              \
    *head=sr;               \
  }                         \
  else {                    \
    sr->next=curr;\
    *head=sr;\
  }\
  }


Generated on Sun Mar 19 21:35:21 2006 for gwenhywfar by  doxygen 1.4.6