/* Filename: WVString.cpp */

/*
* $Id: wvstring.cpp 1.8 1997/03/18 19:30:04 dumoulin Exp $
 */

#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"

#pragma hdrstop

#include <limits.h>
#include "wvclass.h"

// WVString memory management

WMemPool WVString::m_ClassPool(sizeof(WVString), POOLBLOCKSIZE / sizeof(WVString));

WMemPool Pool16 ( 16, POOLBLOCKSIZE / 16);
WMemPool Pool24 ( 24, POOLBLOCKSIZE / 24);
WMemPool Pool32 ( 32, POOLBLOCKSIZE / 32);
WMemPool Pool48 ( 48, POOLBLOCKSIZE / 48);
WMemPool Pool64 ( 64, POOLBLOCKSIZE / 64);
WMemPool Pool80 ( 80, POOLBLOCKSIZE / 80);
WMemPool Pool96 ( 96, POOLBLOCKSIZE / 96);
WMemPool Pool112(112, POOLBLOCKSIZE /112);
WMemPool Pool128(128, POOLBLOCKSIZE /128);
WMemPool Pool160(160, POOLBLOCKSIZE /160);
WMemPool Pool192(192, POOLBLOCKSIZE /192);
WMemPool Pool256(256, POOLBLOCKSIZE /256);

LATEST Latest;

void*WVString::operator new(size_t size)
{
#ifdef _DEBUG
  if(size != sizeof(WVString))
  {
    DEBUG_BREAK; //  derived classes must provide their own operator new
  }
#endif

  return m_ClassPool.AllocElement();
}


void WVString::operator delete(void*p)
{
#ifdef _DEBUG
  if(p == 0)  // this should never happen...
  {
    DEBUG_BREAK;
    return;
  }
#endif
  m_ClassPool.FreeElement(p);
}


WVString::WVString(const char*s, const uint32 uLen)
{
  if(s)
  {
    if(uLen)
    {
      m_data = new char[1 + uLen];
      if(m_data)
      {
        strncpy(m_data, s, uLen);
        m_data[uLen] = '\0';
      }
    }
    else
    {
      m_data = new char[1+strlen(s)];
      if(m_data)
        strcpy(m_data, s);
    }
  }
  else
  {
    m_data = new char[1];
    if(m_data)
      *m_data = '\0';
  }
}


//WVString::WVString(const WVString&rhs)
//{
//  m_data = new char[1 + strlen(rhs.m_data)];
//  if(m_data)
//    strcpy(m_data, rhs.m_data);
//}
//    Add a few extra checks - JD 2/14/97

WVString::WVString(const WVString&rhs)
{
  int ilen;
  
  if (rhs.m_data) {
    ilen = strlen(rhs.m_data);
    if (ilen > 0) {
      m_data = new char[1 + strlen(rhs.m_data)];
      if(m_data)
        strcpy(m_data, rhs.m_data);
    }
  }
  else {
    m_data = new char[1];
    if(m_data)
      *m_data = '\0';
  }
}



WVString::WVString(const WVString&lhs, const WVString&rhs)
{
  m_data = new char[1 + strlen(lhs.m_data) + strlen(rhs.m_data)];
  if(m_data)
  {
    strcpy(m_data, lhs.m_data);
    strcat(m_data, rhs.m_data);
  }
}


WVString::~WVString()
{
  delete [] m_data;
}


WVString& WVString::operator=(const WVString& rhs)
{
  uint32 iNewSize;

  //if(strcmp(m_data, rhs.m_data) != 0) // value compare
  if(this != &rhs) // address compare
  {
    if(rhs.m_data) {
	  iNewSize = 1 + strlen(rhs.m_data);
      if(AllocSize() < iNewSize)
      {
        delete [] m_data;
        m_data = new char[iNewSize];
      }
      if(m_data)
        strcpy(m_data, rhs.m_data);
    }
    else
    {
      if(!m_data)
      {
        m_data = new char[1];
      }
      if(m_data)
        *m_data = '\0';
    }
  }
  return *this;
}


WVString& WVString::operator=(const char* rhs)
{
  uint32 iNewSize;
  
  //if((rhs) && (strlen(rhs) > 0))           // JD 2/14/97
  if(rhs)  // okay if strlen(rhs) == 0
  {
    iNewSize = 1 + strlen(rhs);
    if(AllocSize() < iNewSize)
    {
      delete [] m_data;
      m_data = new char[iNewSize];
    }
    if(m_data)
      strcpy(m_data, rhs);
  }
  else
  {
    if(!m_data)
    {
      m_data = new char[1];
    }
    if(m_data)
      *m_data = '\0';
  }
  return *this;
}


