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

  Simple Object Stack (SOS), copyright (c) 1997 by Salvador E. Tropea (SET)

  If you want to use this code contact me first.

  Purpose:
    The SOS was designed to reduce the number of memory allocations needed
  for string lists operations and to reduce the wasted space.
    The overhead of each allocation is sizeof(size_t) plus the bytes needed
  to align the object to a Dowble Word boundary, so all the obejcts are
  32 bits aligned if size_t is 32 bits or 16 bits if size_t is 16 bits.
    As the routines were designed with the DJGPP malloc scheme in mind the
  program takes memory in cuasi-2-power chunks, that's for example 976 bytes,
  1952, 3904, etc.
    The class have only one chunk of memory that is managed as an stack, so
  the number of elements in the global heap is reduced. As this chunk of
  memory can be resized when all is used and that's involves a call to
  realloc the class can return pointers to the objects, instead returns
  handlers type stkHandler. To convert this handler to a pointer 2 members
  are provided: GetPointerOf and GetStrOf, basically are just the same
  but the second avoids a cast in string operations. The both are inline
  and are just an addittion so the overhead is minimal.

  Notes of application:

    I used it for lists of strings in dialog boxes, so I was forced to
  overwrite some classes:

  TNoCaseSOSStringCollection from TStringCollection:
    Is a collection, no case sensitive that uses an SOStack for the strings,
  the class ISN'T the owner of the SOStack, so you must put the strings in
  the SOStack and insert the stkHandler in the collection. When the
  collection is destroyed the SOStack ISN'T destroyed.

  TSOSSortedListBox from public TSortedListBox:
    Is a sorted listbox that support a TNoCaseSOSStringCollection as
  collection, that's needed because the original can't handle the stkHandler.

  The both are in tnocastc.cc and tnocastc.h

  E-Mail: salvador@inti.edu.ar

  Telephone: (+541) 759-0013

  Postal Address:
  Salvador E. Tropea
  Curapalige 2124
  (1678) Caseros - 3 de Febrero
  Prov: Buenos Aires
  Argentina

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

#include "setstack.h"

SOStack::SOStack()
{
 Buffer=NULL;
 MemPool=0;
 Size=0;
 Cant=0;
}

SOStack::~SOStack()
{
 delete Buffer;
 Buffer=NULL;
}

size_t SOStack::MakeRoomFor(size_t bytes)
{
 size_t rest=4-(bytes & 3);
 size_t requested;

 if (rest==4)
    rest=0;
 bytes+=rest+sizeof(size_t);
 requested=Size+bytes;
 if (requested>MemPool)
   {
    if (!MemPool)
       MemPool=stkInitialMemPool;
    while (MemPool<requested)
       MemPool*=2;
    Buffer=(char *)realloc(Buffer,MemPool);
   }
 return requested;
}

stkHandler SOStack::AddItem(void *p, size_t size, size_t req)
{
 if (Buffer)
   {
    stkHandler ret=Size;
    memcpy(&Buffer[ret],p,size);
    LastChunk=*((size_t *)(&Buffer[req-sizeof(size_t)]))=req-Size;
    Size=req;
    Cant++;
    return ret;
   }
 return 0;
}

stkHandler SOStack::AddEmptyItem(size_t req)
{
 if (Buffer)
   {
    stkHandler ret=Size;
    LastChunk=*((size_t *)(&Buffer[req-sizeof(size_t)]))=req-Size;
    Size=req;
    Cant++;
    return ret;
   }
 return 0;
}

stkHandler SOStack::addStr(char *s)
{
 size_t l;

 for (l=0; s[l]; l++);
 return add(s,l+1);
}

void SOStack::DestroyTop(int shrink)
{
 if (Buffer && Size)
   {
    Size-=LastChunk;
    LastChunk=*((size_t *)(&Buffer[Size-sizeof(size_t)]));
    Cant--;
    if (shrink && Size*2<MemPool)
      {
       size_t newSize=MemPool;
       size_t testSize=MemPool;

       while (testSize>Size)
         {
          newSize=testSize;
          testSize>>=1;
         }
       Buffer=(char *)realloc(Buffer,newSize);
       MemPool=newSize;
      }
   }
}

void *SOStack::GetTop()
{
 if (Buffer && Size)
    return (void *)(&Buffer[Size-LastChunk]);
 return NULL;
}

stkHandler SOStack::GetTopHandle()
{
 if (Buffer && Size)
    return Size-LastChunk;
 return 0;
}

stkHandler SOStack::GetPreviousOf(stkHandler pos)
{
 if (Buffer && Size && pos)
    return pos-*((stkHandler *)(&Buffer[pos-sizeof(size_t)]));
 return 0;
}

void *SOStack::GetItemNumber(unsigned index)
{
 if (Buffer && Size && index<Cant)
   {
    unsigned i=Cant;
    size_t *Len=(size_t *)(Buffer+Size-sizeof(size_t));

    do
      {
       Len=(size_t *)(((char *)Len)-*Len);
       i--;
      }
    while (index!=i);
    return (void *)(((char *)Len)+sizeof(size_t));
   }
 return NULL;
}
