/*

    ========== licence begin  GPL
    Copyright (c) 2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end

*/
#ifndef __OMS_STACKALLOCATOR_HPP
#define __OMS_STACKALLOCATOR_HPP

#include "Oms/OMS_Globals.hpp"
#include "Oms/OMS_SharedMemAllocator.hpp"
#include "Oms/OMS_DbpError.hpp"

#define OMS_STACK_CHUNK_SIZE 64000

struct OMS_StackAllocatorMemChunk {
  OMS_StackAllocatorMemChunk*  m_next;
  unsigned char m_mem[OMS_STACK_CHUNK_SIZE - sizeof(OMS_StackAllocatorMemChunk*)];
  long memSize() { return sizeof(m_mem); }
};

class OMS_StackAllocator {
public:
  OMS_StackAllocator() : 
       m_usedChunks(NULL), m_rest(0), m_used(0) {}
       void* Malloc( size_t requiredSize);
       void  Free();
       tsp00_8ByteCounter HeapUsed() const { return m_used; } /* PTS 1107731 */
private :
  OMS_StackAllocatorMemChunk*     m_usedChunks;
  unsigned char*     m_curr;
  size_t             m_rest;
  tsp00_8ByteCounter m_used; /* PTS 1107731 */
};



/*----------------------------------------------------------------------*/

inline void* OMS_StackAllocator::Malloc(size_t requiredSize) 
{
  void * p;
  size_t alignedSize = OMS_Globals::AlignSize(requiredSize);
  if (m_rest >= alignedSize) {
    m_rest -= alignedSize;
    p       = m_curr;
    m_curr += alignedSize;
    return p;
  }
  else {
    OMS_StackAllocatorMemChunk* c = REINTERPRET_CAST(OMS_StackAllocatorMemChunk*, 
      OMS_SharedMemAllocator::allocateImpl(sizeof(OMS_StackAllocatorMemChunk)));
    if (c != NULL) {
      c->m_next    = m_usedChunks;
      m_usedChunks = c;
      m_rest       = c->memSize() - alignedSize;
      m_curr       = c->m_mem + alignedSize;
      m_used      += c->memSize(); /* PTS 1107731 */
      return c->m_mem;
    }
    else {
      throw DbpError (DbpError::RTE_ERROR, e_new_failed, __MY_FILE__, __LINE__);
    }
  }
}

/*----------------------------------------------------------------------*/

inline void OMS_StackAllocator::Free() 
{
  OMS_StackAllocatorMemChunk* pCurrChunk = m_usedChunks;
  while (NULL != pCurrChunk)
  {
    OMS_StackAllocatorMemChunk* pDelete = pCurrChunk;
    pCurrChunk = pCurrChunk->m_next;
    OMS_SharedMemAllocator::deallocateImpl(pDelete);
  }
  m_usedChunks = NULL;
  m_rest       = 0;
  m_used       = 0; /* PTS 1107731 */
}

#endif // __OMS_STACKALLOCATOR_HPP
