您的位置:首页 > 其它

STL空间配置器(三)

2016-04-07 10:34 302 查看
上一篇没写完的代码,因为我用的是VS2013所以无法测试我的配置器,我是照着SGI的版本写的,所以不符合STL标准规范,而VS随身带的STL是符合STL规范的,所以我无法测试,等到我自己写好了迭代器,容器之后,就可以测试了,不过在这之前,我将专门用一篇文件来学习并且自己写一个内存池,然后将这个内存池部署到我的HJSTL里面,下面是完整的HJSTL 空间配置器代码 1.0.0,大规模模仿SGI,但是这没办法,到后面数据结构部分可能会加入更多我自己的东西,前面的部分再怎么搞也没有别人那么好,所以就献丑了,代码--->

/*
* CopyRight (c) 2016
* HuJian in nankai edu.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.  Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose.  It is provided "as is" without express or implied warranty.
*
* Time :2016/4/5 in nankai edu
*/
#ifndef _HJ_STL_ALLOC_H_
#define _HJ_STL_ALLOC_H_
#include<cstdio>
#include<climits>
#include<iostream>
#include<cstddef>

//if out of memory,just exit after print the info.
#define  _THROW_BAD_ALLOC cerr<<"out of memory"<<endl; exit(1);

//this is the new-handler handler,using when oom
void(*_malloc_alloc_oom_handler_hjstl)() = 0;

//this is the first class of mmu in hjstl,this class will work
//if the second dispatch the job to it.
template<int inst>
class _malloc_alloc_first{
private:
static void* oom_malloc(size_t); //this function use to malloc and has the new-handler
static void* oom_remalloc(void*, size_t);//re-malloc
public:
//this function is the first allocator of hjstl
static void* allocate(size_t size)
{
void* result = malloc(size);
//check and dispatch it to oom_malloc if oom
if (0 == result) result = oom_malloc(size);
return result;
}
//re-malloc,same as malloc
static void* remallocate(void* old, size_t/*old mem size*/, size_t new_size)
{
void* result = realloc(old, new_size);
if (0 == result) result = oom_remalloc(old, new_size);
return result;
}
//de-allocate
static void deallocate(void* mem, size_t size)
{
//we not use the memory pool,so just use free
//but we will use the memory pool to manage the memory of
//hjstl later
free(mem);
}

//we can use this function to set the new handler
static void(*set_malloc_handler(void(*handler)()))()
{
//get the old oom handler,and we will return it to process
void(*old)() = _malloc_alloc_oom_handler_hjstl;
//set the new handler
_malloc_alloc_oom_handler_hjstl = handler;
return (old);
}
};//end of malloc alloc first

///---impelment the first allocate of hjstl
template<int inst>
void* _malloc_alloc_first<inst>::oom_malloc(size_t size)
{
//this is the oom handler,this function will use this function when
//out of memory
void(*my_malloc_handler)();
void* result;
for (;;){//i will loop to test till i get the memory
my_malloc_handler = _malloc_alloc_oom_handler_hjstl;
if (0 == my_malloc_handler) { _THROW_BAD_ALLOC; }
//else,the handler defined,i can use it,run this handler
(*my_malloc_handler)();
result = malloc(size);
if (result) return result;//succeed!!!
}
}
//same as malloc
template<int inst>
void* _malloc_alloc_first<inst>::oom_remalloc(void* old, size_t size)
{
void (* my_handler)();
void* result;
for (;;){
my_handler = _malloc_alloc_oom_handler_hjstl;
if (0 == myhandler) { _THROW_BAD_ALLOC; }
(*my_handler)();
result = realloc(old, size);
if (result) return result;
}
}

//ok,i need to define a first allocate,and if the second
//allocate can not do it,let me try!
typedef _malloc_alloc_first<0> malloc_alloc_first_hjstl;

//we do this,because we need to let the HJSTL standard with STL
template<class Type,class HJALLOC>
class STD_STL_Alloc{
public:
static Type* allocate(size_t size){
return 0 == n ? 0 : (Type*)HJALLOC::allocate(size*sizeof(Type));
}
static Type* allocate(){
return (Type*)HJALLOC::allocate(sizeof(Type));
}
static void deallocate(Type* mem,size_t size){
if (size != 0){
HJALLOC::deallocate(mem,size*sizeof(Type));
}
}
static void deallocate(Type* mem){
HJALLOC::deallocator(mem,sizeof(mem));
}
};

