STL空间配置器(三)

上一篇没写完的代码,因为我用的是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_


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值