STL源码剖析之stl_deque的实现(二)

STL中deque(双端队列)是一种非常重要的结构,stack,与queue底层都是借助deque.

deque(双端队列)是一种双向开口的连续性空间,双向开口意思是可以在头尾两端做元素的插入和删除操作。deque和vector最大的差异在于deque允许常数时间内对起头端进行元素的插入或移除操作,二者在于deque没所谓的容量(capacity)观念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。deque采用一块所谓的map作为主控,这里所谓的map是一小块连续的空间,其中每个元素都是指针,指向另一段较大的连续线性空间,称为缓冲区。缓冲区才是deque的存储空间主体。SGI STL允许我们指定缓冲区大小,默认值为0表示将使用512 bytes缓冲区。但是在deque在排序的时候需要借住vector,为了最高效率要将deque先完整复制到一个vector身上,将vector排序后再复制回deque.默认map_size开始大小为8个.

下面的代码从stl_deque中摘取,deque仅仅实现了构造对象,与插入数值。

deque无类型文件,引用所需要的文件

#ifndef _DEQUE_
#define _DEQUE_

#include"stl_construct.h"
#include"stl_iterator.h"
#include"type_traits.h"
#include"stl_uninitialized.h"
#include"stl_alloc.h"
#include"stl_deque.h"

#endif

stl_construct.h 构造的实现

#ifndef _STL_CONSTRUCT_H
#define _STL_CONSTRUCT_H

#include"type_traits.h"
#include<new.h>

template <class T>
inline void destroy(T* pointer) 
{
    pointer->~T();
}

template <class T1, class T2>
inline void construct(T1* p, const T2& value) 
{
	new (p) T1(value);
}

template <class ForwardIterator>
inline void
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
{
	for ( ; first < last; ++first)
		destroy(&*first);
}

template <class ForwardIterator> 
inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) 
{}

template <class ForwardIterator, class T>
inline void __destroy(ForwardIterator first, ForwardIterator last, T*)
{
	typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
	__destroy_aux(first, last, trivial_destructor());
}

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

#endif

stl_iterator.h 迭代器

#ifndef _STL_ITERATOR_H
#define _STL_ITERATOR_H

template <class T>
inline T* value_type(const T*)
{
	return (T*)(0); 
}

template <class T>
inline size_t* distance_type(const T*)
{
	return (size_t*)(0);
}

struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

template <class T>
inline random_access_iterator_tag iterator_category(const T*) 
{
	return random_access_iterator_tag();
}

#endif

type_traits.h 萃取机制

#ifndef _TYPE_TRAITS_H
#define _TYPE_TRAITS_H


struct __true_type
{};
struct __false_type
{};

template <class type>
struct __type_traits 
{ 
   typedef __true_type     this_dummy_member_must_be_first;
   typedef __false_type    has_trivial_default_constructor;
   typedef __false_type    has_trivial_copy_constructor;
   typedef __false_type    has_trivial_assignment_operator;
   typedef __false_type    has_trivial_destructor;
   typedef __false_type    is_POD_type;
};

struct __type_traits<int> 
{ 
   typedef __true_type     this_dummy_member_must_be_first;
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
   typedef __true_type    is_POD_type;
};

#endif

stl_uninitialized.h 未初始化的参数

#ifndef _STL_UNINITIALIZED_H
#define _STL_UNINITIALIZED_H

#include<typeinfo.h>
#include"stl_algobase.h"

template<class ForwardIterator, class Size, class T>
ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T &x, __true_type)
{
	return fill_n(first, n, x);
}

template<class ForwardIterator, class Size, class T>
ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T &x, __false_type)
{
	ForwardIterator cur = first;
	for(; n>0; --n, ++cur)
		construct(&*cur, x);
	return cur;
}

template<class ForwardIterator, class Size, class T, class T1>
ForwardIterator __uninitialized_fill_n(ForwardIterator first, Size n, const T &x, T1*)
{
	cout<<"T1 = "<<typeid(T1).name()<<endl;
	typedef typename __type_traits<T1>::is_POD_type is_POD;
	return __uninitialized_fill_n_aux(first, n, x, is_POD());
}


template<class ForwardIterator, class Size, class T>
ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T &x)
{
	return __uninitialized_fill_n(first, n, x, value_type(first));
}

///////////////////////////////////////////////////////////////////////////////

template <class InputIterator, class ForwardIterator>
inline ForwardIterator __uninitialized_copy_aux(InputIterator first, 
												InputIterator last,
												ForwardIterator result,
												__true_type)
{
	return copy(first, last, result);
}

