core/vnl/vnl_alloc.cxx
Go to the documentation of this file.
00001 // This is core/vnl/vnl_alloc.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 
00006 #include "vnl_alloc.h"
00007 
00008 #include <vcl_cstring.h>  // memcpy() lives here.
00009 #include <vcl_cstdlib.h>
00010 
00011 char*
00012 vnl_alloc::chunk_alloc(vcl_size_t size, int& nobjs)
00013 {
00014   char * result;
00015   vcl_size_t total_bytes = size * nobjs;
00016   vcl_size_t bytes_left = end_free - start_free;
00017 
00018   if (bytes_left >= total_bytes) {
00019     result = start_free;
00020     start_free += total_bytes;
00021     return result;
00022   }
00023   else if (bytes_left >= size) {
00024     nobjs = int(bytes_left/size);
00025     total_bytes = size * nobjs;
00026     result = start_free;
00027     start_free += total_bytes;
00028     return result;
00029   }
00030   else
00031   {
00032     vcl_size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
00033     // Try to make use of the left-over piece.
00034     if (bytes_left > 0) {
00035       obj *  * my_free_list =
00036         free_list + FREELIST_INDEX(bytes_left);
00037       ((obj *)start_free) -> free_list_link = *my_free_list;
00038       *my_free_list = (obj *)start_free;
00039     }
00040     start_free = (char*)vcl_malloc(bytes_to_get);
00041     if (0 == start_free)
00042     {
00043       obj *  * my_free_list, *p;
00044       // Try to make do with what we have.  That can't
00045       // hurt.  We do not try smaller requests, since that tends
00046       // to result in disaster on multi-process machines.
00047       for (vcl_size_t i = size; i <= VNL_ALLOC_MAX_BYTES; i += VNL_ALLOC_ALIGN)
00048       {
00049         my_free_list = free_list + FREELIST_INDEX(i);
00050         p = *my_free_list;
00051         if (0 != p) {
00052           *my_free_list = p -> free_list_link;
00053           start_free = (char *)p;
00054           end_free = start_free + i;
00055           return chunk_alloc(size, nobjs);
00056           // Any leftover piece will eventually make it to the
00057           // right free vcl_list.
00058         }
00059       }
00060       start_free = (char*)vcl_malloc(bytes_to_get);
00061       // This should either throw an
00062       // exception or remedy the situation.  Thus we assume it
00063       // succeeded.
00064     }
00065     heap_size += bytes_to_get;
00066     end_free = start_free + bytes_to_get;
00067     return chunk_alloc(size, nobjs);
00068   }
00069 }
00070 
00071 
00072 /* Returns an object of size n, and optionally adds to size n free vcl_list.*/
00073 /* We assume that n is properly aligned.                                */
00074 /* We hold the allocation lock.                                         */
00075 void* vnl_alloc::refill(vcl_size_t n)
00076 {
00077   int nobjs = 20;
00078   char * chunk = chunk_alloc(n, nobjs);
00079   obj *  * my_free_list;
00080   obj * result;
00081   obj * current_obj, * next_obj;
00082   int i;
00083 
00084   if (1 == nobjs) return chunk;
00085   my_free_list = free_list + FREELIST_INDEX(n);
00086 
00087   /* Build free vcl_list in chunk */
00088   result = (obj *)chunk;
00089   *my_free_list = next_obj = (obj *)(chunk + n);
00090   for (i = 1; ; i++) {
00091     current_obj = next_obj;
00092     next_obj = (obj *)((char *)next_obj + n);
00093     if (nobjs - 1 == i) {
00094       current_obj -> free_list_link = 0;
00095       break;
00096     }
00097     else {
00098       current_obj -> free_list_link = next_obj;
00099     }
00100   }
00101   return result;
00102 }
00103 
00104 void*
00105 vnl_alloc::reallocate(void *p,
00106                       vcl_size_t old_sz,
00107                       vcl_size_t new_sz)
00108 {
00109   void * result;
00110   vcl_size_t copy_sz;
00111 
00112   if (old_sz > VNL_ALLOC_MAX_BYTES && new_sz > VNL_ALLOC_MAX_BYTES) {
00113     return vcl_realloc(p, new_sz);
00114   }
00115   if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return p;
00116   result = allocate(new_sz);
00117   copy_sz = new_sz > old_sz? old_sz : new_sz;
00118   vcl_memcpy(result, p, copy_sz);
00119   deallocate(p, old_sz);
00120   return result;
00121 }
00122 
00123 char *vnl_alloc::start_free = 0;
00124 char *vnl_alloc::end_free = 0;
00125 vcl_size_t vnl_alloc::heap_size = 0;
00126 
00127 vnl_alloc::obj *
00128 vnl_alloc::free_list[VNL_ALLOC_NFREELISTS] =
00129 {
00130   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00131   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00132 };
00133 // The 32 zeros are necessary to make version 4.1 of the SunPro
00134 // compiler happy.  Otherwise it appears to allocate too little
00135 // space for the array.
00136 
00137 #ifdef TEST
00138 #include <vcl_iostream.h>
00139 int main()
00140 {
00141   char* p = (char*)vnl_alloc::allocate(10);
00142   vcl_strcpy(p, "fred\n");
00143   vcl_cerr << p << '\n';
00144   vnl_alloc::deallocate(p,10);
00145 }
00146 
00147 #endif // TEST