//ok,start to write the second allocator
//and some auxiliary variable neeed to define here
#define  _ALIGN       8                     //the min mem block
#define  _MAX_BYTES   128               //the max mem block
#define  _NFREELISTS  _MAX_BYTES/_ALIGN  //this is the num of free list

template<int inst>//no thread supposed
class _malloc_alloc_second{
private:
//round up a size
static size_t HJSTL_ROUND_UP(size_t bytes){
//ok,i use the SGI STL's round up method,it nice
return (((bytes)+_ALIGN - 1) & ~(_ALIGN - 1));
}
//this function will find the free list's position in the array actually
static size_t HJSTL_FREELIST_INDEX(size_t bytes){
//i just copy the sgi stl's code here.
return (((bytes)+_ALIGN - 1) / _ALIGN - 1);
}
//this is the free list's node strcture
//this is a usion.just copy the sgi stl's
union free_list_node{
free_list_node* free_list_link;//store the next free list
char            data[1];//if assigned,this is the user's data
};
//this is the array of free lists
static free_list_node* free_list[_NFREELISTS];

//return an object of size n,and this function will re-fill the
//free list,update the free list array .
static void* refill(size_t size);

//memory pool,and allocate a chunk for nobjs of size 'size'
//if the memory of pool is not so enough,this function will
//return the real num of nobjs
static char* chunk_alloc(size_t size, int &nobjs);

//this is a sample memory pool
static char* pool_free_start;
static char* pool_free_end;
static size_t  heap_size;

//the second allocate
static void* allocate(size_t size)
{
free_list_node*  my_free_list;
free_list_node*  result;
//dispatch the job,if the ask memory bigger _MAX_BYTES,use
//the first allocate,else use the second allocate
if (size > (size_t)_MAX_BYTES){
return (malloc_alloc_first_hjstl::allocate(size));
}
//else ,use the second allocate to do this job
//find the aim-free list
my_free_list = free_list + HJSTL_FREELIST_INDEX(size);
//now,the result is the header pointer of this list
result = *my_free_list;
if (0 == result){//shirt,this list is empty,i will call refill to help me
void* r = refill(HJSTL_ROUND_UP(size));
return r;
}
//else,this free list is not empty,just use the header pointer
//and change the free list.
*my_free_list = result->free_list_link;
return result;
}

//the second deallocate
static void deallocate(void* mem, size_t size)
{
free_list_node* my_free_list;
free_list_node* new_header_pointer = (free_list_node*)mem;
//dispatch the job
if (size > (size_t)_MAX_BYTES){
malloc_alloc_first_hjstl::deallocate(mem, size);
return;
}
//else,solve it.
//first of all,i will find the free list's position
my_free_list = free_list + HJSTL_FREELIST_INDEX(size);
//change the list
new_header_pointer->free_list_link = my_free_list;
*my_free_list = new_header_pointer;
return;
}

//this is the second reallocate
static void* reallocate(void* old, size_t old_size, size_t new_size);

};//end of second allocator

//heihei,this is the default alloc,we will use this alloc in our project
typedef _malloc_alloc_second<0> hjstl_alloc;

