/*-------------------------------------------------------------------------
** Name: indextbl.cpp
**
** Title: Index Table
**
** Purpose:
**  Supports the creation of a Base Index Table and Type Index Table and
**  provides methods for adding an index and retrieving an offset for an index
**
**  Base class = table
**
** Status: CODED
**
** $Log:   S:/tbird/mt2_186/symbol/indextbl.cpv  $
** 
**    Rev 1.1   26 Feb 1997 11:42:52   Judy
** 
**    Rev 1.1   14 Jan 1997 15:30:44   Judy
** No change.
** 
**    Rev 1.0   14 Jun 1996 16:42:00   Judy
** Initial revision.
** 
**    Rev 1.10   10 Mar 1995 14:56:46   nghia
** Added check for index >= maxIndex to prevent MAX_INDEX to roll to 0 when
** adding 1 to it.
** 
**    Rev 1.9   21 Dec 1994 15:20:36   nghia
** Fixed Cooper's GPF bug, Symbol table failed to expand in holding more than
** 2M+ type indexes.  Added memory reallocation recovery.
** 
**    Rev 1.8   22 Oct 1992 18:22:10   brucea
** Changed: MAX_INDEX_SIZE to be maximum 32 bit value.  This removes a size
**    restriction on the type index table (typit).  For the inherited
**    base index table, it changes the value to its restricted limit
** 
**    Rev 1.7   20 Apr 1992 09:00:52   brucea
** Cosmetic cleanups
** 
**    Rev 1.6   09 Dec 1991 09:20:32   john
** Added member function to free the allocated memory for the 
** index table.
** 
**    Rev 1.5   08 Nov 1991 13:54:04   john
** Added code to update type table index offset.  This was done
** because a type may grow beyond a 64k boundary limit.  When this
** occurs the header must be moved and the offset pointing to that
** header must be updated.
** 
**    Rev 1.4   01 Nov 1991 10:59:08   brucea
** Added #ifdef DEBUG around #ifndef _WINIO_
** 
**    Rev 1.3   15 Oct 1991 10:25:50   brucea
** Added ER_TABLE_SMALLER_THAN_INDEX to GetOffset
** 
**    Rev 1.2   14 Oct 1991 12:58:34   brucea
** In GetOffset, changed the compare for index out of bounds from using
** tableSize to using maxIndex, since the table size can increase with more
** alloc's.  The maximum table size is defined by maxIndex.
** 
**    Rev 1.1   13 Sep 1991 09:59:12   brucea
** No change.
** 
**    Rev 1.0   09 Sep 1991 11:06:30   brucea
** Initial revision.
**
** $Header:   S:/tbird/mt2_186/symbol/indextbl.cpv   1.1   26 Feb 1997 11:42:52   Judy  $
**
** Copyright (C) 1991 Microtek International.  All rights reserved.
**
**------------------------------------------------------------------------*/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef _INDEXTBL_
#include "indextbl.h"
#endif

#ifndef _MEMPOOL_
#include "mempool.h"
#endif

#ifdef DEBUG
#ifndef _WINIO_
#include "winio.h"
#endif
#endif
                       /****************************
                        *                          *
                        *        DEFINITIONS       *
                        *                          *
                        ****************************/


#define INDEXTABLE_INIT_SIZE      (16L * 1024L)
#define INDEXTABLE_EXPANSION_SIZE (4L * 1024L)
#define MAX_INDEX_SIZE           0xFFFFFFFFL // this is the max size of any
                                             // index table;  If desired to be
                                             // smaller, inherited class must
                                             // set smaller;
                                             // e.g. BaseIndexTable

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

//member functions for IndexTable

IndexTable::IndexTable():Table()      // constructor with no params
   {
   entryCount = 0L;  // initialize member vars
   initialSize = INDEXTABLE_INIT_SIZE;
   expandSize  = INDEXTABLE_EXPANSION_SIZE;
   maxIndex = MAX_INDEX_SIZE;
}   // end of IndexTable constructor


