/*
This product contains certain software code or other information
("AT&T Software") proprietary to AT&T Corp. ("AT&T").  The AT&T
Software is provided to you "AS IS".  YOU ASSUME TOTAL RESPONSIBILITY
AND RISK FOR USE OF THE AT&T SOFTWARE.  AT&T DOES NOT MAKE, AND
EXPRESSLY DISCLAIMS, ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND
WHATSOEVER, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, WARRANTIES OF
TITLE OR NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS, ANY
WARRANTIES ARISING BY USAGE OF TRADE, COURSE OF DEALING OR COURSE OF
PERFORMANCE, OR ANY WARRANTY THAT THE AT&T SOFTWARE IS "ERROR FREE" OR
WILL MEET YOUR REQUIREMENTS.

Unless you accept a license to use the AT&T Software, you shall not
reverse compile, disassemble or otherwise reverse engineer this
product to ascertain the source code for any AT&T Software.

(c) AT&T Corp. All rights reserved.  AT&T is a registered trademark of AT&T Corp.

***********************************************************************

History:

      24/11/99  - initial release by Hartmut Liefke, liefke@seas.upenn.edu
                                     Dan Suciu,      suciu@research.att.com
*/

//**************************************************************************
//**************************************************************************

#include "stdafx.h"

UnpackMemBlock *UnpackMemMan::AllocateMemBlock(UnpackMemBlock **memblockref)
{
   // We make sure that we don't try to allocate more than we need
   if(curmaxblocksize>neededmemoryspace)
      curmaxblocksize=neededmemoryspace;

   // Now we try to allocated as much memory as possible.
   // If this fails, we try to allocated half as much, and so on
   // If the block size drops below 20000K, we are running out of memory !
   do
   {
      *memblockref=(UnpackMemBlock *)mymalloc(curmaxblocksize+sizeof(UnpackMemBlock));
      if(*memblockref!=NULL)
         // We were successful ?? => break
      {
         (*memblockref)->len=curmaxblocksize;
         (*memblockref)->used=0;
         (*memblockref)->next=NULL;

         return *memblockref;
      }

      curmaxblocksize/=2;  // We try half the size

      if(curmaxblocksize<20000)  // Blocksize is very small ? ==> That's it, we drop out !
         return NULL;
   }
   while(1);
}

char UnpackMemMan::Init(unsigned long myneededmemoryspace,unsigned long datablockcount)
{
   neededmemoryspace=myneededmemoryspace+datablockcount*sizeof(UnpackDataBlock);
   curmaxblocksize=MAX_BLOCKSIZE;

   // Let's see if we can already allocate as much as possible
   lastblock=AllocateMemBlock(&firstblock);
   if(lastblock==NULL)
      return -1;

   return 0;
}

UnpackDataBlock *UnpackMemMan::AllocateDataBlocks(unsigned long len)
{
   UnpackDataBlock *firstdatablock=NULL,**lastdatablockref=&firstdatablock;

   while(lastblock->used+sizeof(UnpackDataBlock)+len>lastblock->len)
      // As long as the data block does not fit onto the current memblock
      // We must allocate more space !
   {
      if(lastblock->used+sizeof(UnpackDataBlock)+MIN_DATABLOCKSIZE<lastblock->len)
         // If there is a certain minimum space, then we can at least use parts of the
         // block
      {
         *lastdatablockref=(UnpackDataBlock *)((char *)(lastblock+1)+lastblock->used);
         (*lastdatablockref)->len=lastblock->len-lastblock->used-sizeof(UnpackDataBlock);
         (*lastdatablockref)->next=NULL;

         len-=(*lastdatablockref)->len;
         neededmemoryspace-=(*lastdatablockref)->len;

         lastblock->used=lastblock->len;

         lastdatablockref=&((*lastdatablockref)->next);
      }

      // Now, we allocate a new block

      lastblock=AllocateMemBlock(&(lastblock->next));
      if(lastblock==NULL)
         return NULL;

      lastblock=lastblock->next;
   }

   *lastdatablockref=(UnpackDataBlock *)((char *)(lastblock+1)+lastblock->used);
   (*lastdatablockref)->len=len;
   (*lastdatablockref)->next=NULL;

   neededmemoryspace-=len+sizeof(UnpackDataBlock);

   lastblock->used+=sizeof(UnpackDataBlock)+len;

   return firstdatablock;
}
