list_impl.h 11 KB
/**
 * \file scot/list_impl.h
 * \author  Georg Steffers <georg@steffers.org>
 * \brief   Macro which creates functions for typesafe lists by templates.
 *
 * This combines the macro definitions in \link scot/list_man.h scot/list_man.h
 * \endlink, \link scot/list_mod.h scot/list_mod.h \endlink and \link
 * scot/list_nav.h scot/list_nav.h\endlink into one macro that is
 * normally called within a c file that wants to use lists, as it provides
 * you with all functions neccesary for list handling.\n
 * Additionally the whole errorhandling code for lists is here. For that
 * there are some function prototypes of functions implemented in
 * \link list.c\endlink here. These functions do error output or will
 * throw exceptions. Which function is called depends on if 
 * \link exception.c::USE_NO_EXCEPTIONS USE_NO_EXCEPTIONS\endlink is set at
 * include time of this file, or not.
 *
 * Copyright (C)2006    Georg Steffers <georg@steffers.org>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
#ifndef  LIST_IMPL_H
#define  LIST_IMPL_H


#include <scot/exception.h>
#include <scot/scot_types.h>

/**
 * \internal
 * \param   type     the datatype that this queue code should handle.
 * \param   a        a variable holding a pointer to queue_[type]_node_t.
 *
 * \pre              Type must be a single word typename. If one wants
 *                   to use e.g. lists of structs one has to use typedef
 *                   to create a single word type name like this:
 *                   typedef struct mystruct_t mystruct_t;
 *                   a must be a valid pointer to a queue_[type]_node_t.
 * \returns          \a a cast to a pointer of list_[type]_node_t.
 * \post             None
 *
 * \brief   Cast a pointer to list_[type]_node_t.
 *
 * FIXME: I should check better the validity of \a a.
 */
#define  LIST(type, a) (list_ ## type ## _node_t *) (a)

void     list_error_print  (const char *, int, int);
void     list_warning_print  (const char *, int, int);
void     list_error_throw  (const char *, int, int);
void     list_warning_throw  (const char *, int, int);
void *   list_malloc_print (SIZE_T, const char *, int);
void     list_check_null_print (const void *, const char *, int);
void *   list_malloc_throw (SIZE_T, const char *, int);
void     list_check_null_throw (const void *, const char *, int);

#ifdef   USE_NO_EXCEPTION 
#  define  LIST_ERROR(file, line, id)                                \
      list_error_print ((file), (line), (id)) 
#  define  LIST_WARNING(file, line, id)                              \
      list_warning_print ((file), (line), (id)) 
#  define  LIST_MALLOC(size, file, line)                             \
      list_malloc_print ((size), (file), (line)) 
#  define  LIST_CHECK_NULL(val, file, line)                          \
      list_check_null_print ((void *) (val), (file), (line)) 
#  define  LIST_EXC_START 
#  define  LIST_EXC_END(file, line, id) 
#else
/**
 * \internal
 * \param   file  filename of the file where the error occured.
 * \param   line  line in the file where the error occured.
 * \param   id    list error id.
 *
 * \brief print or thow an error
 */
#  define  LIST_ERROR(file, line, id)                                \
      list_error_throw ((file), (line), (id)) 
/**
 * \internal
 * \param   file  filename of the file where the error occured.
 * \param   line  line in the file where the error occured.
 * \param   id    list error id.
 *
 * \brief print or throw a warning
 */
#  define  LIST_WARNING(file, line, id)                              \
      list_warning_throw ((file), (line), (id)) 
/**
 * \internal
 * \param   size  the amount of memory that should be reserved.
 * \param   file  filename of the file where this is called.
 * \param   line  line in the file where this is called.
 *
 * \brief list malloc wrapper
 *
 * A malloc wrapper which either print an error or throw 
 * an exception.
 */
#  define  LIST_MALLOC(size, file, line)                             \
      list_malloc_throw ((size), (file), (line)) 
/**
 * \internal
 * \param   val   variable that should be check for NULL.
 * \param   file  filename of the file where this is called.
 * \param   line  line in the file where this is called.
 *
 * \brief this checks if val is null
 */
#  define  LIST_CHECK_NULL(val, file, line)                          \
      list_check_null_throw ((void *) (val), (file), (line)) 
/**
 * \internal
 * \brief start exception environment in generated list function.
 */
