/*
** (c) 1996-2000 The Regents of the University of California (through
** E.O. Lawrence Berkeley National Laboratory), subject to approval by
** the U.S. Department of Energy.  Your use of this software is under
** license -- the license agreement is attached and included in the
** directory as license.txt or you may contact Berkeley Lab's Technology
** Transfer Department at TTD@lbl.gov.  NOTICE OF U.S. GOVERNMENT RIGHTS.
** The Software was developed under funding from the U.S. Government
** which consequently retains certain rights as follows: the
** U.S. Government has been granted for itself and others acting on its
** behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
** Software to reproduce, prepare derivative works, and perform publicly
** and display publicly.  Beginning five (5) years after the date
** permission to assert copyright is obtained from the U.S. Department of
** Energy, and subject to any subsequent five (5) year renewals, the
** U.S. Government is granted for itself and others acting on its behalf
** a paid-up, nonexclusive, irrevocable, worldwide license in the
** Software to reproduce, prepare derivative works, distribute copies to
** the public, perform publicly and display publicly, and to permit
** others to do so.
*/

#ifndef BL_CARENA_H
#define BL_CARENA_H

#include <winstd.H>
#include <cstddef>
#include <set>
#include <vector>

#include <Arena.H>
#include <Array.H>

//
//@Man:
//@Memo: A Concrete Class for Dynamic Memory Management
/*@Doc:

  This is a coalescing memory manager.  It allocates (possibly) large
  chunks of heap space and apportions it out as requested.  It merges
  together neighboring chunks on each free().
*/

class CArena
    :
    public Arena
{
public:

    /*@ManDoc: Construct a coalescing memory manager.  `hunk\_size' is the
               minimum size of hunks of memory to allocate from the heap.
               If hunk\_size == 0 we use DefaultHunkSize as specified below.
    */
    CArena (size_t hunk_size = 0);
    //
    //@ManDoc: The destructor.
    //
    virtual ~CArena ();
    //
    //@ManDoc: Allocate some memory.
    //
    virtual void* alloc (size_t nbytes);

    /*@ManDoc: Free up allocated memory.  Merge neighboring free memory chunks
               into largest possible chunk.
    */
    virtual void free (void* ap);
    //
    //@ManDoc: The current amount of heap space used by the CArena object.
    //
    size_t heap_space_used () const;
    //
    //@ManDoc: The default memory hunk size to grab from the heap.
    //
    enum { DefaultHunkSize = 1024*1024 };

protected:
    //
    // The nodes in our free list and block list.
    //
    class Node
    {
    public:
        //
        // The default constructor.
        //
        Node ()
            :
            m_block(0), m_size(0) {}
        //
        // Another constructor.
        //
        Node (void* block, size_t size)
            :
            m_block(block), m_size(size) {}
        //
        // The copy constructor.
        //
        Node (const Node& rhs)
            :
            m_block(rhs.m_block), m_size(rhs.m_size) {}
        //
        // The copy assignment constructor.
        //
        Node& operator= (const Node& rhs)
        {
            m_block = rhs.m_block;
            m_size  = rhs.m_size;
            return *this;
        }
        //
        // The "less-than" operator.
        //
        bool operator< (const Node& rhs) const
        {
            return m_block < rhs.m_block;
        }
        //
        // The equality operator. 
        //
        bool operator== (const Node& rhs) const
        {
            return m_block == rhs.m_block;
        }
        //
        // The block address.
        //
        void* block () const { return m_block; }
        //
        // Set block address.
        //
        void block (void* blk) { m_block = blk; }
        //
        // The size of the memory block.
        //
        size_t size () const { return m_size; }
        //
        // Set size.
        //
        void size (size_t sz) { m_size = sz; }

    private:
        //
        // The block of memory we reference.
        //
        void* m_block;
        //
        // The size of the block we represent.
        //
        size_t m_size;
    };
    //
    // The type of our freelist and blocklist.
    // We use a set sorted from lo to hi memory addresses.
    //
    typedef std::set<Node> NL;
    //
    // The list of blocks allocated via ::operator new().
    //
    std::vector<void*> m_alloc;
    //
    // The free list of allocated but not currently used blocks.
    // Maintained in lo to hi memory sorted order.
    //
    NL m_freelist;
    //
    // The list of busy blocks.
    // A block is either on the freelist or on the blocklist, but not on both.
    //
    NL m_busylist;
    //
    // The minimal size of hunks to request via ::operator new().
    //
    size_t m_hunk;
    //
    // The amount of heap space currently allocated.
    //
    size_t m_used;

private:
    //
    // Disallowed.
    //
    CArena (const CArena& rhs);
    CArena& operator= (const CArena& rhs);
};

//
// The Arena used by BaseFab code.
//
extern Arena* The_FAB_Arena;

#endif /*BL_CARENA_H*/