template <class InputIterator, class ForwardIterator>
ForwardIterator __uninitialized_copy_aux(InputIterator first, 
										 InputIterator last,
										 ForwardIterator result,
										 __false_type) 
{
	ForwardIterator cur = result;
    for ( ; first != last; ++first, ++cur)
		construct(&*cur, *first);
    return cur;
}

template <class InputIterator, class ForwardIterator, class T>
inline ForwardIterator __uninitialized_copy(InputIterator first,
											InputIterator last,
											ForwardIterator result, T*) 
{
	typedef typename __type_traits<T>::is_POD_type is_POD;
	return __uninitialized_copy_aux(first, last, result, is_POD());
}

template <class InputIterator, class ForwardIterator>
inline ForwardIterator uninitialized_copy(InputIterator first, 
										  InputIterator last,
										  ForwardIterator result) 
{
	return __uninitialized_copy(first, last, result, value_type(result));
}


#endif

stl_alloc.h 空间配置器

#ifndef _STL_ALLOC_H
#define _STL_ALLOC_H

#if 0
#include<new>
#define __THROW_BAD_ALLOC throw bad_alloc
#else
#include<iostream.h>
#include<malloc.h>
#include<stdlib.h>
#define __THROW_BAD_ALLOC cerr<<"Out Of Memory."<<endl;exit(1)
#endif

//malloc  free

template<int inst>
class __malloc_alloc_template
{
private:
	static void* oom_malloc(size_t n)
	{
		void (*my_malloc_handler)();
		void *result;
		for(;;)
		{
			my_malloc_handler = __malloc_alloc_oom_handler;
			if(0 == my_malloc_handler)
			{
				__THROW_BAD_ALLOC;
			}
			(*my_malloc_handler)();
			result = malloc(n);
			if(result)
				return result;
		}
	}
	static void* oom_realloc(void *p, size_t n)
	{
		void (* my_malloc_handler)();
		void *result;
		for (;;) 
		{
			my_malloc_handler = __malloc_alloc_oom_handler;
			if (0 == my_malloc_handler) 
			{
				__THROW_BAD_ALLOC; 
			}
			(*my_malloc_handler)();
			result = realloc(p, n);
			if (result) 
				return(result);
		}
	}
	static void(*__malloc_alloc_oom_handler)();
public:
	static void* allocate(size_t n)
	{
		void *result = malloc(n);
		if(0 == result)
			result = oom_malloc(n);
		return result;
	}
	static void  deallocate(void *p, size_t n)
	{
		free(p);
	}
	static void* reallocate(void *p, size_t old_sz, size_t new_sz)
	{
		void *result = realloc(p, new_sz);
		if(0 == result)
			result = oom_realloc(p, new_sz);
		return result;
	}
public:
	//set_new_handler  模拟
	static void(*set_malloc_handler(void(*f)()))()
	{
		void(*old)() = __malloc_alloc_oom_handler;
		__malloc_alloc_oom_handler = f;
		return old;
	}
};

void(* __malloc_alloc_template<0>::__malloc_alloc_oom_handler)() = 0;

typedef __malloc_alloc_template<0> malloc_alloc;
/////////////////////////////////////////////////////////////////////////////////

enum {__ALIGN = 8};
enum {__MAX_BYTES = 128};
enum {__NFREELISTS = __MAX_BYTES / __ALIGN};

template<bool threads, int inst>
class __default_alloc_template
{
public:
	static void * allocate(size_t n);
	static void   deallocate(void *p, size_t n);
	static void * reallocate(void *p, size_t old_sz, size_t new_sz);
protected:
	static void * refill(size_t n);
	static char* chunk_alloc(size_t size, int &nobjs);
private:
	static size_t ROUND_UP(size_t bytes)
	{
		return ((bytes + __ALIGN-1) &~(__ALIGN-1));
	}
private:
	union obj
	{
		union obj * free_list_link;
		char client_data[1];
	};
private:
	static size_t  FREELIST_INDEX(size_t bytes)
	{
		return ((bytes + __ALIGN-1) / __ALIGN-1);
	}
	static obj* free_list[__NFREELISTS];
private:
	static char * start_free;
	static char * end_free;
	static size_t heap_size;
};

template<bool threads, int inst>
char* __default_alloc_template<threads, inst>::start_free = 0;
template<bool threads, int inst>
char* __default_alloc_template<threads, inst>::end_free = 0;
template<bool threads, int inst>
size_t __default_alloc_template<threads, inst>::heap_size = 0;

template<bool threads, int inst>
__default_alloc_template<threads, inst>::obj*
__default_alloc_template<threads, inst>::free_list[__NFREELISTS] = 
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

template<bool threads, int inst>
void * __default_alloc_template<threads, inst>::allocate(size_t n)
{
	obj ** my_free_list;
	obj * result;
	if(n > __MAX_BYTES)
		return malloc_alloc::allocate(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;
}

template <bool threads, int inst>
char*
__default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
{
    char * result;
    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;
            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, nobjs));
    }
}

template <bool threads, int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n)
{
    int nobjs = 20;
    char * chunk = chunk_alloc(n, nobjs);
    obj ** my_free_list;
    obj * result;
    obj * current_obj, * next_obj;
    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 = 0;
            break;
        } 
		else 
		{
            current_obj -> free_list_link = next_obj;
        }
	}
    return(result);
}

template <bool threads, int inst>
void*
__default_alloc_template<threads, inst>::reallocate(void *p,
													size_t old_sz,
                                                    size_t new_sz)
{
    void * result;
    size_t copy_sz;
	
    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);
}


template <bool threads, int inst>
void __default_alloc_template<threads, inst>::deallocate(void *p, size_t n)
{
    obj *q = (obj *)p;
    obj ** my_free_list;
    if (n > (size_t) __MAX_BYTES) 
	{
        malloc_alloc::deallocate(p, n);
        return;
    }
    my_free_list = free_list + FREELIST_INDEX(n);
    q -> free_list_link = *my_free_list;
    *my_free_list = q;
}

/////////////////////////////////////////////////////////////////

#ifdef __USE_MALLOC
typedef __malloc_alloc_template<0> malloc_alloc;
typedef malloc_alloc alloc;
#else
typedef __default_alloc_template<0,0> alloc;
#endif

template<class T, class Alloc>
class simple_alloc
{
public:
	static T * allocate(size_t n)
	{
		return 0==n ? 0 : (T*)Alloc::allocate(n * sizeof(T));
	}
	static T * allocate(void)
	{
		return (T*)Alloc::allocate(sizeof(T));
	}
	static void deallocate(T *p, size_t n)
	{
		if(0!=n)
			Alloc::deallocate(p, n*sizeof(T));
	}
	static void deallocate(T *p)
	{
		Alloc::deallocate(p,sizeof(T));
	}
};
#endif




stl_deque.h 双端队列的实现

#ifndef _STL_DEQUE_H
#define _STL_DEQUE_H

template<class T>
T max(T &a, T &b)
{
	return a > b ? a : b;
}

size_t __deque_buf_size(size_t n, size_t sz)
{
	return n!=0 ? n : (sz<512 ? size_t(512/sz) : size_t(1));
}

template<class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator
{
	typedef __deque_iterator<T, T&, T*, BufSiz>   iterator;
	typedef T value_type;
	typedef Ptr pointer;
	typedef Ref reference;
	typedef size_t size_type;
	typedef size_t difference_type;
	typedef T** map_pointer;

	typedef __deque_iterator  self;

	static size_t buffer_size()
	{
		return __deque_buf_size(BufSiz, sizeof(T));
	}

	T *cur;
	T *first;
	T *last;
	map_pointer  node; //T**node

	/////////////////////////////////////////////////////////
	__deque_iterator() : cur(0), first(0), last(0), node(0) 
	{}
	void set_node(map_pointer new_node) 
	{
		node = new_node;
		first = *new_node;
		last = first + difference_type(buffer_size());
	}
	bool operator==(const self& x) const { return cur == x.cur; }
    bool operator!=(const self& x) const { return !(*this == x); }
	reference operator*() const { return *cur; }
	self& operator++() 
	{
		++cur;
		if (cur == last) 
		{
			set_node(node + 1);
			cur = first;
		}
		return *this; 
  }
};

template<class T, class Alloc=alloc, size_t BufSiz=0>
class deque
{
public:
	typedef T value_type;
	typedef size_t size_type;
	typedef value_type* pointer;

	typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
public:
	deque() : start(), finish(), map(0), map_size(0)
	{
		create_map_and_nodes(0);
	}
public:
	iterator begin()
	{
		return start;
	}
	iterator end()
	{
		return finish;
	}
public:
	void push_back(const value_type& t) 
	{
		if (finish.cur != finish.last - 1) 
		{
			construct(finish.cur, t);
			++finish.cur;
		}
		else
			push_back_aux(t);
	}
	
