/*----------------------------------------------------------------------------
** Name: memmanag.cpp
**
** Title: Memory Manager
**
** Purpose:
**  Create and manage the symbol table memory.  Included:
**      creating table
**      adding elements to table
**      growing table
**      closing table
**
** Status: PRELIMINARY | CODED | TESTED
**
** $Log:   S:/tbird/arcppc/symbol/memmanag.cpv  $
** 
**    Rev 1.2   12 Mar 1997 14:47:44   hera
** No change.
** 
**    Rev 1.1   03 Mar 1997 15:48:06   hera
** 
**    Rev 1.0   07 Sep 1995 11:16:40   gene
** Initial revision.
** 
**    Rev 1.5   25 Feb 1994 12:49:56   nghia
** Fixed PV 2.1 BUG: GlobalReAlloc() causes pointers to be invalid.
** - Removed GlobalUnlock() call before calling GlobalReAlloc() to reduce the
** chance that a new handle will be allocated.  However, this will not prevent
** Windows from allocate new memory, if the re-allocation is crossed the 64K
** boundary.
** 
**    Rev 1.4   10 Jul 1992 19:00:28   brucea
** Cleanup, no code changes
** 
**    Rev 1.3   15 Jun 1992 09:18:08   brucea
** Added: return SUCCESS to Table::InitOrExtendTable to fix compile warning
** 
**    Rev 1.2   02 Jan 1992 12:00:54   john
** Added check to make sure memory should be freed
** 
**    Rev 1.1   09 Dec 1991 09:27:50   john
** Added code to handle reinitializing the TABLE entries.  This was
** done to support removing all symbols from the symbol table.
** 
**    Rev 1.0   11 Sep 1991 09:08:56   brucea
** Initial revision.
**
** $Header:   S:/tbird/arcppc/symbol/memmanag.cpv   1.2   12 Mar 1997 14:47:44   hera  $
**
** Copyright (C) 1991 Microtek International.  All rights reserved.
**
**--------------------------------------------------------------------------*/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#ifndef _MEMMANAG_
#include "memmanag.h"
#endif

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

//------------------------------------------------------------------------
// Table::InitOrExtendTable
//
// Purpose:
//    Initialize table if tableSize = 0 else
//    extend the table by <expandSize>.
//
// Input parameters:
//    allocFlag:
//       0 if memory does not need to be zeroed upon initialization
//       GMEM_ZEROINIT if memory needs to be zeroed upon initialization
//
// Output parameters: None
//
// Error:
//    Reports ER_SYM_OUT_OF_MEMORY if memory cannot be Alloc'ed or ReAlloc'ed
//------------------------------------------------------------------------
RETCODE Table::InitOrExtendTable(WORD zeroInitFlag) {

   HANDLE tempTableHandle;
   U32 memAvailable;
   U32 trialSize;    // latest incremental size to try

   if (!tableSize) {  // table has not been Alloc'ed yet
      if (!(tableHandle = GlobalAlloc(GMEM_MOVEABLE | zeroInitFlag,
                                      initialSize))) {
         // not enough memory found; compact then check again

         memAvailable = GlobalCompact(initialSize);
         if (memAvailable < initialSize) {
            return ER_SYM_OUT_OF_MEMORY;
         } else {
            if (!(tableHandle = GlobalAlloc(GMEM_MOVEABLE | zeroInitFlag,
                                            initialSize)))
               return ER_SYM_OUT_OF_MEMORY;
         }
      }
      // memory found; fall thru

      if ((hpTableObject = (HPU8)GlobalLock(tableHandle)) != 0L) {
         //successful initial allocation
         // actual size may be larger than requested size, but we only want
         // the size on an even binary boundary
         tableSize= initialSize;
         return SUCCESS;
      }
   } else {  // table has been previously Alloc'ed; need to ReAlloc
      trialSize = expandSize;

#ifdef DEBUG
      if (expandSize < MIN_EXPAND_SIZE) return ER_EXPAND_SIZE_ERROR;
#endif

	   if (!(tempTableHandle = GlobalReAlloc(tableHandle,
                                            (tableSize + trialSize),
                                            GMEM_MOVEABLE | zeroInitFlag))) {
         // GlobalReAlloc failed; compact and try again
         GlobalCompact(tableSize + trialSize);  // ignore return value
         for (;;)  {
            if ((tempTableHandle =
               GlobalReAlloc(tableHandle,
                             (tableSize + trialSize),
                             GMEM_MOVEABLE | zeroInitFlag)) != 0)
               // get out of loop if the ReAlloc worked
               { break; };

            // reduce requested size in half and try again
            if ((trialSize >>= 1) < 256)
               return ER_SYM_OUT_OF_MEMORY;
         }
      }
      // memory found
      tableHandle = tempTableHandle;    // restore handle

      // restore huge pointer
      if ((hpTableObject = (HPU8)GlobalLock(tableHandle)) != 0L)  {
         //successful lock; update total memory size
         tableSize += trialSize;

         // even though actual size may be larger than requested size,
         // want to maintain binary boundary of memory so that data
         // elements don't cross 64K boundary
         return SUCCESS;
      } else { //GlobalLock failed
         return ER_SYM_OUT_OF_MEMORY;
      }
   }  // end of else part of if (!tableSize)
   return SUCCESS;
};  // end of Table::InitOrExtendTable


//------------------------------------------------------------------------
// Table::ObliterateTable
//
// Purpose: release this table memory with GlobalFree
//------------------------------------------------------------------------
VOID Table::ObliterateTable(VOID) {

   // call the routines to free memory only if the tableHandle is non-zero ;
   if (tableHandle) {
      GlobalUnlock(tableHandle);
      GlobalFree(tableHandle);
   }
   tableHandle = 0;
   tableSize = 0L;
   initialSize = INITIAL_TABLE_SIZE;
   expandSize = MIN_EXPAND_SIZE;
}

/******************************** E O F *************************************/