/*!***************************************************************************

  module      : RTEMem_Allocator.hpp

  -------------------------------------------------------------------------

  responsible : JoergM

  special area: Common Allocator for small objects in RTE context (replaces malloc/free)
  description : Allocator based on SAPDBMem_RawAllocator implementation

                This allocator wrapps internally a SAPDBMem_RawAllocator that is using
                the RTEMem_RawAllocator instance. It is also a singleton.

  last changed: 2000-12-06  19:04
  see also    : example.html ...
  first created:2000-03-09  18:21

  -------------------------------------------------------------------------





    ========== licence begin  GPL
    Copyright (c) 2000-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 RTEMEM_ALLOCATOR_HPP
#define RTEMEM_ALLOCATOR_HPP

/*===========================================================================*
 *  INCLUDES                                                                 *
 *===========================================================================*/

#include "SAPDBCommon/MemoryManagement/SAPDBMem_IRawAllocator.hpp"
#include "SAPDBCommon/MemoryManagement/SAPDBMem_SynchronizedRawAllocator.hpp"
#include "RunTime/Synchronisation/RTESync_NamedSpinlock.hpp"
/*===========================================================================*
 *  CLASSES, STRUCTURES, TYPES, UNIONS ...                                   *
 *===========================================================================*/

/*! 
  Class: RTEMem_Allocator

  Description: Basic synchronised allocator replacing global 'malloc'/'free'
 */
class RTEMem_Allocator: public SAPDBMem_IRawAllocator
{
public:
  /*!
    Function: Instance

    description: Return reference to single instance of RTEMem_Allocator

    The InitializeInstance function must have been called before.
    
    Return value: Reference to RTEMem_Allocator instance
   */
  static SAPDBMem_IRawAllocator & Instance( );

  /*! 
    Declaration: AlignType

    Description: Type requiring maximal alignment on the 
      given platform. 
  */
  typedef union { void* p; long l; double d; } AlignType;

  /*! 
    Function: Allocate

    Description: Allocates contiguous memory for 'count' bytes.

      The memory is suitably aligned for all types.

      The memory is not initialised.  

      If compiled with -DSAPDB_COMPILE_WITHOUT_EXCEPTION_HANDLING a (void *)0 is returned on failure.

      If compiled without this switch an SAPDBMem_BadAllocException exception is thrown on failure.

    Arguments: count [in] Number of Bytes to allocate

    Return value: Position where memory is allocated
   */
  virtual void* Allocate(SAPDB_ULong count);

  /*! 
    Function: Allocate

    Description: Allocates contiguous memory for 'count' bytes,
      while trying to keep locality with a given memory location.

      If possible, the allocator tries to reserve the memory near
      a specified location.

      The memory is suitably aligned for all types.

      The memory is not initialised.  

      If compiled with -DSAPDB_COMPILE_WITHOUT_EXCEPTION_HANDLING a (void *)0 is returned on failure.

      If compiled without this switch an SAPDBMem_BadAllocException exception is thrown on failure.

    Arguments: count [in] Number of Bytes to allocate
               hint [in] Hint where to allocate memory

    Return value: Position where memory is allocated
  */
  virtual void* Allocate(SAPDB_ULong count, const void * hint);

  /*!
    Function: Deallocate
    
    Description: Frees the memory. 

     The pointer must have been obtained by a previous call to
     'allocate'.

    Arguments: p [in] Pointer to memory to deallocate
  */
  virtual void Deallocate(void * p);

  /*!
    Function: GetIdentifier
    
    Description: Return the identifier of this allocator

    Return value: "RTE_Allocator"
  */
  virtual const SAPDB_UTF8 * GetIdentifier() const 
      { return (const SAPDB_UTF8 *)"RTEMem_Allocator"; }

    /*!----------------------------------------------------------------------
      Function: CalcStatistics
      Description:  Outputs statistics about the memory usage of the allocator.
      Arguments:    BytesUsed [out]
                    The number of bytes used by this allocater.
                    BytesControlled [out]
                    The number of bytes controlled by this allocator.

                    The default implementation returns GetInvalidSize() for 
                    both values.
      Return value: none
      -----------------------------------------------------------------------*/
    virtual void CalcStatistics( SAPDB_ULong &BytesUsed,
                                 SAPDB_ULong &MaxBytesUsed,
                                 SAPDB_ULong &BytesControlled);


	/*!----------------------------------------------------------------------
     function: GetBaseAllocatorCallStatistics
     description:  Outputs statistics about the number of Allocate and Deallocate calls of
                   the allocator to the underlying base allocator.
     arguments:    CountAlloc [out]
                   The number of calls of method Allocate of the base allocator.
                   CountDealloc [out]
                   The number of calls of method Deallocate of the base.

     return value: none
     -----------------------------------------------------------------------*/

    virtual void GetBaseAllocatorCallStatistics(SAPDB_ULong &CountAlloc,
                                  SAPDB_ULong &CountDealloc) const;

    /*!----------------------------------------------------------------------
      Function: GetCallStatistics
      Description:  Outputs statistics about the number of Allocate and Deallocate calls.
      Arguments:    CountAlloc [out]
                    The number of calls of method Allocate.
                    CountDealloc [out]
                    The number of calls of method Deallocate.

      Return value: none
      -----------------------------------------------------------------------*/

    virtual void GetCallStatistics(SAPDB_ULong &CountAlloc,
                                  SAPDB_ULong &CountDealloc) const;

    /*!----------------------------------------------------------------------
      Function:  GetChunkSize
      Description: returns the size of a memory chunk of the allocator.
      Arguments:   p [in]
                   the address of the chunk. Must have been returned by a call
                   of method Allocate.
      Return value: the size of the chunk in bytes

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

   virtual SAPDB_ULong GetChunkSize(const void* p);

   /*!----------------------------------------------------------------------
      Function: GetErrorCount
      Description:  Returns the number of errors found and corrected by the allocator

                    The derived class is responsible to implement this feature (but must not do so...)

      Return value: integer
   -----------------------------------------------------------------------*/

   virtual int GetErrorCount() const; 
   
   /*!
      @brief          Returns the number of failed allocation requests
      @return         number of failed allocation requests
    */
   virtual SAPDB_ULong GetAllocFailedCount() const;

private:
  // private allocator only used once during initialization
  RTEMem_Allocator( SAPDB_ULong firstAlloc, 
                    SAPDB_ULong supplementAlloc,
                    SAPDB_ULong maxAlloc );

  // private allocator only used once during initialization
  RTEMem_Allocator( SAPDB_ULong firstAlloc, 
                    SAPDB_ULong supplementAlloc);

  static void Initialize( SAPDB_ULong firstAlloc,
                          SAPDB_ULong supplementAlloc,
                          SAPDB_ULong maxAlloc );

  static SAPDBMem_SynchronizedRawAllocator *m_Allocator;
  static RTEMem_Allocator                  *m_Instance;
  // Using a static reference would mean, that initialization function is called before main
  // This we have to prevent for the same reason we prevent static class instances
  // -> dynamic linked RunTime would not get initialized correctly on some OS...
  
#ifdef SAPDB_DEBUG_ALLOCATOR
  RTESync_NamedSpinlock m_Spinlock;
  SAPDB_ULong           m_BytesUsed;
  SAPDB_ULong           m_MaxBytesUsed;
  SAPDB_ULong           m_BytesControlled;
  SAPDB_ULong           m_CountAlloc;
  SAPDB_ULong           m_CountDealloc;
#endif
}; /*! endclass: RTEMem_Allocator */

#endif  /* RTEMEM_ALLOCATOR_HPP */
