1/* $Id: CoinAlloc.hpp 1448 2011-06-19 15:34:41Z stefan $ */
2// Copyright (C) 2007, International Business Machines
3// Corporation and others. All Rights Reserved.
4// This code is licensed under the terms of the Eclipse Public License (EPL).
5
6#ifndef CoinAlloc_hpp
7#define CoinAlloc_hpp
8
9#include "CoinUtilsConfig.h"
10#include <cstdlib>
11
12#if !defined(COINUTILS_MEMPOOL_MAXPOOLED)
13# define COINUTILS_MEMPOOL_MAXPOOLED -1
14#endif
15
16#if (COINUTILS_MEMPOOL_MAXPOOLED >= 0)
17
18#ifndef COINUTILS_MEMPOOL_ALIGNMENT
19#define COINUTILS_MEMPOOL_ALIGNMENT 16
20#endif
21
22/* Note:
23 This memory pool implementation assumes that sizeof(size_t) and
24 sizeof(void*) are both <= COINUTILS_MEMPOOL_ALIGNMENT.
25 Choosing an alignment of 4 will cause segfault on 64-bit platforms and may
26 lead to bad performance on 32-bit platforms. So 8 is a mnimum recommended
27 alignment. Probably 16 does not waste too much space either and may be even
28 better for performance. One must play with it.
29*/
30
31//#############################################################################
32
33#if (COINUTILS_MEMPOOL_ALIGNMENT == 16)
34static const std::size_t CoinAllocPtrShift = 4;
35static const std::size_t CoinAllocRoundMask = ~((std::size_t)15);
36#elif (COINUTILS_MEMPOOL_ALIGNMENT == 8)
37static const std::size_t CoinAllocPtrShift = 3;
38static const std::size_t CoinAllocRoundMask = ~((std::size_t)7);
39#else
40#error "COINUTILS_MEMPOOL_ALIGNMENT must be defined as 8 or 16 (or this code needs to be changed :-)"
41#endif
42
43//#############################################################################
44
45#ifndef COIN_MEMPOOL_SAVE_BLOCKHEADS
46# define COIN_MEMPOOL_SAVE_BLOCKHEADS 0
47#endif
48
49//#############################################################################
50
51class CoinMempool
52{
53private:
54#if (COIN_MEMPOOL_SAVE_BLOCKHEADS == 1)
55 char** block_heads;
56 std::size_t block_num;
57 std::size_t max_block_num;
58#endif
59#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
60 pthread_mutex_t mutex_;
61#endif
62 int last_block_size_;
63 char* first_free_;
64 const std::size_t entry_size_;
65
66private:
67 CoinMempool(const CoinMempool&);
68 CoinMempool& operator=(const CoinMempool&);
69
70private:
71 char* allocate_new_block();
72 inline void lock_mutex() {
73#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
74 pthread_mutex_lock(&mutex_);
75#endif
76 }
77 inline void unlock_mutex() {
78#if defined(COINUTILS_PTHREADS) && (COINUTILS_PTHREAD == 1)
79 pthread_mutex_unlock(&mutex_);
80#endif
81 }
82
83public:
84 CoinMempool(std::size_t size = 0);
85 ~CoinMempool();
86
87 char* alloc();
88 inline void dealloc(char *p)
89 {
90 char** pp = (char**)p;
91 lock_mutex();
92 *pp = first_free_;
93 first_free_ = p;
94 unlock_mutex();
95 }
96};
97
98//#############################################################################
99
100/** A memory pool allocator.
101
102 If a request arrives for allocating \c n bytes then it is first
103 rounded up to the nearest multiple of \c sizeof(void*) (this is \c
104 n_roundup), then one more \c sizeof(void*) is added to this
105 number. If the result is no more than maxpooled_ then
106 the appropriate pool is used to get a chunk of memory, if not,
107 then malloc is used. In either case, the size of the allocated
108 chunk is written into the first \c sizeof(void*) bytes and a
109 pointer pointing afterwards is returned.
110*/
111
112class CoinAlloc
113{
114private:
115 CoinMempool* pool_;
116 int maxpooled_;
117public:
118 CoinAlloc();
119 ~CoinAlloc() {}
120
121 inline void* alloc(const std::size_t n)
122 {
123 if (maxpooled_ <= 0) {
124 return std::malloc(n);
125 }
126 char *p = NULL;
127 const std::size_t to_alloc =
128 ((n+COINUTILS_MEMPOOL_ALIGNMENT-1) & CoinAllocRoundMask) +
129 COINUTILS_MEMPOOL_ALIGNMENT;
130 CoinMempool* pool = NULL;
131 if (maxpooled_ > 0 && to_alloc >= (size_t)maxpooled_) {
132 p = static_cast<char*>(std::malloc(to_alloc));
133 if (p == NULL) throw std::bad_alloc();
134 } else {
135 pool = pool_ + (to_alloc >> CoinAllocPtrShift);
136 p = pool->alloc();
137 }
138 *((CoinMempool**)p) = pool;
139 return static_cast<void*>(p+COINUTILS_MEMPOOL_ALIGNMENT);
140 }
141
142 inline void dealloc(void* p)
143 {
144 if (maxpooled_ <= 0) {
145 std::free(p);
146 return;
147 }
148 if (p) {
149 char* base = static_cast<char*>(p)-COINUTILS_MEMPOOL_ALIGNMENT;
150 CoinMempool* pool = *((CoinMempool**)base);
151 if (!pool) {
152 std::free(base);
153 } else {
154 pool->dealloc(base);
155 }
156 }
157 }
158};
159
160extern CoinAlloc CoinAllocator;
161
162//#############################################################################
163
164#if defined(COINUTILS_MEMPOOL_OVERRIDE_NEW) && (COINUTILS_MEMPOOL_OVERRIDE_NEW == 1)
165void* operator new(std::size_t size) throw (std::bad_alloc);
166void* operator new[](std::size_t) throw (std::bad_alloc);
167void operator delete(void*) throw();
168void operator delete[](void*) throw();
169void* operator new(std::size_t, const std::nothrow_t&) throw();
170void* operator new[](std::size_t, const std::nothrow_t&) throw();
171void operator delete(void*, const std::nothrow_t&) throw();
172void operator delete[](void*, const std::nothrow_t&) throw();
173#endif
174
175#endif /*(COINUTILS_MEMPOOL_MAXPOOLED >= 0)*/
176#endif
177