// Copyright (C) 2007, International Business Machines // Corporation and others. All Rights Reserved. #ifndef CoinAlloc_hpp #define CoinAlloc_hpp #include "CoinUtilsConfig.h" #include #if !defined(COINUTILS_MEMPOOL_MAXPOOLED) # define COINUTILS_MEMPOOL_MAXPOOLED -1 #endif #if (COINUTILS_MEMPOOL_MAXPOOLED >= 0) #ifdef HAVE_STDLIB_H #include #endif #ifndef COINUTILS_MEMPOOL_ALIGNMENT #define COINUTILS_MEMPOOL_ALIGNMENT 8 #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(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(p+COINUTILS_MEMPOOL_ALIGNMENT); } inline void dealloc(void* p) { if (maxpooled_ <= 0) { std::free(p); return; } if (p) { char* base = static_cast(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