基本是书上原有代码
#ifndef _STL_ALLOC_H
#define _STL_ALLOC_H
#ifndef _BAD_ALLOC
#include <iostream>
#define _BAD_ALLOC std::cerr<<"Out of memory"<<std::endl; exit(1)
#endif // !_BAD_ALLOC
enum { __ALIGN = 8 }; //小区块为8的倍数
enum { __MAX_BYTES = 128 }; //区域最大为128
enum { __NFREELISTS = 16 }; //自由链表个数
template<int inst>
class __malloc_alloc_template
{
private:
static void *oom_malloc(size_t n);
static void *oom_realloc(void *p, size_t old_sz, size_t new_sz);
static void(*oom_handler)();
public:
static void *allocate(size_t n);
static void *reallocate(void *p, size_t old_sz, size_t new_sz);
static void dellocate(void *p, size_t n);
static void set_handler(void(*f)());
};
template<int inst>
void *__malloc_alloc_template<inst>::allocate(size_t n)
{
void *result = malloc(n);
if (!result)
result = oom_malloc(n);
return result;
}
template<int inst>
void *__malloc_alloc_template<inst>::reallocate(void *p, size_t old_sz, size_t new_sz)
{
void *result = realloc(p, new_sz);
if (!result)
oom_realloc(p, old_sz, new_sz);
return result;
}
template<int inst>
void __malloc_alloc_template<inst>::dellocate(void *p, size_t n)
{
free(p);
}
template<int inst>
void(*__malloc_alloc_template<inst>::oom_handler)() = 0;
template<int inst>
void __malloc_alloc_template<inst>::set_handler(void(*f)())
{
oom_handler = f;
}
template<int inst>
void *__malloc_alloc_template<inst>::oom_malloc(size_t n)
{
void *result;
while (1)
{
if (0 == oom_handler) { _BAD_ALLOC; }
(*oom_handler)();
if (result = malloc(n))
return result;
}
}
template<int inst>
void *__malloc_alloc_template<inst>::oom_realloc(void *p, size_t pld_sz, size_t new_sz)
{
void *result;
while (1)
{
if (0 == oom_handler) { _BAD_ALLOC; }
(*oom_handler)();
if (result = realloc(p, new_sz))
return result;
}
}
/*********************************************************************/
typedef __malloc_alloc_template<0> malloc_alloc;
/*********************************************************************/
template <int inst>
class __default_alloc_template
{
private:
union obj
{
union obj * free_list_link;
char client_data[1];
};
private:
static char *start_free; //内存池起始位置
static char *end_free; //内存池结束位置
static size_t heap_size; //内存池大小
//自由链表数
static obj *volatile free_list[__NFREELISTS];
//返回一个大小为n的区块 并且可能向freelist添加几个大小n的区域
static void *refill(size_t n);
//配置一块区域 可以容纳nobjs个大小为n的区域 无法容纳 nodjs可能变低
static char *chunk_alloc(size_t size, int &nobjs);
private:
static size_t ROUND_UP(size_t bytes)
{
return ((bytes + __ALIGN - 1) & ~(__ALIGN - 1));
}
//根据bytes决定链表序号
static size_t FREELIST_INDEX(size_t bytes)
{
return ((bytes + __ALIGN - 1) / __ALIGN - 1);
}
public:
static void *allocate(size_t n);
static void dellocate(void *p, size_t n);
static void *reallocate(void *p, size_t old_sz, size_t new_sz);
};
template <int inst>
typename __default_alloc_template<inst>::obj
*volatile __default_alloc_template<inst>::free_list[__NFREELISTS] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
template <int inst>
char *__default_alloc_template<inst>::start_free = 0;
template <int inst>
char *__default_alloc_template<inst>::end_free = 0;
template <int inst>
size_t __default_alloc_template<inst>::heap_size = 0;
template <int inst>
void *__default_alloc_template<inst>::allocate(size_t n)
{
obj *volatile* my_free_list;
obj *result;
if (n > (size_t)__MAX_BYTES)
return malloc_alloc::allocate(n);
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;
if (!result)
return refill(ROUND_UP(n));
*my_free_list = result->free_list_link;
return result;
}
template <int inst>
void __default_alloc_template<inst>::dellocate(void *p, size_t n)
{
obj *volatile *my_free_list;
if (n > __MAX_BYTES)
malloc_alloc::dellocate(p, n);
else
{
my_free_list = free_list + FREELIST_INDEX(n);
((obj*)p)->free_list_link = *my_free_list;
*my_free_list = (obj*)p;
}
}
template <int inst>
void *__default_alloc_template<inst>::reallocate(void *p, size_t old_sz, size_t new_sz)
{
size_t copy_sz;
void *result;
if (old_sz > (size_t)__MAX_BYTES && new_sz > (size_t)__MAX_BYTES)
return realloc(p, new_sz);
if (ROUND_UP(old_sz) == ROUND_UP(new_sz))
return p;
result = allocate(new_sz);
copy_sz = old_sz < new_sz ? old_sz : new_sz;
memcpy(result, p, copy_sz);
dellocate(p, old_sz);
return result;
}
template <int inst>
void *__default_alloc_template<inst>::refill(size_t n)
{
obj *volatile *my_free_list;
int nobjs = 20;
my_free_list = free_list + FREELIST_INDEX(n);
char *buffer = chunk_alloc(n, nobjs);
for (int i = 1; i < nobjs; ++i)
{
((obj*)(buffer + n*i))->free_list_link = *my_free_list;
*my_free_list = (obj*)(buffer + n*i);
}
return buffer;
}
template <int inst>
char *__default_alloc_template<inst>::chunk_alloc(size_t size, int &nobjs)
{
size_t total_bytes = size * nobjs;
size_t bytes_left = end_free - start_free;
char *result;
if (bytes_left >= total_bytes)
{
result = start_free;
start_free += total_bytes;
return result;
}
else if (bytes_left >= size)
{
nobjs = bytes_left / size;
result = start_free;
start_free += (nobjs * size);
return result;
}
else
{
size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
if (bytes_left > 0)
{
obj *volatile *my_free_list = free_list + FREELIST_INDEX(bytes_left);
((obj*)start_free)->free_list_link = *my_free_list;
*my_free_list = (obj*)start_free;
}
start_free = (char*)malloc(bytes_to_get);
if (0 == start_free)
{
int i;
obj *volatile *my_free_list, *p;
for (i = size; i <= __MAX_BYTES; i += __ALIGN)
{
my_free_list = free_list + FREELIST_INDEX((size_t)i);
p = *my_free_list;
if (p)
{
*my_free_list = p->free_list_link;
start_free = (char*)p;
end_free += i;
return chunk_alloc(size, nobjs);
}
}
end_free = 0;
start_free = (char*)malloc_alloc::allocate(bytes_to_get);
}
end_free = start_free + bytes_to_get;
heap_size = bytes_left;
return chunk_alloc(size, nobjs);
}
}
/***********************************************************************/
typedef __default_alloc_template<0> alloc;
/***********************************************************************/
#endif // !_STL_ALLOC_H