// // Copyright (C) 2000-2002 Andrey Slepuhin // // libp++ is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // libp++ is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with libp++; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // $Source$ // $Revision$ // $Date$ // Author: Andrey Slepuhin #ifndef __pxx_chunk_allocator_ih__ #define __pxx_chunk_allocator_ih__ #include "pxx_chunk_allocator.hh" #include "pxx_chunk_allocator_block_header.ih" #include "pxx_default_allocator.hh" #include "pxx_common.ih" namespace pxx { template inline void ChunkAllocator::FreeList::remove () { prev->next = next; next->prev = prev; } template inline ChunkAllocator::ChunkAllocator ( Allocator& _allocator /* = default_allocator */ ) : allocator (_allocator), block_list (&block_list, &block_list), chunk_size (size_align(sizeof(type_t), sizeof(FreeList))), block_size (0), nchunks (chunks_in_block), root (null) { free_list.prev = free_list.next = &free_list; } template inline ChunkAllocator::ChunkAllocator ( size_t _nchunks, Allocator& _allocator /* = default_allocator */ ) : allocator (_allocator), block_list (&block_list, &block_list), chunk_size (size_align(sizeof(type_t), sizeof(FreeList))), block_size (0), nchunks (_nchunks), root (null) { free_list.prev = free_list.next = &free_list; } template inline void ChunkAllocator::init () { block_size = allocator.get_real_size(nchunks * chunk_size + sizeof(CABlockHeader)); nchunks = (block_size - sizeof(CABlockHeader))/chunk_size; } template inline ChunkAllocator::~ChunkAllocator () { if (&allocator == &default_allocator && default_allocator_destroyed) return; CABlockHeader* p = block_list.next; while (p != &block_list) { void* q = p; p = p->next; allocator.deallocate(q); } } template inline type_t* ChunkAllocator::allocate () { if (block_size == 0) init(); FreeList* p = free_list.next; if (p != &free_list) { p->remove(); CABlockHeader* b = get_block(p); (b->ref_count)++; return (type_t*)p; } else { CABlockHeader* p = (CABlockHeader*)allocator.allocate(block_size); //printf("Allocated block at %p\n", p); init_block(p); return ChunkAllocator::allocate(); } } template inline void ChunkAllocator::deallocate (type_t* _ptr) { if (block_size == 0) init(); FreeList* p = (FreeList* )_ptr; p->prev = free_list.prev; p->next = &free_list; free_list.prev = free_list.prev->next = p ; CABlockHeader* b = get_block(_ptr); if (--(b->ref_count) != 0) return; else return free_block(b); } template inline void ChunkAllocator::free_block (CABlockHeader* _ptr) { FreeList* p = (FreeList*)ptr_add_offset(_ptr, sizeof(CABlockHeader)); FreeList* q = (FreeList*)ptr_add_offset(p, nchunks * chunk_size); while (p < q) { p->remove(); p = (FreeList*)ptr_add_offset(p, chunk_size); } //printf("Deallocating block at %p\n", b); _ptr->remove(); if ((allocator.get_features() & ALLOCATOR_HAS_GET_BLOCK_WITH_SIZE) == 0) { root = root->node_remove(_ptr); } allocator.deallocate(_ptr); } template inline CABlockHeader* ChunkAllocator::get_block (void* _ptr) { if ((allocator.get_features() & ALLOCATOR_HAS_GET_BLOCK_WITH_SIZE) != 0) { return (CABlockHeader*)(allocator.get_block(_ptr, block_size)); } else { CABlockHeader* node = root; do { if (_ptr < node) { node = node->left; } else { if (_ptr < ptr_add_offset(node, block_size)) return node; else node = node->right; } } while (node != null); return null; } } template void ChunkAllocator::init_block (CABlockHeader* _ptr) { _ptr->prev = block_list.prev; _ptr->next = &block_list; block_list.prev = block_list.prev->next = _ptr ; _ptr->ref_count = 0; FreeList* p = (FreeList*)ptr_add_offset(_ptr, sizeof(CABlockHeader)); FreeList* q = (FreeList*)ptr_add_offset(p, (nchunks - 1) * chunk_size); p->prev = &free_list; free_list.next = p; while (p < q) { FreeList* next = (FreeList*)ptr_add_offset(p, chunk_size); p->next = next; next->prev = p; p = next; } p->next = &free_list; free_list.prev = p; if ((allocator.get_features() & ALLOCATOR_HAS_GET_BLOCK_WITH_SIZE) == 0) { _ptr->left = _ptr->right = null; _ptr->balance = 0; if (root == null) root = _ptr; else root = root->node_insert(_ptr); } } } #endif // __pxx_chunk_allocator_ih__