WVString& WVString::operator+=(const WVString& rhs)
{
  char*tmp;
  uint32 iNewSize = 1 + strlen(m_data) + strlen(rhs.m_data);
  
  if(iNewSize > AllocSize())
  {
    tmp = new char[iNewSize];
    if(tmp)
    {
      strcpy(tmp, m_data);
      strcat(tmp, rhs.m_data);
      delete [] m_data;
      m_data = tmp;
    }
  }
  else
  {
    strcat(m_data, rhs.m_data);
  }
  return *this;
}


WVString& WVString::operator+=(const char* rhs)
{
  if(rhs)
  {
    char*tmp;
    uint32 iNewSize = 1 + strlen(m_data) + strlen(rhs);

    if(iNewSize > AllocSize())
    {
      tmp = new char[iNewSize];
      if(tmp)
      {
        strcpy(tmp, m_data);
        strcat(tmp, rhs);
        delete [] m_data;
        m_data = tmp;
      }
    }
    else
    {
      strcat(m_data, rhs);
    }
  }
  return *this;
}


uint32 WVString::AllocSize()
{
  NewStruct* pNS = (NewStruct*) m_data;
  if(!pNS)
    return 0;
  pNS--;
  return pNS->iAllocSize;
}


/*

  C++ Memory management routines

  Written July 1996 H. Brydon

*/


// C++ fixed size memory pool implementation

WMemPool::WMemPool(uint32 uElementSize, unsigned uNumElements)
: m_FreeList(NULL), m_pBlock(NULL),
  m_uElmSize(((uElementSize + sizeof(WMemPool::MemPoolElement)-1) /
    sizeof(WMemPool::MemPoolElement)) * sizeof(WMemPool::MemPoolElement)),
  m_uBlkSize(uNumElements * m_uElmSize)
{
#ifdef _DEBUG
  if(!(m_uElmSize && m_uBlkSize))
    DEBUG_BREAK;
#endif
  //AllocBlock();
}


WMemPool::~WMemPool()
{
  MemPoolBlock*p;

  while(m_pBlock)
  {
#ifdef DEBUGMEMUSAGE
    TRACE2("AllocBlock(): Block of size %u/%u freed\n",
      m_uElmSize, m_uBlkSize);
#endif
    p = m_pBlock->next;
    //delete m_pBlock;
    GlobalFreePtr(m_pBlock);
    m_pBlock = p;
  }
}


void WMemPool::AllocBlock()  // 335.11
{
  unsigned iSize = sizeof(MemPoolBlock) + m_uBlkSize;
  unsigned num;

  MemPoolBlock* pBlk = (MemPoolBlock *) GlobalAllocPtr(GMEM_FIXED, iSize);
  if(pBlk)
  {
#ifdef DEBUGMEMUSAGE
    TRACE3("AllocBlock(): Block of size %u/%u (%u total) allocated\n",
      m_uElmSize, m_uBlkSize, iSize);
#endif    
    pBlk->next = m_pBlock;
    m_pBlock = pBlk;
    MemPoolElement*pe = &pBlk->pe;

    num = m_uBlkSize/m_uElmSize;
    while(--num > 0)
    {
      pe->next = (MemPoolElement*) ((char*) pe + m_uElmSize);
      pe = pe->next;
    }
    pe->next = m_FreeList;
    m_FreeList = &pBlk->pe;
  }
#ifdef DEBUGMEMUSAGE
  else
  {
    TRACE1("AllocBlock(): No memory for block of size %u!\n", iSize);
    DEBUG_BREAK;
  }
#endif
}