#  define  LIST_EXC_START                                            \
      {                                                              \
         excenv_t *ee;                                               \
         TRY {       
/**
 * \internal
 * \brief end the exception environment of the generated list function.
 *
 * This ends the exception environment in the generated list
 * function, that was started with LIST_EXC_START.
 * Any exception that had occured will be forwarded in the upper
 * exception environment and if exceptions had occured a new one
 * will be thrown to the exception environment indicating that the
 * function fails.
 */
#  define  LIST_EXC_END(file, line, id)                              \
         }                                                           \
         CATCH (ee)                                                  \
         {                                                           \
            forward_all_exceptions (ee);                             \
            list_error_throw ((file), (line), (id));                 \
         }                                                           \
      }
#endif   /* USE_NO_EXCEPTION */

extern const char *list_err_msg[];
extern const char *list_wrn_msg[];

struct list_node_t 
{
   const char _ [sizeof (struct {
         const void  *e;
         const void  *prev;
         const void  *next;
         })];
};

#ifdef   GEN_LOCAL
/**
 * \internal
 * \brief   make functions static or not dependig on if GEN_LOCAL was
 *          defined or not.
 */
#  define   STATIC   static
#else
#  define   STATIC
#endif

#include "list_man.h"
#include "list_nav.h"
#include "list_mod.h"

/**
 * \param   type     the datatype that this list code should handle.
 * \pre              Type must be a single word typename. If one wants
 *                   to use e.g. lists of structs one has to use typedef
 *                   to create a single word type name like this:
 *                   typedef struct mystruct_t mystruct_t;
 * \return           Nothing
 * \post             The functions, struct and globals to handle typesave
 *                   lists for the given datatype are generated within the
 *                   calling build file.
 *                   FIXME: This seems not threadsafe to me, as the globals
 *                   are used within all threads. Actually one could work
 *                   around this because normally it is enough to set the
 *                   comparison functions once and dont touch them anymore
 *                   but it might be neccesary to compare elements within
 *                   the list differently in different threads.
 *
 * \brief this creates all functions, structs and globals needed for a
 *        typesafe list of a given \a type.
 *
 * In detail the following is created by this macro:\n
 * \li <b>struct list_[type]_node_t</b>: This is the structure a list
 * is constructed of. A representation of a double linked list node with
 * a pointer to the element it contains, a pointer to the next and a pointer
 * to the previous element in the list. This list implementation uses a kind
 * of a ringlist, that is the next pointer of the last node in the list
 * and the prev pointer in the first element of the list points to the anchor.
 * Thus in an empty list prev and next of the anchor both points to the
 * anchor.
 * \li <b>int list_[type]_default_cmp ()</b>: This is the default
 * comparison function for lists. It simply compares the adresses of two
 * elements. At list initialization list_[type]_compare() is set to this.
 * \li <b>list_[type]_cmp_fptr list_[type]_compare</b>: This pointer
 * to a function that compares list elements is used within the generated
 * list functions.
 * \li <b>list_[type]_elem_free_fptr list_[type]_elem_free</b>: This pointer
 * , if set to non NULL, is used in list_[type]_delete() to free an
 * element within a node before deleting the node. At initial time of
 * the list code this is set to NULL, thus elements are not freed at all.
 * (This is ok when stack variables are used, else one should at least
 * set list_[type]_elem_free to free().)
 * \li all functions defined in \link scot/list_man.h list_man.h\endlink,
 * \link scot/list_mod.h list_mod.h\endlink and 
 * \link scot/list_nav.h list_nav.h\endlink.
 */
#define  GEN_LIST_IMPL(type)                                      \
struct list_ ## type ## _node_t                                   \
{                                                                 \
   const type                       *e;                           \
   struct list_ ## type ## _node_t  *prev;                        \
   struct list_ ## type ## _node_t  *next;                        \
};                                                                \
                                                                  \
STATIC                                                            \
int list_ ## type ## _default_cmp (                               \
      const type * a,                                             \
      const type * b)                                             \
{                                                                 \
   return (a==b)?0:(a<b)?-1:1;                                    \
}                                                                 \
                                                                  \
STATIC                                                            \
list_ ## type ## _cmp_fptr                                        \
list_ ## type ## _compare = list_ ## type ## _default_cmp;        \
STATIC                                                            \
list_ ## type ## _elem_free_fptr                                  \
list_ ## type ## _elem_free = NULL;                               \
                                                                  \
GEN_LIST_MANAGEMENT  (type);                                      \
GEN_LIST_NAVIGATION  (type);                                      \
GEN_LIST_MODIFY      (type);

#endif   /* LIST_IMPL_H */