STL源码剖析__allcoate

书中对内存分配器部分。代码比较多,特别是针对小块内存的分配部分,内存分配/释放使用古老的malloc/free,代码编写在今天看来有点绕。

 

这里有几个思路是很值得学习的。

 

//2013-1-25: 补上uninitialized系列的fill,fill_n和copy函数,这三个函数和construct和destroy函数经常用于容器中。

//补上fill_n函数,没这个函数会编译错误。

 

#ifndef allocator_H_
#define allocator_H_

#include <new.h>
#include <stddef.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <algorithm>
#include <memory>

#include "iterator.h"
#include "type_traits.h"


namespace SGISTL
{ 
	//标准的STL allocator
	template<typename T>
	inline T* allocate(ptrdiff_t size)
	{
		set_new_handler(0);
		T* Tmep = (T*)(::operator new(size * sizeof(T)));
		if(Tmep == nullptr)
		{
			std::cerr<<"out of memory"<<endl;
			exit(1);
		}
		return Tmep;
	}

	template<typename T>
	inline T* allocate()
	{
		set_new_handler(0);
		T* Tmep = (T*)(::operator new(sizeof(T)));
		if(Tmep == nullptr)
		{
			std::cerr<<"out of memory"<<endl;
			exit(1);
		}
		return Tmep;
	}

	template<typename T>
	inline void deallocate(T* Buffer)
	{
		::operator delete(Buffer);
	}

	template<typename T>
	class allocator
	{
	public:
		typedef T value_type;
		typedef T* pointer;
		typedef const T* const_pointer;
		typedef T& reference;
		typedef const T& const_reference;
		typedef size_t size_type;
		typedef ptrdiff_t different_type;

		pointer allocate(size_type size)
		{
			return SGISTL::allocate<value_type>((different_type)size);
		}

		void deallocate(pointer p)
		{
			SGISTL::deallocate(p);
		}

		pointer address(reference x)
		{
			return (pointer)&x;
		}

		const_pointer address(reference x)
		{
			return (const_pointer)&x;
		}

		size_type init_page_size()
		{
			return std::max(size_type(1), size_type(4096/sizeof(T)));
		}

		size_type max_size()
		{
			return max(size_type(1), size_type(UINT_MAX/sizeof(T)));
		}
	};

	/* 只使用于GCC
	class allocator<void>
	{
	public:
		typedef void* pointer;
	};
	*/

	//SGI的allocator
	//construct and destroy
	template<typename T1, typename T2>
	inline void construct(T1* p, const T2& value)
	{
		new(p)T1(value);
	};

	template<typename T>
	inline void destroy(T* p)
	{
		typedef typename type_traits<T>::has_trivial_destructor trivial_destructor;
		_destroy(p, trivial_destructor());
	}

	template<typename T>
	inline void _destroy(T* p, false_type)
	{
		p->~T();
	}

	template<typename T>
	inline void _destroy(T* p, true_type)
	{
	}

	template<typename ForwardIterator>
	inline void destroy(ForwardIterator first, ForwardIterator last)
	{
		_destroy(first, last, value_type(first));
	}

	template<typename ForwardIterator, typename T>
	inline void _destroy(ForwardIterator first, ForwardIterator last, T*)
	{
		typedef type_traits<T>::has_trivial_destructor trivial_destructor;
		_destroy_aux(first, last, trivial_destructor());
	}

	template<typename ForwardIterator>
	inline void _destroy_aux(ForwardIterator first, ForwardIterator last, false_type)
	{
		for(; first != last; ++first)
		{
			destroy(&*first);
		}
	}

	template<typename ForwardIterator>
	inline void _destroy_aux(ForwardIterator first, ForwardIterator last, true_type)
	{
	}

	inline void destroy(char*, char*)
	{
	}

	inline void destroy(wchar_t*, wchar_t*)
	{
	}

	//first alloc
	template<int inst>
	class __malloc_alloc_template
	{
	private:
		static void* oom_malloc(size_t);
		static void* oom_realloc(void *, size_t);
		static void (* __malloc_alloc_oom_handler)();
	public:
		static void* allocate(size_t n)
		{
			void *result = malloc(n);
			if(result == nullptr)
			{
				result = oom_malloc(n);
			}
			return result;
		}

		static void deallocate(void *p, size_t)
		{
			free(p);
		}

		static void* reallocate(void *p, size_t, size_t new_size)
		{
			void *result = realloc(p, new_size);
			if(result == nullptr)
			{
				result = oom_realloc(p, new_size);
			}
			return result;
		}

		static void (* set_malloc_handler(void (*f)()))()
		{
			void (* old)() = __malloc_alloc_oom_handler;
			__malloc_alloc_oom_handler = f;
			return (old);
		}
	};