//------------------------------------------------------------------------
// IndexTable::AddIndex
//
// Purpose:
//    Add an index into the index table with its offset to the item.
//
// Input parameters:
//    index: TABLE_OFFSET index into index table.
//    itemOffset: offset into the symbol table to be stored at table[index]
//
// Output parameters: None
//
// Error:
//    Reports ER_INDEX_ALREADY_EXISTS if the index already has a legitimate
//    value in the index location in the table.
//    Reports ER_INDEX_OUT_OF_BOUNDS if the requested index is larger than
//       the maximum table size
//
// Pseudo-code for allocation
//    if table not alloc'ed yet, set up to alloc on 256 byte boundary that
//       includes requested index
//    if table alloc'ed, set up to realloc on 256 byte boundary, also to
//       include requested index
//    if table alloc'ed, must set expandSize = additional amount to extend
//       table by
//------------------------------------------------------------------------
RETCODE IndexTable::AddIndex(TABLE_INDEX index, TABLE_OFFSET itemOffset) {

   HP_TABLE_OFFSET hpTable;
   U32 tmpTableSize, tmpExpandSize = 0L;
   RETCODE retCode;
   TABLE_INDEX indexPlus1;

   indexPlus1 = index + 1;
   if (indexPlus1 > maxIndex) return ER_INDEX_OUT_OF_BOUNDS;
   // index starts at 0; must incr to calculate the number of bytes needed
   // at that point in the array before testing for greater than tableSize
   if (((indexPlus1) * (sizeof(TABLE_OFFSET))) > tableSize) {
      // must expand table to accommodate new index.
      // calculate needed table size and round up (will add extra 256 if it
      // is initially on an even 256 boundary)
      tmpTableSize = ((indexPlus1 * (sizeof(TABLE_OFFSET)) + 256)
                     & 0xFFFFFF00L);

      if (!tableSize)  {     // table has not been allocated yet
         initialSize = max(initialSize, tmpTableSize);
      } else {
         // must convert absolute request to relative size increase;
         // subtract the present table size from the requested size
         // to come up with the amount to expand the table by
         tmpExpandSize = tmpTableSize - tableSize;
         expandSize = (expandSize > tmpExpandSize)
                      ? expandSize : tmpExpandSize;
      }
      // allocate the memory for new table
      if ((retCode =
         InitOrExtendTable(GMEM_ZEROINIT)) == ER_SYM_OUT_OF_MEMORY) {
         return retCode;
      }
   }
   // memory available; store itemOffset if one is not already there
   hpTable = (HP_TABLE_OFFSET)GetHugeDataPtr(index * (sizeof(TABLE_OFFSET)));

   // 12/19/94 - Nghia
   // Recover from memory allocation failure
   if (!hpTable) {
      // retry  to allocate memory for table again
      if ((retCode =
         InitOrExtendTable(GMEM_ZEROINIT)) == ER_SYM_OUT_OF_MEMORY) {
         return retCode;
      }
      hpTable = (HP_TABLE_OFFSET)GetHugeDataPtr(index*(sizeof(TABLE_OFFSET)));
      if (!hpTable) return ER_SYM_OUT_OF_MEMORY; 
   }
   
   if (!(*hpTable))  {
      *hpTable = itemOffset;  // save offset to item in symbol table
      entryCount++;           // index entry counts 
      return SUCCESS;
   } else
      return ER_INDEX_ALREADY_EXISTS;
}   // end of AddIndex


//------------------------------------------------------------------------
// IndexTable::GetOffset
//
// Purpose:
//    Retrieve offset to item in symbol table given the index to the index
//    table.
//
// Input parameters:
//    index:
//       TABLE_OFFSET index into index table; the index is to the size
//       of a TABLE_OFFSET
//
// Output parameters:
//    itemOffset:
//       offset into symbol table of item
//
// Error:
//    Reports ER_INDEX_NOT_IN_TABLE if the index field is NULL
//    Reports ER_INDEX_OUT_OF_BOUNDS if the requested index is larger than
//       the maximum index parameter allowed (it is not depended on table
//       size because the table can be alloc'ed bigger).
//------------------------------------------------------------------------
 RETCODE IndexTable::GetOffset(TABLE_INDEX index,
                               TABLE_OFFSET& itemOffset) {

   if ((index >= maxIndex) || ((index + 1) > maxIndex))
      return ER_INDEX_OUT_OF_BOUNDS;
   else if ((index + 1) > (tableSize / (sizeof(TABLE_OFFSET)))) {
      return ER_TABLE_SMALLER_THAN_INDEX;
   } else {
      itemOffset =
         *(HP_TABLE_OFFSET)GetHugeDataPtr(index * (sizeof(TABLE_OFFSET)));
      if (!itemOffset)  // if NULL then item not in table
         return ER_INDEX_NOT_IN_TABLE;
      else
         return SUCCESS;
   }
}   // end of GetOffset


//------------------------------------------------------------------------
// IndexTable::ObliterateTable
//------------------------------------------------------------------------
VOID IndexTable::ObliterateTable(VOID) {

   Table::ObliterateTable();
   entryCount = 0L;  // initialize member vars
   initialSize = INDEXTABLE_INIT_SIZE;
   expandSize  = INDEXTABLE_EXPANSION_SIZE;
   maxIndex = MAX_INDEX_SIZE;
}  // end of IndexTable::ObliterateTable


//------------------------------------------------------------------------
// IndexTable::UpdateOffset
//------------------------------------------------------------------------
RETCODE IndexTable::UpdateOffset(TABLE_INDEX index, TABLE_OFFSET newOffset) {

   HPU8 offsetPtr;
   
   if ((index + 1) > maxIndex)
      return ER_INDEX_OUT_OF_BOUNDS;
   else if ((index + 1) > (tableSize / (sizeof(TABLE_OFFSET)))) {
      return ER_TABLE_SMALLER_THAN_INDEX;
   } else {
      offsetPtr = GetHugeDataPtr(index * (sizeof(TABLE_OFFSET)));
      if (! (U32 *) offsetPtr)  // if NULL then item not in table
         return ER_INDEX_NOT_IN_TABLE;
      else
         *(U32 *)offsetPtr = newOffset;
         return SUCCESS;
   }
}  // end of IndexTable::UpdateOffset

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