//=========================================================
//  MusE
//  Linux Music Editor
//  $Id: memory.h,v 1.4 2004/06/07 21:46:08 wschweer Exp $
//
//  (C) Copyright 2003-2004 Werner Schweer (ws@seh.de)
//=========================================================

#ifndef __MEMORY_H__
#define __MEMORY_H__

#include <stdio.h>
#include <map>

// most of the following code is based on examples
// from Bjarne Stroustrup: "Die C++ Programmiersprache"

//---------------------------------------------------------
//   Pool
//---------------------------------------------------------

class Pool {
      struct Verweis {
            Verweis* next;
            };
      struct Chunk {
            enum { size = 4 * 1024 };
            Chunk* next;
            char mem[size];
            };
//      enum { dimension = 11 };
      enum { dimension = 21 };      // increased for 64 bit architectures
      Chunk* chunks[dimension];
      Verweis* head[dimension];
      Pool(Pool&);
      void operator=(Pool&);
      void grow(int idx);

   public:
      Pool();
      ~Pool();
      void* alloc(size_t n);
      void free(void* b, size_t n);
      };

//---------------------------------------------------------
//   alloc
//---------------------------------------------------------

inline void* Pool::alloc(size_t n)
      {
      int idx = ((n + sizeof(int) - 1) / sizeof(int)) - 1;
      if (idx >= dimension) {
            printf("panic: alloc %d\n", n);
            exit(-1);
            }
      if (head[idx] == 0)
            grow(idx);
      Verweis* p = head[idx];
      head[idx] = p->next;
      return p;
      }

//---------------------------------------------------------
//   free
//---------------------------------------------------------

inline void Pool::free(void* b, size_t n)
      {
      int idx = ((n + sizeof(int) - 1) / sizeof(int)) - 1;
      if (idx >= dimension) {
            printf("panic: alloc %d\n", n);
            exit(-1);
            }
      Verweis* p = static_cast<Verweis*>(b);
      p->next = head[idx];
      head[idx] = p;
      }

extern Pool audioRTmemoryPool;
extern Pool midiRTmemoryPool;

//---------------------------------------------------------
//   audioRTalloc
//---------------------------------------------------------

template <class T> class audioRTalloc
      {
   public:
      typedef T         value_type;
      typedef size_t    size_type;
      typedef ptrdiff_t difference_type;

      typedef T*        pointer;
      typedef const T*  const_pointer;

      typedef T&        reference;
      typedef const T&  const_reference;

      pointer address(reference x) const { return &x; }
      const_pointer address(const_reference x) const { return &x; }

      audioRTalloc();
      template <class U> audioRTalloc(const audioRTalloc<U>&) {}
      ~audioRTalloc() {}

      pointer allocate(size_type n, void * = 0) {
            return static_cast<T*>(audioRTmemoryPool.alloc(n * sizeof(T)));
            }
      void deallocate(pointer p, size_type n) {
            audioRTmemoryPool.free(p, n * sizeof(T));
            }

      audioRTalloc<T>&  operator=(const audioRTalloc&) { return *this; }
      void construct(pointer p, const T& val) {
            new ((T*) p) T(val);
            }
      void destroy(pointer p) {
            p->~T();
            }
      size_type max_size() const { return size_t(-1); }

      template <class U> struct rebind { typedef audioRTalloc<U> other; };
      template <class U> audioRTalloc& operator=(const audioRTalloc<U>&) { return *this; }
      };

template <class T> audioRTalloc<T>::audioRTalloc() {}

//---------------------------------------------------------
//   midiRTalloc
//---------------------------------------------------------

template <class T> class midiRTalloc
      {
   public:
      typedef T         value_type;
      typedef size_t    size_type;
      typedef ptrdiff_t difference_type;

      typedef T*        pointer;
      typedef const T*  const_pointer;

      typedef T&        reference;
      typedef const T&  const_reference;

      pointer address(reference x) const { return &x; }
      const_pointer address(const_reference x) const { return &x; }

      midiRTalloc();
      template <class U> midiRTalloc(const midiRTalloc<U>&) {}
      ~midiRTalloc() {}

      pointer allocate(size_type n, void * = 0) {
            return static_cast<T*>(midiRTmemoryPool.alloc(n * sizeof(T)));
            }
      void deallocate(pointer p, size_type n) {
            midiRTmemoryPool.free(p, n * sizeof(T));
            }

      midiRTalloc<T>&  operator=(const midiRTalloc&) { return *this; }
      void construct(pointer p, const T& val) {
            new ((T*) p) T(val);
            }
      void destroy(pointer p) {
            p->~T();
            }
      size_type max_size() const { return size_t(-1); }

      template <class U> struct rebind { typedef midiRTalloc<U> other; };
      template <class U> midiRTalloc& operator=(const midiRTalloc<U>&) { return *this; }
      };

template <class T> midiRTalloc<T>::midiRTalloc() {}

#endif

