struct_manager.h

00001 /* File:      struct_manager.h
00002 ** Author(s): Ernie Johnson
00003 ** Contact:   xsb-contact@cs.sunysb.edu
00004 ** 
00005 ** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1998
00006 ** 
00007 ** XSB is free software; you can redistribute it and/or modify it under the
00008 ** terms of the GNU Library General Public License as published by the Free
00009 ** Software Foundation; either version 2 of the License, or (at your option)
00010 ** any later version.
00011 ** 
00012 ** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
00013 ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014 ** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
00015 ** more details.
00016 ** 
00017 ** You should have received a copy of the GNU Library General Public License
00018 ** along with XSB; if not, write to the Free Software Foundation,
00019 ** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 **
00021 ** $Id: struct_manager.h,v 1.11 2006/02/06 20:20:04 tswift Exp $
00022 ** 
00023 */
00024 
00025 
00026 #ifndef STRUCTURE_MANAGER
00027 
00028 #define STRUCTURE_MANAGER
00029 
00030 
00031 /*===========================================================================*/
00032 
00033 /*
00034  *           Generic Block-Oriented Data Structure Management
00035  *           ================================================
00036  *
00037  * The following structure and macros provide a uniform method for
00038  * managing pools of data structures allocated from the system by block
00039  * (rather than individually).  By following a few guidelines, the
00040  * implementation of any such structure with this desired allocation
00041  * property is simplified.
00042  *
00043  * Interface:
00044  * ---------
00045  * - SM_InitDecl(StructType,StructsPerBlock,StructNameString)
00046  * - SM_AllocateStruct(SM,pNewStruct)
00047  * - SM_DeallocateStruct(SM,pStruct)
00048  * - SM_DeallocateStructList(SM,pHead,pTail)
00049  * - SM_CurrentCapacity(SM,NumBlocks,NumStructs)
00050  * - SM_CountFreeStructs(SM,NumFree)
00051  * - SM_RawUsage(SM,TotalBlockUsageInBytes)
00052  * - SM_ReleaseResources(SM)
00053  *
00054  * MT Interface also includes: 
00055  * SM_InitDeclDyna(StructType,StructsPerBlock,StructNameString)
00056  * as well as shared variants of the above routines.
00057  * ---------
00058  *
00059  * Management Organization:
00060  * -----------------------
00061  * Blocks of structures (records) are allocated from the system, one at a
00062  * time, and maintained on a linked list.  The head of this list is the
00063  * most recently allocated block and the one from which individual records
00064  * are parceled out.  Deallocated records -- ones which were
00065  * previously-allocated but then returned to the Manager -- are maintained
00066  * in a list for reallocation.  Priority is given to these previously-used
00067  * structures during the allocation process.  The first word of a block,
00068  * as well as that in a deallocated record, is used as a link for chaining
00069  * these objects in their respective lists.  This has implications both
00070  * for the layout of a block and managed records.  Ramafications for the
00071  * latter extend only to how one wishes to return records to the Manager
00072  * for reallocation: one-at-a-time or list-at-a-time (see below).  The
00073  * allocation of a block occurs on a needs basis.  Its overall size is
00074  * determined by the number and size of the records it is to hold.  For
00075  * convenience, a field for chaining allocated structures is also
00076  * provided.  Note, however, that the responsibility of maintaining this
00077  * list rests solely with the user (read client).  Four additional macros
00078  * are provided for aiding in its maintenance, but it is up to the user to
00079  * apply them, and in a reasonable way.  Not all records will require this
00080  * feature, and so this field and these macros can be safely ignored.
00081  *
00082  * Use:
00083  * ---
00084  * 
00085  * To use, observe the following guidelines:
00086  *
00087  * 1) For single-threaded engine, or if a SM is to be shared among
00088  *    threads, Declare a Structure_Manager variable for your data structure AND
00089  *    initialize it statically using the macro SM_InitDecl().  Provide
00090  *    the macro with the type of your record, the number you wish it to
00091  *    allocate at once, and a string which contains the name of the
00092  *    structure.  For example:
00093  *
00094  *         Structure_Manager mySM = SM_InitDecl(int,5,"C integer");
00095  *
00096  * 1a) Alternatively, for a thread-private SM, mem_alloc() memory and
00097  * initialize the SM dynamically using SM_InitDeclDyna() with the same
00098  * argument types as SM_InitDecl().
00099  *
00100  * 2) To obtain a new structure from your Manager, make a call to
00101  *    SM_AllocateStruct() for single-threaded, or thread-private
00102  *    SMs: 
00103  *
00104  *         SM_AllocateStruct(mySM,pNewStruct)
00105  *
00106  *    Similarly, for thread-shared SMs use the thread-safe
00107  *
00108  *         SM_AllocateSharedStruct(mySM,pNewStruct)
00109  *
00110  *    Here, and with the rest of the API, use of thread-private
00111  *    routines do not add mutexes to those used by the underlying
00112  *    operating system for mememory management, while thread-shared
00113  *    routines do add such a layer.
00114  *
00115  *    If chaining of allocated structures is desired, then one can use
00116  *    macros SM_AddToAllocList_SL/DL to add the returned record to the
00117  *    head of this list.  One must define field-access macro(s) to the
00118  *    link field(s) of this record type for use by these list-creating
00119  *    macros.
00120  *
00121  * 3) If mass deallocation of a list of records is desired, then make
00122  *    the first field in your record the link field for supporting the
00123  *    list.  You may then use macro SM_DeallocateStructList() (or
00124  *    SM_DeallocateSharedStructList() )
00125  *
00126  *         SM_DeallocateStructList(mySM,pListHead,pListTail)
00127  *
00128  *    Otherwise, you'll have to deallocate them one at a time using
00129  *    SM_DeallocateStruct() (SM_DeallocateSharedStruct().  If these
00130  *    structs are maintained on the 
00131  *    allocation chain of the Structure Manager, then they should be
00132  *    removed BEFORE the deallocation.  One may find the macros
00133  *    SM_RemoveFromAllocList_SL/DL helpful for this.
00134  *    Note that these deallocation routines do NOT free the
00135  *    underlying memory, but just return the structures to the free
00136  *    list of the structure mamanger.
00137  *
00138  * 4) Get info about the state of the Manager using routines
00139  *    SM_CurrentCapacity(), SM_CountFreeStructs(), and SM_RawUsage().
00140  * (No MT analogues yet)
00141  *
00142  * 5) Releasing the resources of the Structure Manager returns the blocks
00143  *    to the system and resets some of its fields.
00144  *
00145  * 6) With possibly the exception of the allocated-record-chain field,
00146  *    avoid direct manipulatiion of the Structure Manager!  Use the
00147  *    provided interface routines.
00148  */
00149 
00150 #define PRIVATE_SM 1
00151 #define SHARED_SM 0
00152 
00153 /* Only accounting for shared/private tables for variant tabling --
00154    smTableXXX denotes shared.  All subsumptive tables must be private
00155    in this version, and check should be made by loader.*/
00156 
00157 #ifdef MULTI_THREAD
00158 #define SET_TRIE_ALLOCATION_TYPE_TIP(pTIF)      \
00159   if (isPrivateTIF(pTIF)) {                     \
00160     smBTN = private_smTableBTN;                 \
00161     smBTHT = private_smTableBTHT;                       \
00162     threads_current_sm = PRIVATE_SM;            \
00163   } else {                                      \
00164     smBTN = &smTableBTN;                        \
00165     smBTHT = &smTableBTHT;                      \
00166     threads_current_sm = SHARED_SM;             \
00167   }
00168 
00169 #define SET_TRIE_ALLOCATION_TYPE_PSC(pPSC)      \
00170   if (get_shared(pPSC)) {                       \
00171     smBTN = &smTableBTN;                        \
00172     smBTHT = &smTableBTHT;                      \
00173     threads_current_sm = SHARED_SM;             \
00174   } else {                                      \
00175     smBTN = private_smTableBTN;                 \
00176     smBTHT = private_smTableBTHT;                       \
00177     threads_current_sm = PRIVATE_SM;            \
00178   }
00179 
00180 #define SET_TRIE_ALLOCATION_TYPE_SF(pSF) \
00181   if (!(pSF->sf_type & SHARED_PRIVATE_MASK)) {  \
00182     smBTN = private_smTableBTN;                 \
00183     smBTHT = private_smTableBTHT;               \
00184     threads_current_sm = PRIVATE_SM;            \
00185   } else {                                      \
00186       smBTN = &smTableBTN;                      \
00187       smBTHT = &smTableBTHT;                    \
00188       threads_current_sm = SHARED_SM;           \
00189     }
00190 #else
00191 #define SET_TRIE_ALLOCATION_TYPE_TIP(pTIF) 
00192 #define SET_TRIE_ALLOCATION_TYPE_SF(pSF) 
00193 #define SET_TRIE_ALLOCATION_TYPE_PSC(pPSC)      
00194 #endif
00195 
00196 typedef struct Structure_Manager {
00197   struct {                 /* Current block descriptor: */
00198     void *pBlock;          /* - current block; head of block chain */
00199     void *pNextStruct;     /* - next available struct in current block */
00200     void *pLastStruct;     /* - last struct in current block */
00201   } cur_block;
00202   struct {                 /* Structure characteristics: */
00203     size_t size;           /* - size of the structure in bytes */
00204     counter num;           /* - number of records per block */
00205     char *name;            /* - short description of the struct type */
00206   } struct_desc;
00207   struct {                 /* Lists of structures: */
00208     void *alloc;           /* - convenience hook, not directly maintained */
00209     void *dealloc;         /* - deallocated structs, poised for reuse */
00210   } struct_lists;
00211 } Structure_Manager;
00212 typedef struct Structure_Manager *SMptr;
00213 
00214 
00215 /* Macro Short-Hands  (mainly for "internal" use)
00216    ----------------- */
00217 #define SM_CurBlock(SM)         ((SM).cur_block.pBlock)
00218 #define SM_NextStruct(SM)       ((SM).cur_block.pNextStruct)
00219 #define SM_LastStruct(SM)       ((SM).cur_block.pLastStruct)
00220 #define SM_StructSize(SM)       ((SM).struct_desc.size)
00221 #define SM_StructsPerBlock(SM)  ((SM).struct_desc.num)
00222 #define SM_StructName(SM)       ((SM).struct_desc.name)
00223 #define SM_AllocList(SM)        ((SM).struct_lists.alloc)
00224 #define SM_FreeList(SM)         ((SM).struct_lists.dealloc)
00225 
00226 #define SM_NewBlockSize(SM)     /* in bytes */                  \
00227    ( sizeof(void *) + SM_StructSize(SM) * SM_StructsPerBlock(SM) )
00228 
00229 #define SM_CurBlockIsDepleted(SM)        \
00230    ( IsNULL(SM_CurBlock(SM)) || (SM_NextStruct(SM) > SM_LastStruct(SM)) )
00231 
00232 #define SM_NumStructsLeftInBlock(SM)                                     \
00233    ( ! SM_CurBlockIsDepleted(SM)                                         \
00234      ? ( ((char *)SM_LastStruct(SM) - (char *)SM_NextStruct(SM))         \
00235          / SM_StructSize(SM) + 1 )                                       \
00236      : 0 )
00237 
00238 
00239 #define SM_AllocateFree(SM,pNewStruct)                          \
00240    pNewStruct = SM_FreeList(SM);                                \
00241    SM_FreeList(SM) = SMFL_NextFreeStruct(SM_FreeList(SM))
00242 
00243 #define SM_AllocateFromBlock(SM,pNewStruct)                     \
00244    pNewStruct = SM_NextStruct(SM);                              \
00245    SM_NextStruct(SM) = SMBlk_NextStruct(SM_NextStruct(SM),SM_StructSize(SM))
00246 
00247 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00248 
00249 extern void smPrint(Structure_Manager, char *);
00250 extern void smAllocateBlock(Structure_Manager *);
00251 extern void smFreeBlocks(Structure_Manager *);
00252 extern xsbBool smIsValidStructRef(Structure_Manager, void *);
00253 extern xsbBool smIsAllocatedStruct(Structure_Manager, void *);
00254 extern xsbBool smIsAllocatedStructRef(Structure_Manager, void *);
00255 
00256 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00257 
00258 /* Manipulating the Free List
00259    -------------------------- */
00260 #define SMFL_NextFreeStruct(pFreeStruct)        ( *(void **)(pFreeStruct) )
00261 
00262 
00263 /* Manipulating Allocation Block
00264    ----------------------------- */
00265 #define SMBlk_NextBlock(pBlock)         ( *(void **)(pBlock) )
00266 
00267 #define SMBlk_FirstStruct(pBlock)       ( (char *)pBlock + sizeof(void *) )
00268 
00269 #define SMBlk_LastStruct(pBlock,StructSize,StructsPerBlock)     \
00270    ( SMBlk_FirstStruct(pBlock) + StructSize * (StructsPerBlock - 1) )
00271 
00272 #define SMBlk_NextStruct(pStruct,StructSize)   ( (char *)pStruct + StructSize )
00273 
00274 /*-------------------------------------------------------------------------*/
00275 
00276 /* Primary Interface Routines
00277    ========================== */
00278 
00279 /*
00280  *  For initialization at declaration time.
00281  */
00282 #define SM_InitDecl(StructType,StructsPerBlock,NameString) {    \
00283    {NULL, NULL, NULL},                                          \
00284    {sizeof(StructType), StructsPerBlock, NameString},           \
00285    {NULL, NULL}                                                 \
00286  }
00287 
00288 #define SM_InitDeclDyna(StructPtr,StructType,StructsPerBlock,NameString)  \
00289   (StructPtr->cur_block).pBlock = NULL;                                 \
00290   (StructPtr->cur_block).pNextStruct = NULL;                            \
00291   (StructPtr->cur_block).pLastStruct = NULL;                            \
00292   (StructPtr->struct_desc).size = sizeof(StructType);                   \
00293   (StructPtr->struct_desc).num = StructsPerBlock;                       \
00294   (StructPtr->struct_desc).name = NameString;                           \
00295   (StructPtr->struct_lists).alloc = NULL;                               \
00296   (StructPtr->struct_lists).dealloc = NULL;                             
00297   
00298 /*  strcpy(&((StructPtr->struct_desc).name),NameString);                \*/
00299 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00300 
00301 /*
00302  *  Allocate a structure from the Structure Manager.
00303  */
00304 
00305 #define SM_AllocateSharedStruct(SM,pStruct) {           \
00306   SYS_MUTEX_LOCK( MUTEX_SM );                           \
00307   if ( IsNonNULL(SM_FreeList(SM)) ) {                   \
00308     SM_AllocateFree(SM,pStruct);                        \
00309   }                                                     \
00310   else {                                                \
00311     if ( SM_CurBlockIsDepleted(SM) ) {                  \
00312       smAllocateBlock(&SM);                             \
00313     }                                                   \
00314     SM_AllocateFromBlock(SM,pStruct);                   \
00315   }                                                     \
00316   SYS_MUTEX_UNLOCK( MUTEX_SM );                         \
00317  }
00318 
00319 #define SM_AllocateStruct(SM,pStruct) {         \
00320                                                 \
00321    if ( IsNonNULL(SM_FreeList(SM)) ) {          \
00322      SM_AllocateFree(SM,pStruct);               \
00323    }                                            \
00324    else {                                       \
00325      if ( SM_CurBlockIsDepleted(SM) )           \
00326        smAllocateBlock(&SM);                    \
00327      SM_AllocateFromBlock(SM,pStruct);          \
00328    }                                            \
00329  }
00330 
00331 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00332 
00333 /*
00334  *  To deallocate a chain of structures -- of the same type -- at once,
00335  *  they must ALREADY be linked using the first word in the structure,
00336  *  since this conforms with the manner in which records on the free
00337  *  chain are maintained.  Head and Tail are relative to the ordering
00338  *  imposed by this first-word linkage.  Otherwise, each structure in
00339  *  the chain must be deallocated individually.
00340  *  Set the second word to -1 to indicate that the block is free.
00341  */
00342 
00343 #ifdef MULTI_THREAD
00344 #define SM_DeallocateSharedStructList(SM,pHead,pTail) { \
00345    void *pStruct = pHead;                               \
00346    while (pStruct != pTail) {                           \
00347      *(((int *)pStruct)+1) = FREE_TRIE_NODE_MARK;       \
00348      pStruct = *(void **)pStruct;                       \
00349    }                                                    \
00350    *(((int *)pStruct)+1) = FREE_TRIE_NODE_MARK;         \
00351    SYS_MUTEX_LOCK( MUTEX_SM );                          \
00352    SMFL_NextFreeStruct(pTail) = SM_FreeList(SM);        \
00353    SM_FreeList(SM) = pHead;                             \
00354    SYS_MUTEX_UNLOCK( MUTEX_SM );                        \
00355  }
00356 #else
00357 #define SM_DeallocateSharedStructList(SM,pHead,pTail)  \
00358   SM_DeallocateStructList(SM,pHead,pTail)  
00359 #endif
00360 
00361 #define SM_DeallocateStructList(SM,pHead,pTail) {       \
00362    void *pStruct = pHead;                               \
00363    while (pStruct != pTail) {                           \
00364      *(((int *)pStruct)+1) = FREE_TRIE_NODE_MARK;       \
00365      pStruct = *(void **)pStruct;                       \
00366    }                                                    \
00367    *(((int *)pStruct)+1) = FREE_TRIE_NODE_MARK;         \
00368    SMFL_NextFreeStruct(pTail) = SM_FreeList(SM);        \
00369    SM_FreeList(SM) = pHead;                             \
00370  }
00371 
00372 #define SM_DeallocateSharedStruct(SM,pStruct)           \
00373    SM_DeallocateSharedStructList(SM,pStruct,pStruct)
00374 
00375 #define SM_DeallocateStruct(SM,pStruct)         \
00376    SM_DeallocateStructList(SM,pStruct,pStruct)
00377 
00378 #ifdef MULTI_THREAD
00379 #define SM_DeallocatePossSharedStruct(SM,pStruct)               \
00380   if (threads_current_sm == PRIVATE_SM) {                       \
00381     SM_DeallocateStruct(SM,pStruct);                            \
00382   } else {                                                      \
00383   SM_DeallocateSharedStruct(SM,pStruct);        \
00384   }
00385 #else
00386 #define SM_DeallocatePossSharedStruct(SM,pStruct)               \
00387   SM_DeallocateStruct(SM,pStruct)
00388 #endif
00389 
00390 
00391 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00392 
00393 /*
00394  *  Query the manager for the number of allocated blocks and the total
00395  *  number of records they hold.
00396  */
00397 #define SM_CurrentCapacity(SM,NumBlocks,NumStructs) {   \
00398                                                         \
00399    void *pBlock;                                        \
00400                                                         \
00401    NumBlocks = 0;                                       \
00402    for ( pBlock = SM_CurBlock(SM);  IsNonNULL(pBlock);  \
00403          pBlock = SMBlk_NextBlock(pBlock) )             \
00404      NumBlocks++;                                       \
00405    NumStructs = NumBlocks * SM_StructsPerBlock(SM);     \
00406  }
00407 
00408 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00409 
00410 /*
00411  *  Query the manager for the number of unallocated records it
00412  *  currently has.
00413  */
00414 #define SM_CountFreeStructs(SM,NumFreeStructs) {                \
00415                                                                 \
00416    void *pStruct;                                               \
00417                                                                 \
00418    if ( IsNonNULL(SM_CurBlock(SM)) ) {                          \
00419      NumFreeStructs = SM_NumStructsLeftInBlock(SM);             \
00420      for ( pStruct = SM_FreeList(SM);  IsNonNULL(pStruct);      \
00421            pStruct = SMFL_NextFreeStruct(pStruct) )             \
00422        NumFreeStructs++;                                        \
00423    }                                                            \
00424    else                                                         \
00425      NumFreeStructs = 0;                                        \
00426  }
00427 
00428 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00429 
00430 /*
00431  *  Query the manager for the total number of bytes it obtained from
00432  *  the system.
00433  */
00434 #define SM_RawUsage(SM,UsageInBytes) {                  \
00435                                                         \
00436    void *pBlock;                                        \
00437                                                         \
00438    UsageInBytes = 0;                                    \
00439    for ( pBlock = SM_CurBlock(SM);  IsNonNULL(pBlock);  \
00440          pBlock = SMBlk_NextBlock(pBlock) )             \
00441      UsageInBytes = UsageInBytes + SM_NewBlockSize(SM); \
00442  }
00443 
00444 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00445 
00446 /*
00447  *  Return all memory blocks to the system.  Need to use on private
00448  *  SMs or within the scope of a mutex.
00449  */
00450 #define SM_ReleaseResources(SM)         smFreeBlocks(&SM)
00451 
00452 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00453 
00454 /*
00455  *  Place a newly allocated record on the "in use" list, maintained as
00456  *  either a singly- or doubly-linked (SL/DL) list.  These need to be
00457  *  called either on private SMs or to be mutexed.
00458  */
00459 
00460 #define SM_AddToAllocList_SL(SM,pRecord,LinkFieldMacro) {       \
00461    LinkFieldMacro(pRecord) = SM_AllocList(SM);                  \
00462    SM_AllocList(SM) = pRecord;                                  \
00463  }
00464 
00465 #define SM_AddToAllocList_DL(SM,pRecord,PrevFieldMacro,NextFieldMacro) { \
00466    PrevFieldMacro(pRecord) = NULL;                                       \
00467    NextFieldMacro(pRecord) = SM_AllocList(SM);                           \
00468    SM_AllocList(SM) = pRecord;                                           \
00469    if ( IsNonNULL(NextFieldMacro(pRecord)) )                             \
00470      PrevFieldMacro(NextFieldMacro(pRecord)) = pRecord;                  \
00471  }
00472 
00473 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
00474 
00475 /*
00476  *  Prepare a record for deallocation by removing it from the "in use"
00477  *  list.  Currently must be called from a private table or within
00478  *  the scope of a mutex.
00479  */
00480 
00481 #define SM_RemoveFromAllocList_SL(SM,pRecord,LinkFieldMacro,RecordType) { \
00482                                                                           \
00483    RecordType pCur, pPrev;                                                \
00484                                                                           \
00485    for ( pPrev = NULL, pCur = SM_AllocList(SM);                           \
00486          IsNonNULL(pCur);                                                 \
00487          pPrev = pCur, pCur = LinkFieldMacro(pCur) )                      \
00488      if ( pCur == pRecord )                                               \
00489        break;                                                             \
00490    if ( IsNonNULL(pCur) ) {                                               \
00491      if ( IsNonNULL(pPrev) )                                              \
00492        LinkFieldMacro(pPrev) = LinkFieldMacro(pCur);                      \
00493      else                                                                 \
00494        SM_AllocList(SM) = LinkFieldMacro(pCur);                           \
00495      LinkFieldMacro(pCur) = NULL;                                         \
00496    }                                                                      \
00497    else                                                                   \
00498      xsb_warn("Record not present in given Structure Manager: %s",        \
00499               SM_StructName(SM));                                         \
00500  }
00501 
00502 #define SM_RemoveFromAllocList_DL(SM,pRecord,PrevFieldMacro,NextFieldMacro) { \
00503    if ( IsNonNULL(PrevFieldMacro(pRecord)) )                                  \
00504      NextFieldMacro(PrevFieldMacro(pRecord)) = NextFieldMacro(pRecord);       \
00505    else {                                                                     \
00506      if ( SM_AllocList(SM) == pRecord )                                       \
00507        SM_AllocList(SM) = NextFieldMacro(pRecord);                            \
00508      else {                                                             \
00509        xsb_abort("Record not present in given Structure Manager: %s",         \
00510                  SM_StructName(SM));                                          \
00511      }                                                                  \
00512    }                                                                          \
00513    if ( IsNonNULL(NextFieldMacro(pRecord)) )                                  \
00514      PrevFieldMacro(NextFieldMacro(pRecord)) = PrevFieldMacro(pRecord);       \
00515    NextFieldMacro(pRecord) = PrevFieldMacro(pRecord) = NULL;                  \
00516  }
00517 
00518 /*===========================================================================*/
00519 
00520 #endif

Generated on Wed Jul 26 13:30:42 2006 for XSB by  doxygen 1.4.5