CoinAlloc.hpp 5.02 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
/* $Id$ */
// Copyright (C) 2007, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#ifndef CoinAlloc_hpp
#define CoinAlloc_hpp

#include "CoinUtilsConfig.h"
#include <cstdlib>

#if !defined(COINUTILS_MEMPOOL_MAXPOOLED)
#define COINUTILS_MEMPOOL_MAXPOOLED -1
#endif

#if (COINUTILS_MEMPOOL_MAXPOOLED >= 0)

#ifndef COINUTILS_MEMPOOL_ALIGNMENT
#define COINUTILS_MEMPOOL_ALIGNMENT 16
#endif

/* Note:
   This memory pool implementation assumes that sizeof(size_t) and
   sizeof(void*) are both <= COINUTILS_MEMPOOL_ALIGNMENT.
   Choosing an alignment of 4 will cause segfault on 64-bit platforms and may
   lead to bad performance on 32-bit platforms. So 8 is a mnimum recommended
   alignment. Probably 16 does not waste too much space either and may be even
   better for performance. One must play with it.
*/

//#############################################################################

#if (COINUTILS_MEMPOOL_ALIGNMENT == 16)
static const std::size_t CoinAllocPtrShift = 4;
static const std::size_t CoinAllocRoundMask = ~((std::size_t)15);
#elif (COINUTILS_MEMPOOL_ALIGNMENT == 8)
static const std::size_t CoinAllocPtrShift = 3;
static const std::size_t CoinAllocRoundMask = ~((std::size_t)7);
#else
#error "COINUTILS_MEMPOOL_ALIGNMENT must be defined as 8 or 16 (or this code needs to be changed :-)"
#endif

//#############################################################################

#ifndef COIN_MEMPOOL_SAVE_BLOCKHEADS
#define COIN_MEMPOOL_SAVE_BLOCKHEADS 0
#endif

//#############################################################################

class CoinMempool {
private:
#if (COIN_MEMPOOL_SAVE_BLOCKHEADS == 1)
  char **block_heads;
  std::size_t block_num;
  std::size_t max_block_num;
#endif
#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
  pthread_mutex_t mutex_;
#endif
  int last_block_size_;
  char *first_free_;
  const std::size_t entry_size_;

private:
  CoinMempool(const CoinMempool &);
  CoinMempool &operator=(const CoinMempool &);

private:
  char *allocate_new_block();
  inline void lock_mutex()
  {
#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
    pthread_mutex_lock(&mutex_);
#endif
  }
  inline void unlock_mutex()
  {
#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
    pthread_mutex_unlock(&mutex_);
#endif
  }

public:
  CoinMempool(std::size_t size = 0);
  ~CoinMempool();

  char *alloc();
  inline void dealloc(char *p)
  {
    char **pp = (char **)p;
    lock_mutex();
    *pp = first_free_;
    first_free_ = p;
    unlock_mutex();
  }
};

//#############################################################################

/** A memory pool allocator.

    If a request arrives for allocating \c n bytes then it is first
    rounded up to the nearest multiple of \c sizeof(void*) (this is \c
    n_roundup), then one more \c sizeof(void*) is added to this
    number. If the result is no more than maxpooled_ then
    the appropriate pool is used to get a chunk of memory, if not,
    then malloc is used. In either case, the size of the allocated
    chunk is written into the first \c sizeof(void*) bytes and a
    pointer pointing afterwards is returned.
*/

class CoinAlloc {
private:
  CoinMempool *pool_;
  int maxpooled_;

public:
  CoinAlloc();
  ~CoinAlloc() {}

  inline void *alloc(const std::size_t n)
  {
    if (maxpooled_ <= 0) {
      return std::malloc(n);
    }
    char *p = NULL;
    const std::size_t to_alloc = ((n + COINUTILS_MEMPOOL_ALIGNMENT - 1) & CoinAllocRoundMask) + COINUTILS_MEMPOOL_ALIGNMENT;
    CoinMempool *pool = NULL;
    if (maxpooled_ > 0 && to_alloc >= (size_t)maxpooled_) {
      p = static_cast< char * >(std::malloc(to_alloc));
      if (p == NULL)
        throw std::bad_alloc();
    } else {
      pool = pool_ + (to_alloc >> CoinAllocPtrShift);
      p = pool->alloc();
    }
    *((CoinMempool **)p) = pool;
    return static_cast< void * >(p + COINUTILS_MEMPOOL_ALIGNMENT);
  }

  inline void dealloc(void *p)
  {
    if (maxpooled_ <= 0) {
      std::free(p);
      return;
    }
    if (p) {
      char *base = static_cast< char * >(p) - COINUTILS_MEMPOOL_ALIGNMENT;
      CoinMempool *pool = *((CoinMempool **)base);
      if (!pool) {
        std::free(base);
      } else {
        pool->dealloc(base);
      }
    }
  }
};

extern CoinAlloc CoinAllocator;

//#############################################################################

#if defined(COINUTILS_MEMPOOL_OVERRIDE_NEW) && (COINUTILS_MEMPOOL_OVERRIDE_NEW == 1)
void *operator new(std::size_t size) throw(std::bad_alloc);
void *operator new[](std::size_t) throw(std::bad_alloc);
void operator delete(void *)throw();
void operator delete[](void *) throw();
void *operator new(std::size_t, const std::nothrow_t &) throw();
void *operator new[](std::size_t, const std::nothrow_t &) throw();
void operator delete(void *, const std::nothrow_t &)throw();
void operator delete[](void *, const std::nothrow_t &) throw();
#endif

#endif /*(COINUTILS_MEMPOOL_MAXPOOLED >= 0)*/
#endif

/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
*/