#ifndef MEMORYPOOL_H
#define MEMORYPOOL_H
#include <stdio.h>
#include <assert.h>
using
namespace
std;
class
MemoryPool
{
private
:
enum
{__ALIGN = 8};
enum
{__MAX_BYTES = 128};
enum
{__NFREELISTS = __MAX_BYTES/__ALIGN};
static
size_t
ROUND_UP(
size_t
bytes)
{
return
(((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
}
union
obj
{
union
obj* free_list_link;
char
client_data[1];
};
private
:
static
obj *free_list[__NFREELISTS];
static
size_t
FREELIST_INDEX(
size_t
bytes)
{
return
(((bytes) + __ALIGN-1)/__ALIGN - 1);
}
static
void
*refill(
size_t
n);
static
char
*chunk_alloc(
size_t
size,
int
&nobjs);
static
char
*start_free;
static
char
*end_free;
static
size_t
heap_size;
public
:
static
void
* allocate(
size_t
n)
{
obj** my_free_list = NULL;
obj* result = NULL;
if
(n > (
size_t
) __MAX_BYTES)
{
return
malloc
(n);
}
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;
if
(result == 0)
{
void
*r = refill(ROUND_UP(n));
return
r;
}
*my_free_list = result->free_list_link;
return
result;
};
static
void
deallocate(
void
*p,
size_t
n)
{
assert
(p != NULL);
obj* q = (obj *)p;
obj** my_free_list = NULL;
if
(n > (
size_t
) __MAX_BYTES)
{
free
(p) ;
}
my_free_list = free_list + FREELIST_INDEX(n);
q -> free_list_link = *my_free_list;
*my_free_list = q;
}
static
void
* reallocate(
void
*p,
size_t
old_sz,
size_t
new_sz);
} ;
char
* MemoryPool::chunk_alloc(
size_t
size,
int
& nobjs)
{
char
* result = NULL;
size_t
total_bytes = size * nobjs;
size_t
bytes_left = end_free - start_free;
if
(bytes_left >= total_bytes)
{
result = start_free;
start_free += total_bytes;
return
result;
}
else
if
(bytes_left >= size)
{
nobjs = bytes_left/size;
total_bytes = size * nobjs;
result = start_free;
start_free += total_bytes;
return
result;
}
else
{
size_t
bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
if
(bytes_left > 0)
{
obj** 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 ** my_free_list, *p;
for
(i = size; i <= __MAX_BYTES; i += __ALIGN)
{
my_free_list = free_list + FREELIST_INDEX(i);
p = *my_free_list;
if
(0 != p)
{
*my_free_list = p -> free_list_link;
start_free = (
char
*)p;
end_free = start_free + i;
return
chunk_alloc(size, nobjs);
}
}
end_free = 0;
}
heap_size += bytes_to_get;
end_free = start_free + bytes_to_get;
return
chunk_alloc(size, nobjs);
}
}
void
* MemoryPool::refill(
size_t
n)
{
int
nobjs = 20;
char
* chunk = chunk_alloc(n, nobjs);
obj* * my_free_list = NULL;
obj* result = NULL;
obj* current_obj = NULL;
obj* next_obj = NULL;
int
i;
if
(1 == nobjs)
{
return
chunk;
}
my_free_list = free_list + FREELIST_INDEX(n);
result = (obj*)chunk;
*my_free_list = next_obj = (obj *)(chunk + n);
for
(i = 1; ; i++)
{
current_obj = next_obj;
next_obj = (obj *)((
char
*)next_obj + n);
if
(nobjs - 1 == i)
{
current_obj -> free_list_link = NULL;
break
;
}
else
{
current_obj -> free_list_link = next_obj;
}
}
return
result;
}
void
* MemoryPool::reallocate(
void
*p,
size_t
old_sz,
size_t
new_sz)
{
void
* result = NULL;
size_t
copy_sz = 0;
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 = new_sz > old_sz? old_sz : new_sz;
memcpy
(result, p, copy_sz);
deallocate(p, old_sz);
return
result;
}
char
* MemoryPool::start_free = 0;
char
* MemoryPool::end_free = 0;
size_t
MemoryPool::heap_size = 0;
MemoryPool::obj* MemoryPool::free_list[MemoryPool::__NFREELISTS]
= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
#endif