	void push_front(const value_type& t) 
	{
		if (start.cur != start.first) 
		{
			construct(start.cur - 1, t);
			--start.cur;
		}
		else
			push_front_aux(t);
	}
protected:
	void push_back_aux(const value_type& t);
	void push_front_aux(const value_type& t);
	void reserve_map_at_back (size_type nodes_to_add = 1)
	{
		if (nodes_to_add + 1 > map_size - (finish.node - map))
			reallocate_map(nodes_to_add, false);
	}
	void reserve_map_at_front (size_type nodes_to_add = 1) 
	{
		if (nodes_to_add > start.node - map)
			reallocate_map(nodes_to_add, true);
	}
	void reallocate_map(size_type nodes_to_add, bool add_at_front);
protected:
	void create_map_and_nodes(size_type n);
	static size_type initial_map_size() 
	{
		return 8; 
	}
	static size_type buffer_size() 
	{
		return __deque_buf_size(BufSiz, sizeof(value_type));
	}
	pointer allocate_node() 
	{
		return data_allocator::allocate(buffer_size()); 
	}
protected:
	typedef pointer* map_pointer;
	typedef simple_alloc<value_type, Alloc> data_allocator;
	typedef simple_alloc<pointer, Alloc>    map_allocator;
protected:
	iterator start;
	iterator finish;
	map_pointer map;
	size_type map_size;
};

template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::create_map_and_nodes(size_type num_elements)
{
	size_type num_nodes = num_elements / buffer_size() + 1;
	
	//map_size = max(initial_map_size(), num_nodes + 2);
	map_size = initial_map_size() > (num_nodes + 2) ? initial_map_size() : (num_nodes + 2);
	map = map_allocator::allocate(map_size);
	
	map_pointer nstart = map + (map_size - num_nodes) / 2;
	map_pointer nfinish = nstart + num_nodes - 1;
    
	map_pointer cur;
	
    for (cur = nstart; cur <= nfinish; ++cur)
		*cur = allocate_node();
	
	start.set_node(nstart);
	finish.set_node(nfinish);
	start.cur = start.first;
	finish.cur = finish.first + num_elements % buffer_size();
}

template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::push_back_aux(const value_type& t) 
{
	value_type t_copy = t;
	reserve_map_at_back();
	*(finish.node + 1) = allocate_node();
	
    construct(finish.cur, t_copy);
    finish.set_node(finish.node + 1);
    finish.cur = finish.first;
}

template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::push_front_aux(const value_type& t) 
{
	value_type t_copy = t;
	reserve_map_at_front();
	*(start.node - 1) = allocate_node();
	
    start.set_node(start.node - 1);
    start.cur = start.last - 1;
    construct(start.cur, t_copy);
} 

template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::reallocate_map(size_type nodes_to_add,
                                              bool add_at_front) 
{
	size_type old_num_nodes = finish.node - start.node + 1;
	size_type new_num_nodes = old_num_nodes + nodes_to_add;
	
	map_pointer new_nstart;
	if (map_size > 2 * new_num_nodes) 
	{
		new_nstart = map + (map_size - new_num_nodes) / 2 
			+ (add_at_front ? nodes_to_add : 0);
		if (new_nstart < start.node)
			copy(start.node, finish.node + 1, new_nstart);
		else
			copy_backward(start.node, finish.node + 1, new_nstart + old_num_nodes);
	}
	else 
	{
		size_type new_map_size = map_size + max(map_size, nodes_to_add) + 2;
		
		map_pointer new_map = map_allocator::allocate(new_map_size);
		new_nstart = new_map + (new_map_size - new_num_nodes) / 2
			+ (add_at_front ? nodes_to_add : 0);
		copy(start.node, finish.node + 1, new_nstart);
		map_allocator::deallocate(map, map_size);
		
		map = new_map;
		map_size = new_map_size;
	}
	
	start.set_node(new_nstart);
	finish.set_node(new_nstart + old_num_nodes - 1);
}


#endif

测试主函数main.cpp

void main()
{
	deque<int> de;
	de.push_back(1);
	de.push_back(2);
	de.push_front(3);
	de.push_front(4);  //4 3 1 2

	deque<int>::iterator it = de.begin();
	while(it != de.end())
	{
		cout<<*it<<" ";
		++it;
	}
	cout<<endl;

}

参考文献:《STL源码剖析》

猜你喜欢

转载自blog.csdn.net/zzb2019/article/details/81189818