//the follow function is the memory pool of hjstl
//and this function will allocate a large memory chunk in
//order to avoid fragement.
template<int inst>
char*    _malloc_alloc_second<inst>::chunk_alloc(size_t size, int&nobjs)
{
char*  result;
//the size the the num of each objs
size_t total_bytes = size*nobjs;
//the left bytes current
size_t left_bytes = pool_free_end - pool_free_start;
//then,if the memory pool's memory is enough,just give it and update the memory pool.
if (total_bytes <= left_bytes){
result = pool_free_start;
pool_free_start += total_bytes;
return result;
}
//else ,the pool's memory is not enough to allocate.
//but the pool's memory left at least 1 size memory
//just return it.
//but,this part maybe left some fragment in the pool
//so,before we re-fill this pool,we need to handle the lefe mem in pool
else if (left_bytes >= size){
//calc the counts we can allocate
nobjs = left_bytes / size;
//update the pool's size
total_bytes = nobjs*size;
result = pool_free_start;
pool_free_start += total_bytes;
return result;
}
//ok,the pool's memory is not enough to allocate 1 obj
//then,we need to re-alloc memory to fill pool from os
//but before doing this job,we need to check the pool's left memory
//and handle it.<append the left mem to free list>
else{
size_t ask_bytes = 8* total_bytes + HJSTL_ROUND_UP(heap_size >> 4);
//is any fragments in pool's
if (left_bytes > 0){
free_list_node* my_free_list = free_list + HJSTL_FREELIST_INDEX(left_bytes);
//append this fragment to free list
((free_list_node*)pool_free_start)->free_list_link = *my_free_list;
*my_free_list = (free_list_node*)pool_free_start;
}
//is any little fragment in pool now? if it is,just free it
if (left_bytes<_ALIGN){
#ifdef _HJSTL_DUBUG_
cout<<"little fragments left pool now...<in function chunk_alloc>"<<endl;
#endif
int free_len = 0;
while (free_len < left_bytes){
free(pool_free_start);
pool_free_start++;
}
}
//it's time to re-allocate a big memory from os
pool_free_start = (char*)malloc(ask_bytes);
//but if the malloc fail
if (0 == pool_free_start){
free_list_node*  my_free_list, *find_list;
//ok,we need to check the free lists and get some aproval size's
//node to free,and re-try malloc,loop till we get the memory
//but we will down to half ask to do it.
if (ask_bytes / 2 && ask_bytes>(2* total_bytes + HJSTL_ROUND_UP(heap_size >> 4)))
ask_bytes /= 2;
for (int i = size; i <= _MAX_BLOCKS; i += _ALIGN){
my_free_list = free_list + HJSTL_FREELIST_INDEX(i);
find_list = *my_free_list;
if (0 != find_list){
//free an node of this list
*my_free_list = find_list->free_list_link;
//update the pool's size
pool_free_start = (char*)find_list;
pool_free_end = pool_free_start + i;
//re-try
return (chunk_alloc(size, njobs));
}
}// end of for loop
//ok,you need to know we have no choice but ask first-allocate for help
pool_free_end = 0;
pool_free_start = (char*)malloc_alloc_first_hjstl::allocate(ask_bytes);
}
//well,if the program run to here,it say i have asked first-allocate for help
//and now i have enough memory to give you
//so,just adjust the pool's size and heap's size
heap_size += ask_bytes;
pool_free_end = pool_free_start + ask_bytes;
//you can re-call self to complete the job now.
//cause the pool's size is enough to  work.
return (chunk_alloc(size, nobjs));
}//end of re-allocate
}

//this is the re-fill function,and this function will adjust the free list
//and the main operator is call the chunk_alloc..
template<int inst>
void* _malloc_alloc_second<inst>::refill(size_t size)
{
//the default nodes is 20,but you can adjust the num
int default_nodes = 20;
//allocate memory from pool
char* chunk = chunk_alloc(size, default_nodes);
free_list_node*  my_free_list, *result;
free_list_node*  current_node, *next_node;
//if the chunk_alloc just return 1 nodes,it's ok to use it,but do not
//need to adjust the free list
if (1 == default_nodes)  return chunk;
//else,not only return 1 node,but also adjust the free list
my_free_list = free_list + HJSTL_FREELIST_INDEX(size);
result = (free_list_node*)chunk;//just get one node,and return to user
//connect the list,the first node give the user
//the next_node pointer to the start of chunk we can use to adjust free list
next_node = (free_list_node*)(chunk + size);
*my_free_list = next_node;
for (int i = 1;; i++){
current_node = next_node;
next_node = (free_list_node*)((char*)next_node + size);
//if this is the last node
if (i == default_nodes - 1){
current_node->free_list_link = 0;
}
else{
//this is not the last node
current_node->free_list_link = next_node;
}
}
return (result);
}

//re-allocate
template<int inst>
void* _malloc_alloc_second<inst>::reallocate(void* oldmem, size_t oldsz, size_t newsz)
{
void* result;
//if the size is no change.just return
if (HJSTL_ROUND_UP(oldsz) == HJSTL_ROUND_UP(newsz)) return oldmem;
//if the new size <old size,just return
if (oldsz > newsz) return oldmem;
//else,malloc,and copy data
result = allocate(newsz);
memcpy(rsult, oldmem, newsz);
deallocate(oldmem, oldsz);
return result;
}
#endif  //end of _HJ_STL_ALLOC_H_
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: