summaryrefslogtreecommitdiff
path: root/build/Bonmin/include/coin/CoinAlloc.hpp
blob: 8f6b08c418083965306aaf84762d97ce102c338b (plain)
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
/* $Id: CoinAlloc.hpp 1438 2011-06-09 18:14:12Z stefan $ */
// 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