void*operator new(size_t iReqSize)
{
  uint32 iGetSize;
  NewStruct*memory = NULL;
  if(iReqSize == 0)
  {
    iReqSize = 1;
  }
  iGetSize = iReqSize + sizeof(NewStruct);
  
  if(iGetSize <= 16)
  {
    static uint32 iAllocSize = 16 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool16.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 24)
  {
    static uint32 iAllocSize = 24 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool24.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 32)
  {
    static uint32 iAllocSize = 32 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool32.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 48)
  {
    static uint32 iAllocSize = 48 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool48.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 64)
  {
    static uint32 iAllocSize = 64 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool64.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 80)
  {
    static uint32 iAllocSize = 80 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool80.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 96)
  {
    static uint32 iAllocSize = 96 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool96.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 112)
  {
    static uint32 iAllocSize = 112 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool112.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 128)
  {
    static uint32 iAllocSize = 128 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool128.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 160)
  {
    static uint32 iAllocSize = 160 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool160.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 192)
  {
    static uint32 iAllocSize = 192 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool192.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  else if(iGetSize <= 256)
  {
    static uint32 iAllocSize = 256 - sizeof(NewStruct);
    if(memory = (NewStruct*) Pool256.AllocElement())
      memory->iAllocSize = iAllocSize;
  }
  if (!memory)
  {
    if(memory = (NewStruct*) GlobalAllocPtr(GMEM_FIXED, iGetSize))
    {
#ifdef DEBUGMEMUSAGE
      TRACE2("operator new: Memory block of size %u/%u allocated\n",
        iReqSize, iGetSize);
#endif      
      memory->iAllocSize = iGetSize - sizeof(NewStruct);
    }
  }
#ifdef DEBUGMEMUSAGE
  if(memory)
  {
    static uint32 iSeqNo = 0;
    memory->iSeqCtr = ++iSeqNo;
  }
#endif
  return (void*) &memory[1];
}

// A Huge pointer version of the new operator to fix
// allocation problems with Win16. (JD 1/7/97)
#ifdef _WIN32
 void __far *operator new(unsigned int lReqSize, size_t ReqSize1)
#else
 void __huge *operator new(unsigned long lReqSize, size_t ReqSize1)
#endif

{
  unsigned long lGetSize;
  NewStruct*memory = NULL;
  if(lReqSize == 0)          
  {
    lReqSize = 1;
  }
  lGetSize = (lReqSize * ReqSize1) + sizeof(NewStruct);

  if(memory = (NewStruct*) GlobalAllocPtr(GMEM_FIXED, lGetSize))
    {
#ifdef DEBUGMEMUSAGE
      TRACE2("operator new: Memory block of size %lu/%lu allocated\n",
        lReqSize, lGetSize);
#endif      
      memory->iAllocSize = lGetSize - sizeof(NewStruct);
    }
#ifdef DEBUGMEMUSAGE 
  if(memory)
  {
    static int iSeqNo = 0;
    memory->iSeqCtr = ++iSeqNo;
  }
#endif
  return (void*) &memory[1];
}


void operator delete(void*p)
{
  if(p)
  {
    NewStruct* pNS = (NewStruct*) p;
    
    pNS--;
    switch(pNS->iAllocSize)
    {
    case  16 - sizeof(NewStruct):
      Pool16.FreeElement(pNS);
      break;
    case  24 - sizeof(NewStruct):
      Pool24.FreeElement(pNS);
      break;
    case  32 - sizeof(NewStruct):
      Pool32.FreeElement(pNS);
      break;
    case  48 - sizeof(NewStruct):
      Pool48.FreeElement(pNS);
      break;
    case  64 - sizeof(NewStruct):
      Pool64.FreeElement(pNS);
      break;
    case  80 - sizeof(NewStruct):
      Pool80.FreeElement(pNS);
      break;
    case  96 - sizeof(NewStruct):
      Pool96.FreeElement(pNS);
      break;
    case  112 - sizeof(NewStruct):
      Pool112.FreeElement(pNS);
      break;
    case  128 - sizeof(NewStruct):
      Pool128.FreeElement(pNS);
      break;
    case  160 - sizeof(NewStruct):
      Pool160.FreeElement(pNS);
      break;
    case  192 - sizeof(NewStruct):
      Pool192.FreeElement(pNS);
      break;
    case  256 - sizeof(NewStruct):
      Pool256.FreeElement(pNS);
      break;
    default:
#ifdef DEBUGMEMUSAGE
      TRACE1("operator delete: Memory block of size %lu being freed\n",
        pNS->iAllocSize + sizeof(NewStruct));
#endif
      if ((pNS->iAllocSize < 64000)  && (pNS->iAllocSize > 0))
      {
        GlobalFreePtr(pNS);
      }
      else
      {
        TRACE2("operator delete failed: Memory block of size %lu (Hex %Z08) too big\n",
          pNS->iAllocSize + sizeof(NewStruct), pNS->iAllocSize + sizeof(NewStruct));
        DEBUG_BREAK;
      }
    }
  }
}