	template<int inst>
	void (*__malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = nullptr;

	template<int inst>
	void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
	{
		void (* my_malloc_handler)();
		void *result;

		while(true)
		{
			my_malloc_handler = __malloc_alloc_oom_handler;
			if(my_malloc_handler == nullptr)
			{
				cerr<<"out of memory."<<endl;
				exit(1);
			}
			(*my_malloc_handler)();
			result = malloc(n);
			if(result != nullptr)
			{
				return result;
			}
		}

	}

	template<int inst>
	void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
	{
		void (* my_malloc_handler)();
		void *result;

		while(true)
		{
			my_malloc_handler = __malloc_alloc_oom_handler;
			if(my_malloc_handler == nullptr)
			{
				cerr<<"out of memory."<<endl;
				exit(1);
			}
			(*my_malloc_handler)();
			result = realloc(p, n);
			if(result != nullptr)
			{
				return result;
			}
		}
	}

	typedef __malloc_alloc_template<0> malloc_alloc;

	//second alloc
	const size_t ALIGN = 8;
	const size_t MAX_BYTES = 128;
	const size_t NFREELISTS = MAX_BYTES / ALIGN;
	const size_t AMOUNTOFOBJ = 20;

	template<int inst>
	class __default_alloc_template
	{
	private:
		static size_t ROUND_UP(size_t n)
		{
			return ((n + ALIGN - 1) & ~(ALIGN - 1));
		}
	private:
		union obj
		{
			union obj * free_list_link;
			char client_data[1];
		};
	private:
		static obj* volatile 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, size_t &noobjs);

		static char *start_free;
		static char *end_free;
		static size_t heap_size;

	public:
		static void *allocate(size_t n);
		static void deallocate(void *p, size_t n);
		static void *reallocate(void *p, size_t, size_t new_size);
	};

	template<int inst>
	char* __default_alloc_template<inst>::start_free = nullptr;

	template<int inst>
	char* __default_alloc_template<inst>::end_free = nullptr;

	template<int inst>
	size_t __default_alloc_template<inst>::heap_size = 0;

	template<int inst>
	typename __default_alloc_template<inst>::obj * volatile 
	__default_alloc_template<inst>::free_list[NFREELISTS] 
	= {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr};

	template<int inst>
	void* __default_alloc_template<inst>::allocate(size_t n)
	{
		if(n > MAX_BYTES)
		{
			return (malloc_alloc::allocate(n));
		}

		obj * volatile * my_free_list = free_list + FREELIST_INDEX(n);
		obj *result = *my_free_list;

		if(result == nullptr)
		{
			void *r = refill(ROUND_UP(n));
			return r;
		}
		else
		{
			*my_free_list = result->free_list_link;
			return result;
		}

	}

	template<int inst>
	void __default_alloc_template<inst>::deallocate(void *p, size_t n)
	{
		if(n > MAX_BYTES)
		{
			malloc_alloc::deallocate(p, n);
		}

		obj *q = (obj*)p;
		obj * volatile * my_free_list = free_list + FREELIST_INDEX(n);

		q->free_list_link = *my_free_list;
		*my_free_list = q;
	}

	template<int inst>
	void* __default_alloc_template<inst>::refill(size_t n)
	{
		size_t noobjs = AMOUNTOFOBJ;
		char * chunk = chunk_alloc(n, noobjs);

		if(noobjs == 1)
		{
			return chunk;
		}

		obj *result = (obj *)chunk;
		chunk += n;
	    obj *current_obj = (obj *)(chunk);

		obj * volatile * my_freelist = free_list + FREELIST_INDEX(n);
		*my_freelist = current_obj;

		while(noobjs > 2)
		{
			chunk += n;
			current_obj->free_list_link = (obj *)chunk;
			--noobjs;
		}
		current_obj->free_list_link = nullptr;

		return result;
	}

	template<int inst>
	char* __default_alloc_template<inst>::chunk_alloc(size_t size, size_t &noobjs)
	{
		char *result;
		size_t total_bytes = size * noobjs;
		size_t bytes_left  = end_free - start_free;

		if(bytes_left >= total_bytes)//chunk空间满足noobjs * size大小的空间
		{
			result = start_free;
			start_free += total_bytes;
			return result;
		}
		else if(bytes_left >= size)//chunk空间只满足 大于等于size并且小于noobjs * size大小 
		{
			noobjs = bytes_left / size;
			total_bytes = size * noobjs;
			result = start_free;
			start_free += total_bytes;
			return result;
		}
		else //不能满足一个size大小
		{
			size_t bytes_to_get = (2 * total_bytes) + ROUND_UP(heap_size * 16);

			if(bytes_left > 0)//chunk中有剩余空间分配给其它大小的列表
			{
				obj * volatile * my_freelist = free_list + FREELIST_INDEX(bytes_left);
				((obj *)(start_free))->free_list_link = *my_freelist;
				*my_freelist = (obj	*)start_free;
			}

			start_free = (char *)malloc(bytes_to_get);

			if(start_free == nullptr) //向系统获取空间失败
			{
				obj * volatile * my_freelist;
				obj *p;
				for(size_t i = size; i <= MAX_BYTES; i += ALIGN)//从比较自己大的空间列表里获取空间
				{
					my_freelist = free_list + FREELIST_INDEX(i);
					p = *my_freelist;
					if(p != nullptr)
					{
						*my_freelist = p->free_list_link;
						start_free = (char*)p;
						end_free = start_free + i;
						return(chunk_alloc(size, noobjs));
					}
				}

				end_free = 0;

				start_free = (char *)malloc_alloc::allocate(bytes_to_get); //最后做后努力,如果失败则退出
			}

			heap_size += bytes_to_get;
			end_free = start_free + bytes_to_get;
			return(chunk_alloc(size, noobjs));
		}
	}

