GridLab
Grid Application Toolkit

A simple API for Grid Applications
GAT

Menu



Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

GATList.c

Go to the documentation of this file.
00001 /** @file GATList_i.c
00002  * Source file for the GATList implementation functions.
00003  *
00004  * GATList is a set of functions for implementing double linked lists of
00005  * objects of arbitrary type.
00006  *
00007  * @date Sat Sep 27 2003
00008  *
00009  * @version $Header: /export/cvs-gridlab/wp-1/Codes/GATEngine/C-reference/src/GATList.c,v 1.30 2004/04/02 12:31:57 hartmutkaiser Exp $
00010  *
00011  *  Copyright (C) Hartmut Kaiser
00012  *  This file is part of the GAT Engine.
00013  *  Contributed by Hartmut Kaiser <hartmutkaiser [at] t-online [dot] de>.
00014  *
00015  *  Use, modification and distribution is subject to the Gridlab Software
00016  *  License. (See accompanying file GLlicense.txt or copy at
00017  *  http://www.gridlab.org/GLlicense.txt)
00018  */
00019  
00020 static const char *rcsid = "$Header: /export/cvs-gridlab/wp-1/Codes/GATEngine/C-reference/src/GATList.c,v 1.30 2004/04/02 12:31:57 hartmutkaiser Exp $";
00021  
00022 #include <stdlib.h>
00023 #include <assert.h>
00024 #include <string.h>
00025 
00026 #include "GATUtil.h"
00027 #include "GATInternal.h"
00028 #include "GATErrors.h"
00029 #include "GATType.h"
00030 #include "GATObject.h"
00031 #include "GATString.h"
00032 #include "GATList.h"
00033 
00034 #include "GATXdsWrapper.h"
00035 #include "GATMemoryStream.h"
00036 
00037 #define MAGIC_GATLIST           0x12345678UL
00038 #define MAGIC_GATLISTNODE       0x87654321UL
00039 
00040 /* define the vtable types */
00041 GATOBJECT_DEFINE_VTABLE(GATList);
00042 GATSERIALISABLE_DEFINE_VTABLE(GATList);
00043 
00044 /* Declare the converters to/from GATObject */
00045 GATOBJECT_DEFINE_CONVERTERS(GATList);
00046 GATOBJECT_DEFINE_CONVERTERS_QUALIFIED(extern, GATList_String, GATType_GATList);
00047 
00048 /*
00049  *  This is the internal structure, which represents a GATListNode object.
00050  */
00051 typedef struct GATListNode_S {
00052   unsigned long magic;          /* magic number (set to MAGIC_GATLISTNODE) */
00053   struct GATListNode_S *next;   /* next node in the chain */
00054   struct GATListNode_S *prev;   /* previous node in the chain */
00055   char *data;                   /* dynamically allocated data held by this */
00056 } GATListNode_S;
00057 
00058 /*
00059  *  This is the internal structure, which represents a GATList object.
00060  */
00061 typedef struct GATList_S {
00062   /* the GATObject vtable for this object */
00063   GATList_vtable *GATObject__vtable;  
00064   /* the GATSerialisable vtable for this object */
00065   GATList_ISerialisable_vtable *GATSerialisable__vtable;  
00066   
00067   unsigned long magic;          /* magic number (set to MAGIC_GATLIST) */
00068   GATType element_type;         /* the GATType of the list elements */
00069   GATuint32 nodesize;           /* size of data, held by this list */
00070   GATListNode_S *begin;         /* first node of the chain */
00071   GATuint32 num_of_elements;    /* number of elements in this list */
00072   GATBool isdirty;              /* dirty status (changed since last write) */
00073 } GATList_S;
00074 
00075 /* static function declarations */
00076 static GATResult
00077   GATList_i_Compare(GATType type, GATuint32 size, 
00078     GATListIterator_const lhs_first, GATListIterator_const lhs_last,
00079     GATListIterator_const rhs_first, GATBool *isequal);
00080     
00081 static GATListNode_S *
00082   GATListNode_Create(size_t nodesize);
00083 
00084 static GATListNode_S *
00085   GATList_Splice(GATList_S *dest, GATListNode_S *iter, 
00086     GATList_S *src, GATListNode_S *first, GATListNode_S *last, 
00087     size_t count);
00088 
00089 static size_t
00090   GATList_Distance(GATListIterator_const first, GATListIterator_const last);
00091 
00092 static GATResult 
00093   GATList_i_SerialiseItems(GATList_const list, GATXds xds,
00094     GATXdsScope flag, void **buffer, size_t *buffer_size, GATBool clear_dirty);
00095 
00096 static GATResult
00097 GATList_DeSerialise_Create(GATContext context, GATXds xds, GATType element_type, 
00098   GATuint32 nodesize, GATuint32 num_of_elements, GATList *list);
00099 
00100 static GATResult
00101 GATList_DeSerialise_Items(GATContext context, GATList new_list, GATXds xds, 
00102   GATObject stream, GATType element_type, GATuint32 num_of_elements);
00103 
00104 /* File scope variables */
00105 static GATList_vtable GATList__vtable = {
00106   GATList_i_GetType,
00107   GATList_i_Destroy,
00108   GATList_i_Equals,
00109   GATList_i_Clone,
00110   GATList_i_GetInterface,
00111   NULL
00112 };
00113 
00114 static GATList_ISerialisable_vtable GATList_ISerialisable__vtable = {
00115   GATList_i_Serialise,
00116   GATList_i_DeSerialise,
00117   GATList_i_GetIsDirty
00118 };
00119 
00120 
00121 /* external functions */
00122 
00123 /** GATList_Register_GATSerialisable
00124  *  The GATList_Register_GATSerialisable function registers the serialization
00125  *  vtable with the GAT engine to allow generic object creation.
00126  *  This function is called by the GAT engine, there is no need to use it 
00127  *  directly.
00128  */
00129 GATResult GATList_Register_GATSerialisable()
00130 {
00131   return GATObject_Register_GATSerialisable(GATType_GATList, 
00132     &GATList_ISerialisable__vtable);
00133 }
00134 
00135 /** GATList GATList_i_Create(GATType type, size_t nodesize)
00136  *  @internal This function belongs to the internal GATList API, do not use it
00137  *        directly.
00138  *  @brief Creates a new generic list
00139  *
00140  *  The function @c GATList_i_Create creates a new generic list @c GATList, which 
00141  *  holds arbitrary objects of the given @c nodesize. 
00142  *
00143  *  @param type The type identifier of the data to be stored in this list.
00144  *  @param nodesize Is the size of one data item to be held by this list.
00145  *
00146  *  @return Returns a handle to the newly created list. If an error occures
00147  *        0 (zero) is returned.
00148  */
00149 GATList 
00150 GATList_i_Create(GATType type, size_t nodesize)
00151 {
00152   GATListNode_S *newnode = NULL;
00153   GATList_S *newlist = NULL;
00154   
00155   /* validate parameters */ 
00156   assert(nodesize != 0);
00157   if (nodesize != 0) 
00158   {
00159     /* allocate a new list head structure */
00160     newlist = (struct GATList_S *)malloc(sizeof(GATList_S));   
00161     if (NULL != newlist) 
00162     {
00163       /* initialize members */
00164       memset(newlist, 0, sizeof(GATList_S));
00165       newlist->GATObject__vtable = &GATList__vtable;
00166       newlist->GATSerialisable__vtable = &GATList_ISerialisable__vtable;
00167       
00168       newlist->magic = MAGIC_GATLIST;
00169       newlist->element_type = type;
00170       newlist->nodesize = nodesize;
00171       newlist->isdirty = GATFalse;
00172 
00173       /* allocate the end of list node */    
00174       newnode = GATListNode_Create(0);  
00175       if (NULL == newnode) 
00176       {
00177         free(newlist);
00178         newlist = NULL;
00179       }
00180       else 
00181       {
00182         newnode->next = newnode->prev = newnode;
00183         newlist->begin = newnode;
00184       }
00185     }
00186   }
00187   return (GATList) newlist;
00188 }
00189 
00190 /** int GATList_i_Equals(GATList_const lhs, GATList_const rhs, GATBool *isequal)
00191  *  @internal This function belongs to the internal GATList API, do not use it
00192  *        directly.
00193  *  @brief Compares two generic lists
00194  *
00195  *  The function @c GATList_i_Equals compares two generic lists @c #GATList.
00196  *
00197  *  @param lhs The first list to compare
00198  *  @param rhs The second list to compare
00199  *  @param isequal The pointer to the GATBool variable, which should receive 
00200  *        the result if the comparision
00201  *
00202  *  @return An error code.
00203  */
00204 GATResult
00205 GATList_i_Equals(GATList_const lhs, GATList_const rhs, GATBool *isequal)
00206 {
00207   GATList_S const *lhs_list = lhs;
00208   GATList_S const *rhs_list = rhs;
00209   GATResult result = GAT_INVALID_PARAMETER;
00210   
00211   if (NULL != lhs_list && NULL != rhs_list && NULL != isequal)
00212   {
00213     assert(MAGIC_GATLIST == lhs_list->magic && 
00214       MAGIC_GATLIST == rhs_list->magic);
00215     if (lhs_list->magic != MAGIC_GATLIST || rhs_list->magic != MAGIC_GATLIST) 
00216     {
00217       result = GAT_INVALID_HANDLE;
00218     }
00219     else
00220     {
00221       if (lhs_list->element_type == rhs_list->element_type &&
00222           lhs_list->num_of_elements == rhs_list->num_of_elements)
00223       {
00224         /* types and sizes match, so make a deep compare */
00225         result = GATList_i_Compare(lhs_list->element_type, lhs_list->nodesize,
00226           GATList_i_Begin(lhs_list), GATList_i_End(lhs_list), 
00227           GATList_i_Begin(rhs_list), isequal);
00228       }
00229       else
00230       {
00231         *isequal = GATFalse;
00232         result = GAT_SUCCESS;
00233       }
00234     }
00235   }
00236   
00237   return result;
00238 }
00239 
00240 /** int GATList_i_GetType(GATList_const listhandle)
00241  *  @internal This function belongs to the internal GATList API, do not use it
00242  *        directly.
00243  *  @brief Return the type of the GATList
00244  *
00245  *  The function @c GATList_type_GetType always returns GATType_GATList. 
00246  *
00247  *  @param object The object to inspect
00248  *
00249  *  @return returns always @c #GATType_GATList.
00250  */
00251 GATType GATList_i_GetType(GATList_const list)
00252 {
00253   GAT_UNUSED_PARAMETER(list);
00254   return GATType_GATList;
00255 }
00256 
00257 /** int GATList_i_Clone(GATList_const list, GATList *new_list)
00258  *  @internal This function belongs to the internal GATList API, do not use it
00259  *        directly.
00260  *  @brief Clone the given list
00261  *
00262  *  The function @c GATList_type_Clone generates a (deep) copy of the given
00263  *  list. 
00264  *
00265  *  @param listhandle The object to clone
00266  *  @param new_listhandle The pointer, through which the result is to be 
00267  *        returned.
00268  *
00269  *  @return An error type.
00270  */
00271 GATResult GATList_i_Clone(GATList_const listhandle, GATList *new_listhandle)
00272 {
00273   GATResult result = GAT_INVALID_HANDLE;
00274   if (NULL != listhandle)
00275   {
00276     GATList_S const*list = listhandle;
00277     GATList new_list = GATList_i_Create(list->element_type, list->nodesize);
00278     
00279     if (NULL == new_list)
00280     {
00281       result = GAT_MEMORYFAILURE;
00282     }
00283     else
00284     {
00285       GATListIterator it = GATList_i_Begin(listhandle);
00286       GATListIterator end = GATList_i_End(listhandle);
00287       
00288       result = GAT_SUCCESS;   /* empty lists should be copied correctly */
00289       for (/**/; it != end; it = GATList_i_Next(it))
00290       {
00291         switch(list->element_type)
00292         {
00293           case GATType_GATint32:
00294           case GATType_GATint16:
00295           case GATType_GATfloat32:
00296           case GATType_GATdouble64:
00297           case GATType_PlainOldData:
00298             result = (NULL != GATList_i_Insert(new_list, GATList_i_End(new_list), 
00299               GATList_i_Get(it))) ? GAT_SUCCESS : GAT_MEMORYFAILURE;
00300             break;
00301             
00302           default:
00303             if (list->element_type & GATType_GATObject)
00304             {
00305               /* GATList_i_Insert clones GATObject's */
00306               result = (NULL != GATList_i_Insert(new_list, GATList_i_End(new_list), 
00307                 GATList_i_Get(it))) ? GAT_SUCCESS : GAT_MEMORYFAILURE;
00308             }
00309             else
00310             {
00311               result = GAT_NOTIMPL;
00312             }
00313         }
00314         
00315         if (GAT_SUCCESS != result)
00316         {
00317           break;
00318         }
00319       }
00320       
00321       if (GAT_SUCCESS == result)
00322       {
00323         new_list->isdirty = GATFalse;
00324         *new_listhandle = new_list;
00325       }
00326       else
00327       {
00328         /* destroy, what's allocated so far */
00329         GATList_i_Destroy(&new_list);
00330       }
00331     }
00332   }
00333   return result;
00334 }
00335 
00336 /** int GATList_GetInterface(GATList_const list, GATInterface iftype, void const **ifp)
00337  *  @brief Get an interface supported by a GATList
00338  *
00339  *  The function GATList_GetInterface allows to get a pointer to an 
00340  *  additional interface supported by this GATList.
00341  *
00342  *  @param object The object to be asked for the new interface.
00343  *  @param iftype The interface the object is to be asked for.
00344  *  @param ifp The pointer, through which the result is to be returned.
00345  *
00346  *  @return An error type.
00347  */
00348 GATResult 
00349 GATList_i_GetInterface(GATList_const list, GATInterface iftype, void const **ifp)
00350 {
00351   GATResult retval = GAT_INVALID_PARAMETER;
00352 
00353   if (NULL != ifp && NULL != list)
00354   {
00355     *ifp = NULL;
00356     if (GATInterface_ISerialisable == iftype)
00357     {
00358       *ifp = (void const *) &list->GATSerialisable__vtable;
00359       retval = GAT_SUCCESS;
00360     }
00361     else
00362     {
00363       retval = GAT_NO_INTERFACE;
00364     }
00365   }
00366   return retval;
00367 }
00368 
00369 /** int GATList_i_Destroy(GATList *listhandle)
00370  *  @internal This function belongs to the internal GATList API, do not use it
00371  *        directly.
00372  *  @brief Destroy the given list and all of its contents
00373  *
00374  *  The function @c GATList_i_Destroy destroys the given list and all of its
00375  *  elements. If during creation time of this list there was specified a 
00376  *  @c destroyfunc, this function will be called for every element to be 
00377  *  destroyed. 
00378  *
00379  *  @param listhandle The list to be destroyed. If this parameter is 0 (zero) 
00380  *        the function does nothing, but returns @c #GAT_SUCCESS.
00381  *
00382  *  @return Returns @c #GAT_SUCCESS if the list was destroyed successfully or 
00383  *        if the listhandle parameter was 0 (zero). If the given parameter was 
00384  *        not a valid list (but not equal zero), then @c #GAT_INVALID_HANDLE 
00385  *        is returned.
00386  */
00387 void 
00388 GATList_i_Destroy(GATList *listhandle)
00389 {
00390   GATListNode_S *nextnode = NULL;
00391   GATListNode_S *current_node = NULL;
00392   
00393   /* if the given listhandle is 0 (zero), then do nothing */
00394   if (NULL != listhandle && NULL != *listhandle)
00395   {
00396     GATList_S *list = *listhandle;
00397     
00398     /* validate parameters */ 
00399     assert(list->magic == MAGIC_GATLIST);
00400     if (list->magic == MAGIC_GATLIST) 
00401     {
00402       /* erase all remaining elements */
00403       current_node = list->begin->next;
00404       list->begin->next = list->begin;
00405       list->begin->prev = list->begin;
00406       list->num_of_elements = 0;
00407 
00408       for (/**/; current_node != list->begin; current_node = nextnode) 
00409       {
00410         /* delete one element */
00411         nextnode = current_node->next;
00412 
00413         /* deallocate node */
00414         switch(list->element_type)
00415         {
00416           case GATType_GATint16:
00417           case GATType_GATint32:
00418           case GATType_GATfloat32:
00419           case GATType_GATdouble64:
00420           case GATType_PlainOldData:
00421             /* nothing special to do here */
00422             break;
00423             
00424           default:
00425             if (GATType_GATObject & list->element_type)
00426             {
00427               /* destroy this object */
00428               GATObject_Destroy((GATObject *) current_node->data);
00429             }
00430             else
00431             {
00432               /* this should not happen */
00433               assert(GATType_GATObject & list->element_type);
00434             }
00435             break;
00436         }        
00437         free(current_node);
00438       }
00439       
00440       free(list->begin);  /* free the head node */
00441       free(list);         /* free the list structure itself */
00442       
00443       *listhandle = NULL;
00444     }
00445   }
00446 }
00447 
00448 /** size_t GATList_i_Size(GATList listhandle)
00449  *  @internal This function belongs to the internal GATList API, do not use it
00450  *        directly.
00451  *  @brief Return the number of elements stored inside a list
00452  *
00453  *  The function @c GATList_i_Size returns the number of elements, currently
00454  *  stored inside the given list.
00455  *
00456  *  @param listhandle The list to be queried for its number of elements
00457  *
00458  *  @return If successful, the number of elements is returned. If an error 
00459  *        occures, (size_t)(-1) is returned.
00460  */
00461 size_t 
00462 GATList_i_Size(GATList_const listhandle)
00463 {
00464   GATList_S const *list = listhandle;
00465   size_t size = (size_t)(-1);
00466   
00467   /* validate parameters */    
00468   assert(list->magic == MAGIC_GATLIST);
00469   if (list->magic == MAGIC_GATLIST) 
00470   {
00471     /* just return the number of elements */    
00472     size = list->num_of_elements;
00473   }
00474   return size;
00475 }
00476 
00477 /** GATListIterator GATList_i_Begin(GATList listhandle)
00478  *  @internal This function belongs to the internal GATList API, do not use it
00479  *        directly.
00480  *  @brief Return a pointer to the first element of the list
00481  *
00482  *  The function @c GATList_i_Begin returns a @c GATListIterator 
00483  *  pointing to the first element of the inspected list.
00484  *
00485  *  @param listhandle The list to be queried for its begin iterator
00486  *
00487  *  @return If successful, the function returns the begin iterator of the list. 
00488  *        If an error occures, 0 (zero) is returned.
00489  */
00490 GATListIterator 
00491 GATList_i_Begin(GATList_const listhandle)
00492 {
00493   GATList_S const *list = listhandle;
00494   GATListIterator begin = NULL;
00495   
00496   /* validate parameters */    
00497   assert(list->magic == MAGIC_GATLIST);
00498   if (list->magic == MAGIC_GATLIST) 
00499   {
00500     begin = list->begin->next;
00501   }
00502   return begin;
00503 }
00504 
00505 /** GATListIterator GATList_i_End(GATList listhandle)
00506  *  @internal This function belongs to the internal GATList API, do not use it
00507  *        directly.
00508  *  @brief Return a pointer to the first element beyond the last element of the 
00509  *        list.
00510  *
00511  *  The function @c GATList_i_End returns a @c GATListIterator 
00512  *  pointing to the first element beyond the last of element of the the 
00513  *  inspected list. Please note, that the returned @c GATListIterator may 
00514  *  @b not be used for accessing a valid element of the list, it may be used 
00515  *  for testing against the end of list condition only.
00516  *
00517  *  @param listhandle The list to be queried for its begin iterator
00518  *
00519  *  @return If successful, the function returns the end iterator of the list. 
00520  *        If an error occures, 0 (zero) is returned.
00521  */
00522 GATListIterator 
00523 GATList_i_End(GATList_const listhandle)
00524 {
00525   GATList_S const *list = listhandle;
00526   GATListIterator end = NULL;
00527   
00528   /* validate parameters */    
00529   assert(list->magic == MAGIC_GATLIST);
00530   if (list->magic == MAGIC_GATLIST) 
00531   {
00532     end = list->begin;
00533   }
00534   return end;
00535 }
00536 
00537 /** GATListIterator GATList_i_Next(GATListIterator iter)
00538  *  @internal This function belongs to the internal GATList API, do not use it
00539  *        directly.
00540  *  @brief Return a pointer to the next element beyond the given iterator.
00541  *
00542  *  The function @c GATList_i_Next returns a @c GATListIterator 
00543  *  pointing to the list element following the element, to which points the 
00544  *  given iterator. 
00545  *
00546  *  @param iter The iterator, which is to be incremented
00547  *
00548  *  @return If successful, the function returns the next iterator of the given
00549  *        one. If the end of the list is reached, the function returns an 
00550  *        iterator, which has the same value as the iterator returned by the
00551  *        function @c #GATList_i_End.
00552  *        If an error occures, 0 (zero) is returned.
00553  *
00554  *  @remark Calling this function with an end iterator of a list will result in 
00555  *        undefined behaviour.
00556  */
00557 GATListIterator 
00558 GATList_i_Next(GATListIterator_const iterator)
00559 {
00560   GATListNode_S const *current_node = iterator;
00561   GATListIterator next = NULL;
00562   
00563   /* validate parameters */    
00564   assert(current_node->magic == MAGIC_GATLISTNODE);
00565   if (current_node->magic == MAGIC_GATLISTNODE) 
00566   {
00567     next = current_node->next;
00568   }
00569   return next;
00570 }
00571 
00572 /** GATListIterator GATList_i_Previous(GATListIterator iter)
00573  *  @internal This function belongs to the internal GATList API, do not use it
00574  *        directly.
00575  *  @brief Return a pointer to the element preceeding the given iterator.
00576  *
00577  *  The function @c GATList_i_Previous returns a @c GATListIterator 
00578  *  pointing to the list element preceeding the element, to which points the 
00579  *  given iterator. 
00580  *
00581  *  @param iter The iterator, which is to be decremented
00582  *
00583  *  @return If successful, the function returns the previous iterator of the 
00584  *        given one. 
00585  *        If an error occures, 0 (zero) is returned.
00586  *
00587  *  @remark Calling this function with an begin iterator of a list will result 
00588  *        in  undefined behaviour.
00589  */
00590 GATListIterator 
00591 GATList_i_Previous(GATListIterator_const iterator)
00592 {
00593   GATListNode_S const *current_node = iterator;
00594   GATListIterator prev = NULL;
00595   
00596   /* validate parameters */    
00597   assert(current_node->magic == MAGIC_GATLISTNODE);
00598   if (current_node->magic == MAGIC_GATLISTNODE) 
00599   {
00600     prev = current_node->prev;
00601   }
00602   return prev;
00603 }
00604 
00605 /** GATListIterator GATList_i_Insert(GATList list, GATListIterator where, void *data)
00606  *  @internal This function belongs to the internal GATList API, do not use it
00607  *        directly.
00608  *  @brief Insert a new element into a list.
00609  *
00610  *  The function @c GATList_i_Insert inserts the new element pointed to by 
00611  *  @c data into the given list. The new element is inerted just before the 
00612  *  element pointed to by the iterator @c where.
00613  *
00614  *  @param list The list, into which the new element is to be inserted.
00615  *  @param where The position inside the list, where the new element is to be 
00616  *        inserted.
00617  *  @param data The pointer to the new element, a copy of which is to be 
00618  *        inserted into the list.
00619  *
00620  *  @return If successful, the function returns an iterator pointing to the 
00621  *        newly inserted element
00622  *        If an error occures, 0 (zero) is returned.
00623  */
00624 GATListIterator 
00625 GATList_i_Insert(GATList listhandle, GATListIterator iterator, 
00626   void const *data)
00627 {
00628   GATListNode_S *newnode = NULL;
00629   GATList_S *list = listhandle;
00630   GATListNode_S *current_node = iterator;
00631   
00632   /* validate parameters */    
00633   assert(list->magic == MAGIC_GATLIST);
00634   assert(current_node->magic == MAGIC_GATLISTNODE);
00635   if ((list->magic == MAGIC_GATLIST) && 
00636       (current_node->magic == MAGIC_GATLISTNODE)) 
00637   {
00638     /* allocate the end of list node */    
00639     newnode = GATListNode_Create(list->nodesize);  
00640     if (NULL != newnode) 
00641     {
00642       if (list->element_type & GATType_GATObject)
00643       {
00644         /* GATObject's have to be cloned before inserting into the list */
00645         GATObject new_object = NULL;
00646         GATObject_Clone(*(GATObject const *) data, &new_object);
00647         if (NULL != new_object)
00648         {
00649           memcpy(newnode->data, &new_object, list->nodesize);
00650         }
00651         else
00652         {
00653           /* something went wrong :-( */
00654           free(newnode);
00655           newnode = NULL;
00656         }
00657       }
00658       else
00659       {
00660         /* copy the data into the node */
00661         memcpy(newnode->data, data, list->nodesize);
00662       }
00663       
00664       if (NULL != newnode)
00665       {
00666         /* link the new node into the chain */
00667         newnode->next = current_node;
00668         newnode->prev = current_node->prev;
00669         current_node->prev = newnode;
00670         newnode->prev->next = newnode;
00671 
00672         /* adjust list size */
00673         ++list->num_of_elements;
00674         list->isdirty = GATTrue;
00675       }
00676     }
00677   }
00678   return (GATListIterator) newnode;
00679 }
00680 
00681 /** GATListIterator GATList_i_Erase(GATList list, GATListIterator where)
00682  *  @internal This function belongs to the internal GATList API, do not use it
00683  *        directly.
00684  *  @brief Remove an existing element from a list.
00685  *
00686  *  The function @c GATList_i_Erase removes the existing element pointed to 
00687  *  by the iterator @c where from the given list. If during creation time of 
00688  *  the list there was specified a @c destroyfunc, this function will be called 
00689  *  for the element to be destroyed.
00690  *
00691  *  @param list The list, from which the existing element is to be removed.
00692  *  @param where The position inside the list, where the new element is to be 
00693  *        inserted.
00694  *
00695  *  @return If successful, the function returns an iterator pointing to the 
00696  *        next element adjacent to the removed element.
00697  *        If an error occures, 0 (zero) is returned.
00698  */
00699 GATListIterator 
00700 GATList_i_Erase(GATList listhandle, GATListIterator iterator)
00701 {
00702   GATList_S *list = listhandle;
00703   GATListNode_S *current_node = iterator;
00704   GATListNode_S *next_node = NULL;
00705 
00706   /* validate parameters */    
00707   assert(list->magic == MAGIC_GATLIST);
00708   assert(current_node->magic == MAGIC_GATLISTNODE);
00709   if ((list->magic == MAGIC_GATLIST) &&
00710       (current_node->magic == MAGIC_GATLISTNODE))
00711   {
00712     next_node = current_node->next;
00713     if (current_node != list->begin) 
00714     {
00715       /* not the list head, so it's safe to erase it */
00716       current_node->prev->next = current_node->next;
00717       current_node->next->prev = current_node->prev;
00718 
00719       /* adjust list size */
00720       --list->num_of_elements;
00721       list->isdirty = GATTrue;
00722       
00723       /* deallocate node */
00724       switch(list->element_type)
00725       {
00726         case GATType_GATint16:
00727         case GATType_GATint32:
00728         case GATType_GATfloat32:
00729         case GATType_GATdouble64:
00730         case GATType_PlainOldData:
00731           /* nothing special to do here */
00732           break;
00733           
00734         default:
00735           if (GATType_GATObject & list->element_type)
00736           {
00737             /* destroy this object */
00738             GATObject_Destroy((GATObject *) current_node->data);
00739           }
00740           else
00741           {
00742             /* this should not happen */
00743             assert(GATType_GATObject & list->element_type);
00744           }
00745           break;
00746       }        
00747       
00748       free(current_node);
00749     }
00750   }
00751   return next_node;
00752 }
00753 
00754 /** void *GATList_i_Get(GATList_type_Iterator where)
00755  *  @internal This function belongs to the internal GATList API, do not use it
00756  *        directly.
00757  *  @brief Access the data of a stored element of a list.
00758  *
00759  *  The function @c GATList_i_Get allows to access the data stored inside an 
00760  *  element of a list. It returns a pointer to the contained data.
00761  *
00762  *  @param where The position inside the list, from which the stored data is to 
00763  *        be returned.
00764  *
00765  *  @return If successful, the function returns a pointer to the data stored 
00766  *        inside the referenced list element.
00767  *        If an error occures, 0 (zero) is returned.
00768  */
00769 void *
00770 GATList_i_Get(GATListIterator_const iterator)
00771 {
00772   GATListNode_S const *current_node = iterator;
00773   void *data = NULL;
00774   
00775   /* validate parameters */    
00776   assert(current_node->magic == MAGIC_GATLISTNODE);
00777   if (current_node->magic == MAGIC_GATLISTNODE) 
00778   {
00779     data = current_node->data;
00780   }
00781   return data;
00782 }
00783 
00784 /** GATListIterator GATList_i_Splice(GATList dest, GATListIterator where, GATList source, GATListIterator first, GATListIterator last, size_t count)
00785  *  @internal This function belongs to the internal GATList API, do not use it
00786  *        directly.
00787  *  @brief Removes elements from the source list and inserts them into the 
00788  *        destination list.
00789  *
00790  *  The function @c GATList_i_Splice allows to remove a sequence of elements
00791  *  from an source list and inserts this sequence into a destination list. The 
00792  *  source and the destination list may refer to be the same list.
00793  *
00794  *  @param dest The destination list, where the sequence is to be inserted.
00795  *  @param where The position inside the destination list, where the sequence 
00796  *        is to be inserted.
00797  *  @param source The source list, from where the sequence is to be taken.
00798  *  @param first The starting position inside the source list of the sequence 
00799  *        to transfer.
00800  *  @param last The end position inside the source list of the sequence to
00801  *        transfer. This parameter may be 0 (zero), in which case the end of 
00802  *        the source list is assumed.
00803  *  @param count The number of elements in the sequence to transfer. This 
00804  *        parameter is an optimization aid and may be set to 0 (zero), in which 
00805  *        case the number of elements to transfer is determined.
00806  *
00807  *  @return If successful, the function returns an iterator pointing to the 
00808  *        first element beyond the newliy inserted sequence.
00809  *        If an error occures, 0 (zero) is returned.
00810  */
00811 GATListIterator_const 
00812 GATList_i_Splice(
00813   GATList desthandle, GATListIterator herehandle, 
00814   GATList srchandle, GATListIterator firsthandle, 
00815   GATListIterator lasthandle, size_t count)
00816 {
00817   GATList_S *dest = desthandle;
00818   GATList_S *src = srchandle;
00819   GATListNode_S *here = herehandle;
00820   GATListNode_S *first = firsthandle;
00821   GATListNode_S *last = lasthandle;
00822   
00823   /* validate parameters */    
00824   assert(dest->magic == MAGIC_GATLIST);
00825   assert(src->magic == MAGIC_GATLIST);
00826   assert(here->magic == MAGIC_GATLISTNODE);
00827   assert(first->magic == MAGIC_GATLISTNODE);
00828   assert((NULL == last) || (last->magic == MAGIC_GATLISTNODE));
00829   if ((src->magic == MAGIC_GATLIST) &&
00830       (dest->magic == MAGIC_GATLIST) &&
00831       (here->magic == MAGIC_GATLISTNODE) &&
00832       (first->magic == MAGIC_GATLISTNODE) &&
00833       ((NULL == last) || (last->magic == MAGIC_GATLISTNODE)))
00834   {
00835     /* fill in default parameter last, if appropriate */
00836     if (NULL == last)
00837     {
00838       last = src->begin;
00839     }
00840   
00841     /* test, whether it's worth doing something */
00842     if (first != last && ((dest != src) || (here != last)))
00843     {
00844       /* fill in default parameter count, if appropriate */
00845       if (0 == count)
00846       {
00847         if (dest == src)
00848         {
00849           /* rearrange the list */
00850         }
00851         else if (first == src->begin->next && last == src->begin)
00852         {
00853           /* splice in the whole list */
00854           count = src->num_of_elements;
00855         }
00856         else
00857         {
00858           /* splice in partial list */
00859           count = GATList_Distance(first, last);
00860         }
00861       }
00862       GATList_Splice(dest, here, src, first, last, count);
00863 
00864       dest->isdirty = GATTrue;
00865       src->isdirty = GATTrue;
00866     }
00867   }
00868   else
00869   {
00870     here = NULL;
00871   }
00872   return here;
00873 }
00874 
00875 
00876 /* GATAdvertiseable API */
00877 
00878 /** int GATList_Serialise(GATList_const list, GATObject stream, GATBool clear_dirty)
00879  *  @brief Serialise a GATList object
00880  *
00881  *  The function GATList_Serialise serialises the given GATList object into the
00882  *  given stream. 
00883  *
00884  *  @param file The GATList object to serialise.
00885  *  @param stream The stream interface to use for the serialisation.
00886  *  @param clear_dirty If the clear_dirty parameter is set to GATTrue, the 
00887  *        internal dirty flag of this object is to be reset (no used here)
00888  *
00889  *  @return An error code.
00890  */
00891 GATResult GATList_i_Serialise(GATList list, GATObject stream, 
00892   GATBool clear_dirty)
00893 {
00894   int retval = GAT_INVALID_HANDLE;
00895   if (NULL != list)
00896   {
00897     GATXds xds = NULL;
00898     void *xds_buffer = NULL;
00899     GATuint32 xds_buffer_size = 0;
00900     void *xds_item_buffer = NULL;
00901     GATuint32 xds_item_buffer_size = 0;
00902     
00903     if (GAT_SUCCESS == (retval = GATXds_Init(&xds, GATXdsType_Encode)) &&
00904         GAT_SUCCESS == (retval = GATXds_Encode(xds, GATXdsScope_Gift, 
00905           &xds_buffer, (size_t *) &xds_buffer_size, "uint32 uint32 uint32 uint32", 
00906           GATLIST_VERSION1, list->element_type, list->nodesize, 
00907           list->num_of_elements)) &&
00908         GAT_SUCCESS == (retval = GATList_i_SerialiseItems(list, xds,
00909           GATXdsScope_Gift, &xds_item_buffer, (size_t *) &xds_item_buffer_size, 
00910           clear_dirty)))
00911     {
00912       /* write the buffer len to ease de-serialisation */
00913       void *xds_size_buffer = NULL;
00914       GATuint32 xds_size_buffer_size = 0;
00915       
00916       if (GAT_SUCCESS == (retval = GATXds_Encode(xds, GATXdsScope_Gift,
00917             &xds_size_buffer, (size_t *) &xds_size_buffer_size, "uint32", 
00918             xds_buffer_size + xds_item_buffer_size)))
00919       {
00920         assert(NULL != xds_size_buffer);
00921         retval = GATStreamable_Write(stream, xds_size_buffer, 
00922           xds_size_buffer_size, 0);
00923         if (GAT_SUCCESS == retval)
00924         {
00925           /* write the GATList instance data */
00926           assert(NULL != xds_buffer);
00927           retval = GATStreamable_Write(stream, xds_buffer, xds_buffer_size, 0);
00928         }
00929         
00930         if (GAT_SUCCESS == retval)
00931         {
00932           /* write the GATList item data */
00933           retval = GATStreamable_Write(stream, xds_item_buffer, 
00934             xds_item_buffer_size, 0);
00935             
00936           if (GAT_SUCCESS == retval && clear_dirty)
00937           {
00938             list->isdirty = GATFalse;   /* clear the dirty flag of this list */
00939           }
00940         }
00941       }
00942       free(xds_size_buffer);
00943     }
00944     free(xds_item_buffer);
00945     free(xds_buffer);
00946     GATXds_Destroy(&xds);
00947   }
00948   return retval;
00949 }
00950 
00951 /** GATList GATList_DeSerialise(GATContext context, GATObject stream, GATBool clear_dirty)
00952  *  @brief De-serialise a GATList object
00953  *
00954  *  The function GATList_DeSerialise de-serialises a streamed GATList object  
00955  *  from the given stream  It constructs a new instance of the de-serialised 
00956  *  object.
00957  *
00958  *  @param context The GAT context to be used for object construction.
00959  *  @param stream The stream interface to use for the serialisation.
00960  *  @param result The pointer to a variable, which receives the status code of
00961  *        the operation.
00962  *
00963  *  @return The newly constructed GATList object.
00964  */
00965 GATList GATList_i_DeSerialise(GATContext context, GATObject stream, 
00966   GATResult *result)
00967 {
00968   GATList list = NULL;
00969   char buffer[64];          /* seems to be sufficient for a GATuint32 value */
00970   GATuint32 xds_read_bytes = 0;
00971   GATResult retval = GATStreamable_Read(stream, buffer, sizeof(buffer), 
00972     &xds_read_bytes);
00973   
00974   if (GAT_SUCCESS == retval)
00975   {
00976     GATXds xds = NULL;
00977 
00978     if (GAT_SUCCESS == (retval = GATXds_Init(&xds, GATXdsType_Decode)))
00979     {
00980       GATuint32 xds_buffer_size = 0;
00981       
00982       /* read the expected size of the stream for this object */
00983       retval = GATXds_Decode(xds, GATXdsScope_Loan, buffer, 
00984         sizeof(buffer), "uint32", &xds_buffer_size);
00985       if (GAT_SUCCESS == retval)
00986       {
00987         /* reposition the input stream to start with the real object data */
00988         retval = GATStreamable_Seek(stream, GATOrigin_Current, 
00989           GATXds_GetBufferLen(xds) - xds_read_bytes, 0);
00990           
00991         if (GAT_SUCCESS == retval)
00992         {
00993           /* read the object data itself */
00994           char *xds_buffer = (char *)malloc(xds_buffer_size);
00995           if (NULL == xds_buffer)
00996           {
00997             retval = GAT_MEMORYFAILURE;
00998           }
00999           else if (GAT_SUCCESS == (retval = GATStreamable_Read(stream, 
01000               xds_buffer, xds_buffer_size, 0)))
01001           {
01002             /* read the version */
01003             GATuint32 version = 0;
01004 
01005             retval = GATXds_Decode(xds, GATXdsScope_Gift, xds_buffer, 
01006               xds_buffer_size, "uint32", &version);
01007             if (GAT_SUCCESS != retval || 
01008                 (version & ~GATSTRING_MINOR_MASK) > GATSTRING_LASTVERSION)
01009             {
01010               retval = GAT_UNKNOWN_FORMAT;
01011             }
01012             else 
01013             {
01014               /* read the data */
01015               GATType element_type = GATType_NoType;
01016               GATuint32 num_of_elements = 0;
01017               GATuint32 nodesize = 0;
01018               
01019               retval = GATXds_Decode(xds, (GATXdsScope)0, 0, 0, 
01020                 "uint32 uint32 uint32", &element_type, &nodesize, 
01021                 &num_of_elements);
01022               if (GAT_SUCCESS == retval)
01023               {
01024                 /* construct the new object */
01025                 retval = GATList_DeSerialise_Create(context, xds, element_type, 
01026                   nodesize, num_of_elements, &list);
01027               }
01028             }
01029           }
01030         }
01031       }
01032     }
01033     GATXds_Destroy(&xds);
01034 
01035     /* FIXME: GATStatus(retval); */
01036   }
01037   
01038   if (NULL != result)
01039   {
01040     *result = retval;
01041   }
01042   return list;
01043 }
01044 
01045 /** GATList_GetIsDirty
01046  *  
01047  *  The function GATList_GetIsDirty retrieves the status of the dirty flag of 
01048  *  this GATList object.
01049  *
01050  *  @param file The GATList object to inspect for its dirty status.
01051  *  @param isdirty The pointer to a variable, which receives the dirty status.
01052  *
01053  *  @return An error code.
01054  */
01055 GATResult GATList_i_GetIsDirty(GATList_const list, GATBool *isdirty)
01056 {
01057   GATResult retval = GAT_INVALID_HANDLE;
01058   if (NULL != list)
01059   {
01060     if (NULL != isdirty)
01061     {
01062       *isdirty = list->isdirty;
01063       retval = GAT_SUCCESS;
01064     }
01065     else
01066     {
01067       retval = GAT_INVALID_PARAMETER;
01068     }
01069   }
01070   return retval;
01071 }
01072   
01073 /*
01074  *  Special list interface for the datatype 'const char *'
01075  */
01076 GATList_String GATList_String_Create(void)
01077 {
01078   return (GATList_String) GATList_i_Create(GATType_GATString, 
01079     sizeof(GATString));
01080 }
01081 
01082 GATResult 
01083 GATList_String_Equals(GATList_String_const lhs, GATList_String_const rhs,
01084   GATBool *isequal)
01085 {
01086   return GATList_i_Equals((GATList_const) lhs, (GATList_const) rhs, isequal);
01087 }
01088 
01089 GATType GATList_String_GetType(GATList_String_const list)
01090 {
01091   return GATList_i_GetType((GATList_const) list);
01092 }
01093 
01094 GATResult 
01095 GATList_String_Clone(GATList_String_const list, GATList_String *new_list)
01096 {
01097   return GATList_i_Clone((GATList_const) list, (GATList *)new_list);
01098 }
01099 
01100 GATResult 
01101 GATList_String_GetInterface(GATList_String_const list, 
01102   GATInterface iftype, void const **ifp)
01103 {
01104   return GATList_i_GetInterface((GATList_const) list, iftype, ifp);
01105 }
01106 
01107 void GATList_String_Destroy(GATList_String *list)
01108 {
01109   GATList_i_Destroy((GATList *) list);
01110 }
01111 
01112 size_t GATList_String_Size(GATList_String_const list)
01113 {
01114   return GATList_i_Size((GATList_const) list);
01115 }
01116 
01117 GATList_String_Iterator GATList_String_Begin(GATList_String_const list)
01118 {
01119   return (GATList_String_Iterator) GATList_i_Begin((GATList_const)list);
01120 }
01121 
01122 GATList_String_Iterator GATList_String_End(GATList_String_const list)
01123 {
01124   return (GATList_String_Iterator) GATList_i_End((GATList_const) list);
01125 }
01126 
01127 GATList_String_Iterator GATList_String_Next(
01128   GATList_String_Iterator_const iterator)
01129 {
01130   return (GATList_String_Iterator) GATList_i_Next(
01131     (GATListIterator_const) iterator);
01132 }
01133 
01134 GATList_String_Iterator GATList_String_Previous(
01135   GATList_String_Iterator_const iterator)
01136 {
01137   return (GATList_String_Iterator) GATList_i_Previous(
01138     (GATListIterator_const) iterator);
01139 }
01140 
01141 GATList_String_Iterator GATList_String_Insert(
01142   GATList_String list, GATList_String_Iterator iterator, 
01143     char const *data)
01144 {
01145   GATListIterator result = NULL;
01146   GATString item = GATString_Create(data, strlen(data)+1, "ASCII");
01147   
01148   if (NULL != item)
01149   {
01150     result = GATList_i_Insert((GATList)list, (GATListIterator) iterator, 
01151       (void const *) &item);
01152 
01153     GATString_Destroy(&item);   /* was cloned inside */
01154   }
01155   return (GATList_String_Iterator) result;
01156 }
01157 
01158 GATList_String_Iterator GATList_String_Erase(
01159   GATList_String list, GATList_String_Iterator iterator)
01160 {
01161   return (GATList_String_Iterator) GATList_i_Erase((GATList)list,
01162     (GATListIterator) iterator);
01163 }
01164 
01165 char const *
01166 GATList_String_Get(GATList_String_Iterator_const iterator)
01167 {
01168   GATString_const *string = (GATString_const *)GATList_i_Get(
01169     (GATListIterator_const) iterator);
01170   return (NULL != string) ? GATString_GetBuffer(*string) : 0;
01171 }
01172 
01173 GATList_String_Iterator_const GATList_String_Splice(
01174   GATList_String dest, GATList_String_Iterator here, 
01175   GATList_String src, GATList_String_Iterator first,
01176     GATList_String_Iterator last, size_t count)
01177 {
01178   return (GATList_String_Iterator_const) GATList_i_Splice(
01179     (GATList) dest, (GATListIterator) here,
01180     (GATList) src, (GATListIterator) first, 
01181     (GATListIterator) last, count);
01182 }
01183 
01184 /* GATAdvertiseable API */
01185 
01186 /*  Serialise a GATList object */
01187 GATResult GATList_String_Serialise(GATList_String list, GATObject stream, 
01188   GATBool clear_dirty)
01189 {
01190   return GATList_i_Serialise((GATList) list, stream, clear_dirty);
01191 }
01192 
01193 /*  De-serialise a GATList object */
01194 GATList_String GATList_String_DeSerialise(GATContext context, GATObject stream, 
01195   GATResult *result)
01196 {
01197   return (GATList_String) GATList_i_DeSerialise(context, stream, result);
01198 }
01199 
01200 /*  Retrieves the status of the dirty flag of a GATList object.`*/
01201 GATResult 
01202 GATList_String_GetIsDirty(GATList_String_const list, GATBool *isdirty)
01203 {
01204   return GATList_i_GetIsDirty((GATList_const) list, isdirty);
01205 }
01206 
01207 
01208 /* static functions */
01209 
01210 /*
01211  *  Create a new listnode
01212  */
01213 static GATListNode_S *
01214 GATListNode_Create(size_t nodesize)
01215 {
01216   GATListNode_S *newnode = 
01217     (GATListNode_S *)malloc(sizeof(GATListNode_S) + nodesize);
01218   if (NULL != newnode) 
01219   {
01220     /* initialize members */
01221     memset(newnode, 0, sizeof(GATListNode_S));
01222     newnode->magic = MAGIC_GATLISTNODE;
01223     newnode->data = (char *)(newnode+1);
01224   }
01225   return newnode;
01226 }
01227 
01228 /*
01229  *  Helper function, which splices a given sub-list before the given iterator
01230  */
01231 static GATListNode_S *
01232 GATList_Splice(GATList_S *dest, GATListNode_S *iter, GATList_S *src, 
01233   GATListNode_S *first, GATListNode_S *last, size_t count)
01234 {
01235   GATListNode_S *node = NULL;
01236   
01237   if (dest != src)
01238   {
01239     /* not the same list, adjust element counts */
01240     dest->num_of_elements += count;
01241     src->num_of_elements -= count;
01242   }
01243   
01244   first->prev->next = last;
01245   last->prev->next = iter;
01246   iter->prev->next = first;
01247   node = iter->prev;
01248   iter->prev = last->prev;
01249   last->prev = first->prev;
01250   first->prev = node;
01251   
01252   return iter;
01253 }
01254 
01255 /*
01256  *  Helper function, which calculates the distance between two given Iterators
01257  */
01258 static size_t
01259 GATList_Distance(GATListIterator_const first, GATListIterator_const last)
01260 {
01261   size_t count = 0;
01262   while(first != last)
01263   {
01264     first = first->next;
01265     ++count;
01266   }
01267   return count;
01268 }
01269 
01270 /* 
01271  *  Helper function to compare the actual list elements
01272  */
01273 static GATResult
01274 GATList_i_Compare(GATType type, GATuint32 size,
01275   GATListIterator_const lhs_first, GATListIterator_const lhs_last,
01276   GATListIterator_const rhs_first, GATBool *isequal)
01277 {
01278   GATResult result = GAT_SUCCESS;
01279   int break_while = 0;
01280   
01281   assert(NULL != isequal);
01282   while (lhs_first != lhs_last && !break_while)
01283   {
01284     void *lhs_data = GATList_i_Get(lhs_first);
01285     void *rhs_data = GATList_i_Get(rhs_first);
01286     
01287     if (NULL != lhs_data && NULL != rhs_data)
01288     {
01289       switch(type)
01290       {
01291         case GATType_GATint16:
01292           *isequal = (*(GATint16 *)lhs_data == *(GATint16 *)rhs_data) ?
01293             GATTrue : GATFalse;
01294           break;
01295           
01296         case GATType_GATint32:
01297           *isequal = (*(GATint32 *)lhs_data == *(GATint32 *)rhs_data) ?
01298             GATTrue : GATFalse;
01299           break;
01300           
01301         case GATType_GATfloat32:
01302           *isequal = (*(float *)lhs_data == *(float *)rhs_data) ?
01303             GATTrue : GATFalse;
01304           break;
01305           
01306         case GATType_GATdouble64:
01307           *isequal = (*(double *)lhs_data == *(double *)rhs_data) ?
01308             GATTrue : GATFalse;
01309           break;
01310           
01311         default:
01312           if (GATType_GATObject & type)
01313           {
01314             /* we have to compare two GATObject's */
01315             result = GATObject_Equals(*(GATObject *) lhs_data, 
01316               *(GATObject *) rhs_data, isequal);
01317             if (GAT_SUCCESS != result)
01318             {
01319               break_while = 1;
01320             }
01321           }
01322           else if (GATType_PlainOldData == type)
01323           {
01324             result = (0 == memcmp(lhs_data, rhs_data, size)) ? 
01325               GATTrue : GATFalse;
01326           }
01327           else
01328           {
01329             result = GAT_FAIL;
01330             break_while = 1;        
01331           }
01332           break;
01333       }
01334     }
01335     else
01336     {
01337       /*
01338        *  This should not happen, because memory allocation errors should have 
01339        *  been detected earlier.
01340        */
01341       assert(NULL != lhs_data && NULL != rhs_data);
01342       result = GAT_FAIL;
01343     }
01344     
01345     if (GATTrue != *isequal)
01346     {
01347       result = GAT_SUCCESS;
01348       break;  /* break on the first different element or on error */
01349     }
01350         
01351     /* advance to next list elements */
01352     lhs_first = GATList_i_Next(lhs_first);
01353     rhs_first = GATList_i_Next(rhs_first);
01354   }
01355   return result;
01356 }
01357 
01358 /* Serialize the items stored in the given list */
01359 static GATResult 
01360 GATList_i_SerialiseItems(GATList_const list, GATXds xds,
01361   GATXdsScope flag, void **buffer, size_t *buffer_size, GATBool clear_dirty)
01362 {
01363   GATResult retval = GAT_SUCCESS;
01364   GATListIterator it = GATList_i_Begin(list);
01365   GATListIterator end = GATList_i_End(list);
01366   GATMemoryStream memory_stream = NULL;
01367   GATObject memory_stream_obj = NULL;
01368   
01369   if (GATType_GATObject & list->element_type)
01370   {
01371     memory_stream = GATMemoryStream_Create(0, 0, GATFalse);
01372     if (NULL == memory_stream)
01373     {
01374       retval = GAT_MEMORYFAILURE;
01375     }
01376     else
01377     {
01378       memory_stream_obj = GATMemoryStream_ToGATObject(memory_stream);
01379     }
01380   }
01381   
01382   if (GAT_SUCCESS == retval)
01383   {
01384     for (/**/; it != end; it = GATList_i_Next(it))
01385     {
01386       if (NULL == GATList_i_Get(it))
01387       {
01388         retval = GAT_FAIL;    /* completely unexpected */
01389         break;
01390       }
01391       
01392       switch(list->element_type)
01393       {
01394         case GATType_GATint32:
01395           retval = GATXds_Encode(xds, (GATXdsScope)0, 0, 0, "int32", 
01396             *(GATint32 *)GATList_i_Get(it));
01397           break;
01398           
01399         case GATType_GATint16:
01400           retval = GATXds_Encode(xds, (GATXdsScope)0, 0, 0, "int32", 
01401             (GATint32)*(GATint16 *)GATList_i_Get(it));
01402           break;
01403           
01404         case GATType_GATfloat32:
01405           retval = GATXds_Encode(xds, (GATXdsScope)0, 0, 0, "double", 
01406             *(float *)GATList_i_Get(it));
01407           break;
01408 
01409         case GATType_GATdouble64:
01410           retval = GATXds_Encode(xds, (GATXdsScope)0, 0, 0, "double", 
01411             *(double *)GATList_i_Get(it));
01412           break;
01413 
01414         default:
01415           if (list->element_type & GATType_GATObject)
01416           {
01417             retval = GATSerialisable_Serialise(*(GATObject *)GATList_i_Get(it), 
01418               memory_stream_obj, clear_dirty);
01419           }
01420           else
01421           {
01422             retval = GAT_NOTIMPL;
01423           }
01424       }
01425       
01426       if (GAT_SUCCESS != retval)
01427       {
01428         break;
01429       }
01430     }
01431     
01432     if (GATType_GATObject & list->element_type)
01433     { 
01434       if (GAT_SUCCESS == retval)
01435       {
01436         *buffer = GATMemoryStream_GetBuffer(memory_stream, (GATuint32 *) buffer_size, 
01437           GATTrue);
01438         retval = (NULL != *buffer) ? GAT_SUCCESS : GAT_MEMORYFAILURE; 
01439       }
01440       GATMemoryStream_Destroy(&memory_stream);
01441     }
01442     else if (GAT_SUCCESS == retval)
01443     {
01444       retval = GATXds_GetBuffer(xds, flag, buffer, buffer_size);
01445     }
01446   }
01447   return retval;
01448 }
01449 
01450 /** GATList_DeSerialise_Create
01451  *
01452  *  The function GATList_DeSerialise_Create creates a new GATList object and 
01453  *  fills it from the given stream.
01454  *
01455  *  @param context The GAT context to be used for object construction.
01456  *  @param xds The XDS engine to use for decoding.
01457  *  @param element_type This is the type of the items contained in the new 
01458  *        list.
01459  *  @param nodesize This is the size of one item as it is stored in the list.
01460  *  @param num_of_elements The number of elements to read from the stream.
01461  *  @param new_object The pointer to the variable, which should receive the 
01462  *        newly constructed GATList object.
01463  *
01464  *  @return An error code.
01465  */
01466 static GATResult
01467 GATList_DeSerialise_Create(GATContext context, GATXds xds, GATType element_type, 
01468   GATuint32 nodesize, GATuint32 num_of_elements, GATList *new_object)
01469 {
01470   GATResult retval = GAT_MEMORYFAILURE;
01471   GATList new_list = (GATList) malloc(sizeof(struct GATList_S));
01472 
01473   if(NULL != new_list)
01474   {
01475     GATListNode_S *newnode = NULL;
01476     
01477     GATMemoryStream memory_stream = NULL;
01478     GATObject memory_stream_obj = NULL;
01479 
01480     /* initialise the main list members */    
01481     memset(new_list, 0, sizeof(struct GATList_S));
01482     new_list->magic = MAGIC_GATLIST;
01483     new_list->GATObject__vtable = &GATList__vtable;
01484     new_list->GATSerialisable__vtable = &GATList_ISerialisable__vtable;
01485     new_list->element_type = element_type;
01486     new_list->nodesize = nodesize;
01487 
01488     /* if we have to read GATObject's, then initialise a memory stream */
01489     if (GATType_GATObject & element_type)
01490     {
01491       void *buffer = NULL;
01492       size_t used_buffer = 0;
01493       size_t buffer_size = GATXds_GetBufferCapacity(xds);
01494       
01495       retval = GATXds_GetBuffer(xds, GATXdsScope_Gift, &buffer, &used_buffer);
01496       if (GAT_SUCCESS == retval)
01497       {
01498         memory_stream = GATMemoryStream_Create(buffer, buffer_size, GATTrue);
01499         if (NULL == memory_stream)
01500         {
01501           retval = GAT_MEMORYFAILURE;
01502         }
01503         else
01504         {
01505           memory_stream_obj = GATMemoryStream_ToGATObject(memory_stream);
01506           retval = GAT_SUCCESS;
01507         }
01508       }
01509       
01510       if (GAT_SUCCESS == retval)
01511       {
01512         /* reposition the memory stream to start with the actual object data */
01513         retval = GATMemoryStream_Seek(memory_stream, GATOrigin_Set, 
01514           used_buffer, 0);
01515       }
01516     }
01517     else
01518     {
01519       retval = GAT_SUCCESS;
01520     }
01521 
01522     if (GAT_SUCCESS == retval)
01523     {
01524       /* allocate the end of list node */    
01525       newnode = GATListNode_Create(0);  
01526       if (NULL == newnode) 
01527       {
01528         retval = GAT_MEMORYFAILURE;
01529       }
01530       else 
01531       {
01532         /* link in the end of list node */
01533         newnode->next = newnode->prev = newnode;
01534         new_list->begin = newnode;
01535         
01536         /* de-serialise all the items in this list */
01537         retval = GATList_DeSerialise_Items(context, new_list, xds, 
01538           memory_stream_obj, element_type, num_of_elements);
01539       }
01540 
01541       if (GATType_GATObject & element_type)
01542       {
01543         GATMemoryStream_Destroy(&memory_stream);
01544       }
01545     }
01546   }
01547 
01548   if (GAT_SUCCESS == retval)
01549   {
01550     if (NULL != new_object)
01551     {
01552       *new_object = new_list;
01553     }
01554     else
01555     {
01556       GATList_i_Destroy(&new_list);
01557       retval = GAT_INVALID_PARAMETER;
01558     }
01559   }
01560   else
01561   {
01562     GATList_i_Destroy(&new_list);
01563   }
01564   return retval;
01565 }
01566 
01567 static GATResult
01568 GATList_DeSerialise_Items(GATContext context, GATList new_list, GATXds xds, 
01569   GATObject stream, GATType element_type, GATuint32 num_of_elements)
01570 {
01571   GATuint32 i = 0;
01572   GATResult retval = GAT_SUCCESS;   /* zero elements is ok */
01573   
01574   for (/**/; i < num_of_elements; ++i)
01575   {
01576     switch(element_type)
01577     {
01578       case GATType_GATint32:
01579         {
01580           GATint32 data = 0;
01581           retval = GATXds_Decode(xds, (GATXdsScope)0, 0, 0, "int32", &data);
01582           if (GAT_SUCCESS == retval)
01583           {
01584             retval = (NULL != GATList_i_Insert(new_list, GATList_i_End(new_list), 
01585               &data)) ? GAT_SUCCESS : GAT_MEMORYFAILURE;
01586           }
01587         }
01588         break;
01589         
01590       case GATType_GATint16:
01591         {
01592           GATint32 data = 0;
01593           retval = GATXds_Decode(xds, (GATXdsScope)0, 0, 0, "int32", &data);
01594           if (GAT_SUCCESS == retval)
01595           {
01596             GATint16 real_data = (GATint16) data;
01597             retval = (NULL != GATList_i_Insert(new_list, GATList_i_End(new_list), 
01598               &real_data)) ? GAT_SUCCESS : GAT_MEMORYFAILURE;
01599           }
01600         }
01601         break;
01602         
01603       case GATType_GATfloat32:
01604         {
01605           double data = 0;
01606           retval = GATXds_Decode(xds, (GATXdsScope)0, 0, 0, "double", &data);
01607           if (GAT_SUCCESS == retval)
01608           {
01609             float real_data = (float) data;
01610             retval = (NULL != GATList_i_Insert(new_list, GATList_i_End(new_list), 
01611               &real_data)) ? GAT_SUCCESS : GAT_MEMORYFAILURE;
01612           }
01613         }
01614         break;
01615 
01616       case GATType_GATdouble64:
01617         {
01618           double data = 0;
01619           retval = GATXds_Decode(xds, (GATXdsScope)0, 0, 0, "double", &data);
01620           if (GAT_SUCCESS == retval)
01621           {
01622             retval = (NULL != GATList_i_Insert(new_list, GATList_i_End(new_list), 
01623               &data)) ? GAT_SUCCESS : GAT_MEMORYFAILURE;
01624           }
01625         }
01626         break;
01627 
01628       default:
01629         if (element_type & GATType_GATObject)
01630         {
01631           GATObject obj = GATSerialisable_DeSerialise(context, stream, &retval);
01632           if (NULL != obj)
01633           {
01634             retval = (NULL != GATList_i_Insert(new_list, GATList_i_End(new_list),
01635               &obj)) ? GAT_SUCCESS : GAT_MEMORYFAILURE;
01636             GATObject_Destroy(&obj);
01637           }
01638         }
01639         else
01640         {
01641           retval = GAT_NOTIMPL;
01642         }
01643     }
01644     
01645     if (GAT_SUCCESS != retval)
01646     {
01647       break;
01648     }
01649   }
01650   return retval;
01651 }