text: /*------------------------------------------------------------*/
  /* filename -       new.cpp                                   */
  /*------------------------------------------------------------*/
  /*
   *      Turbo Vision - Version 2.0
   *
   *      Copyright (c) 1994 by Borland International
   *      All Rights Reserved.
   *
   */
  
  #define Uses_TVMemMgr
  #include <tvision/tv.h>
  
  #ifndef NDEBUG
  #define NDEBUG
  #endif
  #include <assert.h>
  
  #if !defined( __MEM_H )
  #include <mem.h>
  #endif  // __MEM_H
  
  #if !defined( __ALLOC_H )
  
  #include <alloc.h>
  #endif  // __ALLOC_H
  
  #if !defined( __STDLIB_H )
  #include <stdlib.h>
  #endif  // __STDLIB_H
  
  TBufListEntry * _NEAR TBufListEntry::bufList = 0;
  
  TBufListEntry::TBufListEntry( void*& o, size_t sz ) noexcept :
      owner( o ),
      sz( sz )
  {
      next = bufList;
      prev = 0;
      bufList = this;
      if( next != 0 )
          next->prev = this;
  }
  
  void TBufListEntry::destroy()
  {
      owner = 0;
      if( prev == 0 )
          bufList = next;
      else
          prev->next = next;
      if( next != 0 )
          next->prev = prev;
      delete this;
  }
  
  void *TBufListEntry::operator new( size_t sz, size_t extra ) noexcept
  {
      return malloc( sz + extra );
  }
  
  void *TBufListEntry::operator new( size_t ) noexcept
  {
      return 0;
  }
  
  void TBufListEntry::operator delete( void *b ) noexcept
  {
      free( b );
  }
  
  Boolean TBufListEntry::freeHead()
  {
      if( bufList == 0 )
          return False;
      else
          {
          bufList->destroy();
          return True;
          }
  }
  
  void * _NEAR TVMemMgr::safetyPool = 0;
  size_t _NEAR TVMemMgr::safetyPoolSize = 0;
  int _NEAR TVMemMgr::inited = 0;
  
  TVMemMgr memMgr;
  
  TVMemMgr::TVMemMgr()
  {
      if( !inited )
          resizeSafetyPool();
  }
  
  TVMemMgr::~TVMemMgr()
  {
      resizeSafetyPool(0);
      inited = 0;
  }
  
  void TVMemMgr::resizeSafetyPool( size_t sz )
  {
      inited = 1;
      free( safetyPool );
      if( sz == 0 )
          safetyPool = 0;
      else
          safetyPool = malloc( sz );
      safetyPoolSize = sz;
  }
  
  int TVMemMgr::safetyPoolExhausted()
  {
      return inited && (safetyPool == 0);
  }
  
  void TVMemMgr::allocateDiscardable( void *&adr, size_t sz )
  {
      if( safetyPoolExhausted() )
          adr = 0;
      else
          {
          TBufListEntry *newEntry = new( sz ) TBufListEntry( adr, sz );
          if( newEntry == 0 )
              adr = 0;
          else
              adr = (char *)newEntry + sizeof(TBufListEntry);
          }
  }
  
  void TVMemMgr::reallocateDiscardable( void *&adr, size_t sz )
  {
      if( !sz )
          {
          freeDiscardable( adr );
          adr = 0;
          }
      else if( !adr )
          allocateDiscardable( adr, sz );
      else
          {
          TBufListEntry *entry = (TBufListEntry *)((char *)adr - sizeof(TBufListEntry));
          if( sz < entry->sz )
              {
              void *p = ::realloc(entry, sizeof(TBufListEntry) + sz);
              if( p )
                  {
                  TBufListEntry *newEntry = (TBufListEntry *)p;
                  if( newEntry->prev )
                      newEntry->prev->next = newEntry;
                  else
                      TBufListEntry::bufList = newEntry;
                  if( newEntry->next )
                      newEntry->next->prev = newEntry;
                  newEntry->sz = sz;
                  adr = (char *)p + sizeof(TBufListEntry);
                  }
              else
                  {
                  freeDiscardable( adr );
                  adr = 0;
                  }
              }
          else if( sz > entry->sz )
              {
              freeDiscardable( adr );
              allocateDiscardable( adr, sz );
              }
          }
  }
  
  void TVMemMgr::freeDiscardable( void *block )
  {
      if (block)
          ((TBufListEntry *)((char *)block - sizeof(TBufListEntry)))->destroy();
  }
  
  #if defined( __BORLANDC__ )
  
  #if !defined( NDEBUG )
  const int BLK_SIZE = 16;
  const int BLK_DATA = 0xA6;
  #else
  const int BLK_SIZE = 0;
  #endif
  
  void * allocBlock( size_t sz )
  {
      assert( heapcheck() >= 0 );
  
      sz += BLK_SIZE;
      if( sz == 0 )
          sz = 1;
  
      void *temp = malloc( sz );
      while( temp == 0 && TBufListEntry::freeHead() == True )
          temp = malloc( sz );
      if( temp == 0 )
          {
          if( TVMemMgr::safetyPoolExhausted() )
              abort();
          else
              {
              TVMemMgr::resizeSafetyPool( 0 );
              temp = malloc( sz );
              if( temp == 0 )
                  abort();
              }
          }
  #if !defined( NDEBUG )
      memset( temp, BLK_DATA, BLK_SIZE );
  #endif
      return (char *)temp + BLK_SIZE;
  }
  
  void * operator new[] ( size_t sz )
  {
     return allocBlock(sz);
  }
  
  void * operator new ( size_t sz )
  {
     return allocBlock(sz);
  }
  
  #if !defined( NDEBUG )
  static void check( void *blk )
  {
      for( int i = 0; i < BLK_SIZE; i++ )
          assert( *((unsigned char *)blk + i) == BLK_DATA );
  }
  #endif
  
  static void deleteBlock( void *blk )
  {
      assert( heapcheck() >= 0 );
      if( blk == 0 )
          return;
      void *tmp = (char *)blk - BLK_SIZE;
  #if !defined( NDEBUG )
      check( tmp );
  #endif
      free( tmp );
      if( TVMemMgr::safetyPoolExhausted() )
          TVMemMgr::resizeSafetyPool();
  }
  
  void operator delete ( void *blk )
  {
     deleteBlock(blk);
  }
  
  void operator delete[] ( void *blk )
  {
     deleteBlock(blk);
  }
  
  #endif
  