	template<typename T, typename Alloc = __default_alloc_template<0>>
	class simple_alloc
	{
	public:
		static T * allocate(size_t n)
		{
			return (n == 0 ? 0 : (T*)Alloc::allocate(n * sizeof(T)));
		}

		static T * allocate(void)
		{
			return (T*)Alloc::allocate(sizeof(T));
		}

		static void deallocate(T *p)
		{
			Alloc::deallocate(p, sizeof(T));
		}

		static void deallocate(T *p, size_t n)
		{
			Alloc::deallocate(p, n * sizeof(T));
		}
	};

	typedef __default_alloc_template<0> alloc;

    //memory assistant
	//copy
	template<typename InputIterator, typename ForwardIterator>
	inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result)
	{
		return _uninitialized_copy(first, last, result, value_type(result));
	}

	inline char* uninitialized_copy(char *first, char *last, char *result)
	{
		std::memmove(result, first, (last - first));
		return result + (last - first);
	};

	inline wchar_t* uninitialized_copy(wchar_t *first, wchar_t *last, wchar_t *result)
	{
		std::memmove(result, first, (last - first));
		return result + (last - first);
	};

	template<typename InputIterator, typename ForwardIterator, typename T>
	inline ForwardIterator _uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result, T*)
	{
		typedef type_traits<T>::is_POD_type POD_type;
		return _uninitialized_copy_aux(first, last, result, POD_type());
	};

	template<typename InputIterator, typename ForwardIterator>
	inline ForwardIterator _uninitialized_copy_aux(InputIterator first, InputIterator last, ForwardIterator result, true_type)
	{
		return std::copy(first, last, result);
	}

	template<typename InputIterator, typename ForwardIterator>
	inline ForwardIterator _uninitialized_copy_aux(InputIterator first, InputIterator last, ForwardIterator result, false_type)
	{
		for(;first != last; ++first, ++result)
		{
			construct(&*result, *first);
		}
		return result;
	}

	//fill
	template<typename ForwardIterator, typename T>
	inline void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x)
	{
		_uninitialized_fill(first, last, x, value_type(first));
	}

	template<typename ForwardIterator, typename T, typename T2>
	inline void _uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x, T2*)
	{
		typedef type_traits<T2>::is_POD_type POD_type;
		_uninitialized_fill_aux(first, last, x, POD_type());
	}

	template<typename ForwardIterator, typename T>
	inline void _uninitialized_fill_aux(ForwardIterator first, ForwardIterator last, const T& x, true_type)
	{
		std::fill(first, last, x);
	}

	template<typename ForwardIterator, typename T>
	inline void _uninitialized_fill_aux(ForwardIterator first, ForwardIterator last, const T& x, false_type)
	{
		for(; first != last; ++first)
		{
			construct(&*first, x);
		}
	}

	//fill_n
	template<typename ForwardIterator, typename Size, typename T>
	inline ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T& x)
	{
		return _uninitialized_fill_n(first, n, x, value_type(first));
	}

	template<typename ForwardIterator, typename Size, typename T, typename T2>
	inline ForwardIterator _uninitialized_fill_n(ForwardIterator first, Size n, const T& x, T2*)
	{
		typedef type_traits<T2>::is_POD_type POD_type;
		return _uninitialized_fill_n_aux(first, n, x, POD_type());
	}

	template<typename ForwardIterator, typename Size, typename T>
	inline ForwardIterator _uninitialized_fill_n_aux(ForwardIterator first, Size n, const T& x, true_type)
	{
		return fill_n(first, n, x);
	}

	template<typename ForwardIterator, typename Size, typename T>
	inline ForwardIterator _uninitialized_fill_n_aux(ForwardIterator first, Size n, const T& x, false_type)
	{
		for(;n > 0; --n, ++first)
		{
			construct(&*first, x);
		}
		return first;
	}

	template<typename outputiterator, typename Size, typename T>
	inline outputiterator fill_n(outputiterator iter, Size n, const T& x)
	{
		for(;n >0; --n, ++iter)
		{
			*iter = x;
		}
		return iter;
	}
}

#endif

你可能感兴趣的:(STL源码剖析__allcoate)