/*++

Copyright (C) 1998-1999 Microsoft Corporation

Module Name:

   NEWNEW.H

Abstract:

   CReuseMemoryManager

History:

--*/

#ifndef __WBEM_NEW_NEW__H_
#define __WBEM_NEW_NEW__H_

#include "esscpol.h"
#include <stack>

class ESSCLI_POLARITY CReuseMemoryManager
{
protected:
    CCritSec m_cs;
    CFlexQueue m_Available;
    int m_nSize;
    int m_nMaxQueued;
public:
    CReuseMemoryManager(size_t nSize, size_t nMaxQueued = 0 )
      : m_nSize(nSize)
    {
        m_nMaxQueued = nMaxQueued == 0 ? 256 : nMaxQueued;
    }

    ~CReuseMemoryManager()
    {
        Clear();
    }

    void* Allocate()
    {
        CInCritSec ics(&m_cs);

        if(m_Available.GetQueueSize() == 0)
        {
            return new BYTE[m_nSize];
        }
        else
        {
            void* p = m_Available.Unqueue();
            return p;
        }
    }
    
    void Free(void* p)
    {
        CInCritSec ics(&m_cs);

        if ( m_Available.GetQueueSize() < m_nMaxQueued )
        {
            m_Available.Enqueue(p);
        }
        else
        {
            delete [] (BYTE*)p;
        }
    }
        
    void Clear()
    {
        CInCritSec ics(&m_cs);

        while(m_Available.GetQueueSize())
        {
            delete [] (BYTE*)m_Available.Unqueue();
        }
    }
};

#define DWORD_ALIGNED(x)    (((x) + 3) & ~3)
#define QWORD_ALIGNED(x)    (((x) + 7) & ~7)

#ifdef _WIN64
#define DEF_ALIGNED         QWORD_ALIGNED
#else
#define DEF_ALIGNED         DWORD_ALIGNED
#endif

class ESSCLI_POLARITY CTempMemoryManager
{
protected:
    CCritSec m_cs;
    
    class CAllocation
    {
    private:
        size_t m_dwAllocationSize;
        size_t m_dwUsed;
        size_t m_dwFirstFree;

        static inline size_t GetHeaderSize() {return sizeof(CAllocation);}
        inline byte* GetStart() {return ((byte*)this) + GetHeaderSize();}
        inline byte* GetEnd() {return ((byte*)this) + m_dwAllocationSize;}

    public:
        size_t GetAllocationSize() {return m_dwAllocationSize;}
        size_t GetUsedSize() {return m_dwUsed;}
        static size_t GetMinAllocationSize(size_t dwBlock)
            {return dwBlock + GetHeaderSize();}

        void Init(size_t dwAllocationSize);
        void* Alloc(size_t nBlockSize);
        bool Contains(void* p);
        bool Free(size_t nBlockSize);
        void Destroy();
    };

    CPointerArray<CAllocation>* m_pAllocations;
    DWORD m_dwTotalUsed;
    DWORD m_dwTotalAllocated;
    DWORD m_dwNumAllocations;
    DWORD m_dwNumMisses;

protected:
    inline size_t RoundUp(size_t nSize) {return DEF_ALIGNED(nSize);}

public:
    CTempMemoryManager();
    ~CTempMemoryManager();

    void* Allocate(size_t nBlockSize);
    void Free(void* p, size_t nBlockSize);
    void Clear();
};

#define MAX_ALLOCA_USE 100

template <class TArg>
class CTempArray
{
protected:
    BYTE* m_a;
    BOOL m_bStack;
    int m_nByteSize;

    TArg* GetArray() {return (TArg*)m_a;}
    const TArg* GetArray() const {return (const TArg*)m_a;}
public:
    inline CTempArray() : m_a(NULL), m_bStack(TRUE), m_nByteSize(0){}

    inline ~CTempArray()
    {
        if(!m_bStack)
            delete [] m_a;
    }

    operator TArg*() {return (TArg*)m_a;}
    operator const TArg*() const {return (const TArg*)m_a;}

    TArg& operator[](int nIndex) {return GetArray()[nIndex];}
    const TArg& operator[](int nIndex) const {return GetArray()[nIndex];}
    TArg& operator[](long lIndex) {return GetArray()[lIndex];}
    const TArg& operator[](long lIndex) const {return GetArray()[lIndex];}

    void SetMem(void* p) {m_a = (BYTE*)p;}
    BOOL SetSize(int nSize)
    {
        m_nByteSize = nSize * sizeof(TArg);
        if(m_nByteSize < MAX_ALLOCA_USE)
        {
            m_bStack = TRUE;
            return TRUE;
        }
        else
        {
            m_bStack = FALSE;
            return FALSE;
        }
    }
    int GetByteSize() {return m_nByteSize;}
    BOOL IsNull() {return (m_a == NULL);}
};

    
// This macro initializes the CTempArray with a given size.  First it "sets" the
// size into the array, which returns TRUE if _alloca can be used.  If so, it
// uses alloca on the now-computed byte size of the array.

#define INIT_TEMP_ARRAY(ARRAY, SIZE) \
        ((ARRAY.SetMem(                         \
            (ARRAY.SetSize(SIZE)) ?             \
                _alloca(ARRAY.GetByteSize()) :  \
                new BYTE[ARRAY.GetByteSize()]   \
                     )                          \
        ), !ARRAY.IsNull())                     \

    

        

    
#endif