dlib C++ Library - memory_manager_kernel_3.h

// Copyright (C) 2004 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_MEMORY_MANAGER_KERNEl_3_
#define DLIB_MEMORY_MANAGER_KERNEl_3_
#include "../algs.h"
#include "memory_manager_kernel_abstract.h"
#include "../assert.h"
#include <new>
#include "memory_manager_kernel_2.h"
#include "../binary_search_tree/binary_search_tree_kernel_2.h"
namespace dlib
{
 template <
 typename T,
 size_t chunk_size
 >
 class memory_manager_kernel_3
 {
 /*! 
 INITIAL VALUE
 allocations == 0
 next == 0
 first_chunk == 0
 bst_of_arrays == 0
 REQUIREMENTS ON chunk_size
 chunk_size is the number of items of type T we will allocate at a time. so
 it must be > 0.
 CONVENTION
 This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T)
 bytes. All the sizeof(T) subblocks are kept in a linked list of free memory blocks
 and are given out whenever an allocation request occurs. Also, memory is not freed
 until this object is destructed. 
 
 allocations == get_number_of_allocations()
 - if (next != 0) then
 - next == the next pointer to return from allocate()
 and next == pointer to the first node in a linked list. each node
 is one item in the memory pool. 
 - the last node in the linked list has next set to 0
 - else
 - we need to call new to get the next pointer to return from allocate()
 - if (arrays != 0) then
 - someone has called allocate_array()
 - (*arrays)[size] == an array of size bytes of memory 
 - if (first_chunk != 0) then
 - first_chunk == the first node in a linked list that contains pointers 
 to all the chunks we have ever allocated. The last link in the list
 has its next pointer set to 0.
 !*/
 union node
 {
 node* next;
 char item[sizeof(T)];
 };
 struct chunk_node
 {
 node* chunk;
 chunk_node* next;
 };
 typedef binary_search_tree_kernel_2<
 size_t,
 char*,
 memory_manager_kernel_2<char,5>
 > bst_of_arrays; 
 public:
 typedef T type;
 template <typename U>
 struct rebind {
 typedef memory_manager_kernel_3<U,chunk_size> other;
 };
 memory_manager_kernel_3(
 ) :
 allocations(0),
 next(0),
 first_chunk(0),
 arrays(0)
 {
 // You FOOL! You can't have a zero chunk_size.
 COMPILE_TIME_ASSERT(chunk_size > 0);
 }
 virtual ~memory_manager_kernel_3(
 )
 {
 if (allocations == 0)
 {
 while (first_chunk != 0)
 {
 chunk_node* temp = first_chunk;
 first_chunk = first_chunk->next;
 // delete the memory chunk 
 ::operator delete ( static_cast<void*>(temp->chunk));
 // delete the chunk_node
 delete temp;
 }
 }
 if (arrays)
 {
 arrays->reset();
 while (arrays->move_next())
 {
 ::operator delete (arrays->element().value());
 }
 delete arrays;
 }
 }
 size_t get_number_of_allocations (
 ) const { return allocations; }
 T* allocate_array (
 size_t size
 )
 {
 size_t block_size = sizeof(T)*size + sizeof(size_t)*2;
 // make sure we have initialized the arrays object.
 if (arrays == 0)
 {
 arrays = new bst_of_arrays;
 }
 char* temp;
 // see if we have a suitable block of memory already.
 arrays->position_enumerator(block_size);
 if (arrays->current_element_valid())
 {
 // we have a suitable block of memory already so use that one.
 arrays->remove_current_element(block_size,temp); 
 }
 else
 {
 temp = static_cast<char*>(::operator new(block_size));
 }
 reinterpret_cast<size_t*>(temp)[0] = block_size;
 reinterpret_cast<size_t*>(temp)[1] = size;
 temp += sizeof(size_t)*2;
 try
 {
 initialize_array(reinterpret_cast<T*>(temp),size);
 }
 catch (...)
 {
 // something was thrown while we were initializing the array so
 // stick our memory block into arrays and rethrow the exception
 temp -= sizeof(size_t)*2;
 arrays->add(block_size,temp);
 throw;
 }
 ++allocations;
 return reinterpret_cast<T*>(temp);
 }
 void deallocate_array (
 T* item
 )
 {
 char* temp = reinterpret_cast<char*>(item);
 temp -= sizeof(size_t)*2;
 size_t block_size = reinterpret_cast<size_t*>(temp)[0];
 size_t size = reinterpret_cast<size_t*>(temp)[1];
 deinitialize_array(item,size);
 arrays->add(block_size,temp);
 
 --allocations;
 }
 T* allocate (
 ) 
 { 
 T* temp;
 if (next != 0)
 {
 temp = reinterpret_cast<T*>(next);
 node* n = next->next;
 try
 {
 // construct this new T object with placement new.
 new (static_cast<void*>(temp))T();
 }
 catch (...)
 {
 next->next = n;
 throw;
 }
 next = n;
 }
 else
 {
 // the linked list is empty so we need to allocate some more memory
 node* block = static_cast<node*>(::operator new (sizeof(node)*chunk_size));
 // the first part of this block can be our new object
 temp = reinterpret_cast<T*>(block);
 try
 {
 // construct this new T object with placement new.
 new (static_cast<void*>(temp))T();
 }
 catch (...)
 {
 // construction of the new object threw so delete the block of memory
 ::operator delete ( static_cast<void*>(block));
 throw;
 }
 // allocate a new chunk_node
 chunk_node* chunk;
 try {chunk = new chunk_node; }
 catch (...) 
 { 
 temp->~T();
 ::operator delete ( static_cast<void*>(block));
 throw;
 }
 // add this block into the chunk list
 chunk->chunk = block;
 chunk->next = first_chunk;
 first_chunk = chunk;
 ++block;
 // now add the rest of the block into the linked list of free nodes.
 for (size_t i = 0; i < chunk_size-1; ++i)
 {
 block->next = next;
 next = block;
 ++block;
 }
 }
 ++allocations;
 return temp;
 }
 void deallocate (
 T* item
 ) 
 { 
 --allocations; 
 item->~T();
 // add this memory into our linked list.
 node* temp = reinterpret_cast<node*>(item);
 temp->next = next;
 next = temp; 
 }
 void swap (
 memory_manager_kernel_3& item
 ) 
 { 
 exchange(allocations,item.allocations); 
 exchange(next,item.next); 
 exchange(first_chunk,item.first_chunk);
 exchange(arrays,item.arrays);
 }
 private:
 // data members
 size_t allocations;
 node* next;
 chunk_node* first_chunk;
 bst_of_arrays* arrays;
 void initialize_array (
 T* array,
 size_t size
 ) const
 {
 size_t i;
 try
 {
 for (i = 0; i < size; ++i)
 {
 // construct this new T object with placement new.
 new (static_cast<void*>(array+i))T();
 }
 }
 catch (...)
 {
 // Catch any exceptions thrown during the construction process
 // and then destruct any T objects that actually were successfully
 // constructed.
 for (size_t j = 0; j < i; ++j)
 {
 array[i].~T();
 }
 throw;
 }
 }
 void deinitialize_array (
 T* array,
 size_t size
 ) const
 {
 for (size_t i = 0; i < size; ++i)
 {
 array[i].~T();
 }
 }
 // don't do any initialization for the built in types
 void initialize_array(unsigned char*, size_t) {} 
 void deinitialize_array(unsigned char*, size_t) {}
 void initialize_array(signed char*, size_t) {} 
 void deinitialize_array(signed char*, size_t) {}
 void initialize_array(char*, size_t) {} 
 void deinitialize_array(char*, size_t) {}
 void initialize_array(int*, size_t) {} 
 void deinitialize_array(int*, size_t) {}
 void initialize_array(unsigned int*, size_t) {} 
 void deinitialize_array(unsigned int*, size_t) {}
 void initialize_array(unsigned long*, size_t) {} 
 void deinitialize_array(unsigned long*, size_t) {}
 void initialize_array(long*, size_t) {} 
 void deinitialize_array(long*, size_t) {}
 void initialize_array(float*, size_t) {} 
 void deinitialize_array(float*, size_t) {}
 void initialize_array(double*, size_t) {} 
 void deinitialize_array(double*, size_t) {}
 void initialize_array(short*, size_t) {} 
 void deinitialize_array(short*, size_t) {}
 void initialize_array(unsigned short*, size_t) {} 
 void deinitialize_array(unsigned short*, size_t) {}
 // restricted functions
 memory_manager_kernel_3(memory_manager_kernel_3&); // copy constructor
 memory_manager_kernel_3& operator=(memory_manager_kernel_3&); // assignment operator
 };
 template <
 typename T,
 size_t chunk_size
 >
 inline void swap (
 memory_manager_kernel_3<T,chunk_size>& a, 
 memory_manager_kernel_3<T,chunk_size>& b 
 ) { a.swap(b); } 
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_MEMORY_MANAGER_KERNEl_3_

AltStyle によって変換されたページ (->オリジナル) /