STL源码剖析——deque

Deque

双向开口的连续线性空间

deque与vector的区别:

  1.允许常数时间对头部元素进行插入或移除

   2.由分段连续空间组合而成,没有容量的概念

deque采用一块连续的区间,其中每个元素指向一个缓冲区(存放数据)

   缓冲区大小BufSize默认0表示使用512bytes

template<class T, class Alloc = alloc, size_t BufSize = 0>
class deque {
public:
    typedef T value_type;
    typedef value_type* pointer;
protected:
    typedef pointer* map_pointer;
    iterator start;   //第一个节点
    iterator finish;  //最后一个节点
    map_pointer map;
    size_type map_size;    //map容纳的指针数
}
size_type max_size() const {return size_type(-1);}

迭代器

template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator{
    typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
    
    typedef random_access_iterator_tag iterator_category;
    ...

    T* cur;  //缓冲区当前元素
    T* first;//缓冲区头部
    T* last; //缓冲区尾部
    map_pointer node; //指向管控中心

    static size_t buffer_size() {return __deque_buf_size(BufSize, sizeof(T));
    //如果n不为0,buffer_size为n
    //否则表示使用默认值
    //    如果sizeof(value_type) < 512,传回512/sizeof(value_type)
    //    否则传回1
    inline size_t __deque_buf_size(size_t n, size_t sz)
    {
        return n != 0 ? n : (sz < 512 ? size_t(512 / sz) : size_t(1));
    }
    

迭代器操作

//设置跳到new_node缓冲区
void set_node(map_pointer new_node) {
    node = new_node;
    first = *new_node;
    last = first + difference_type(buffer_size());
}

//各个重载运算
reference operator*() const {return *cur;}
pointer operator->() const {return &(operator*());}

//两个迭代器之间的距离
difference_type operator-(const self& x) const {
    return difference_type(buffer_size()) * (node - x.node - 1) + (cur - first) + (x.last - x.cur);

self& operator++(){
    ++cur;
    if (cur == last) {
        set_node(node + 1);
        cur = first;
    }
    return *this;
}

self operator++(int) {
    self tmp = *this;
    ++*this;
    return tmp;
}

self& operator+= (difference_type n) {
    difference_type offset = n + (cur - first);
    //目标在同一缓冲区内
    if (offset >= 0 && offset < difference_type(buffer_size())){
        cur += n;
    }
    else {
        difference_type node_offset = offset > 0 ? offset / difference_type(buffer_size())
                                    : -difference_type((-offset - 1) / buffer_size()) - 1;
        set_node(node + node_offset);
        cur = first + (offset - node_offset * difference_type(buffer_size()));
    }
    return *this;
}

self& operator+(difference_type n) const {
    self tmp = *this;
    return tmp += n;
}

空间配置器

typedef simple_alloc<value_type, Alloc> data_allocator;
typedef simple_alloc<pointer, Alloc> map_allocator;

deque(int n, const value_type& value)
    : start(), finish(), map(0), map_size(0)
{
    fill_initialize(n, value);
}

void fill_initialize(size_type n, const value_type& value)
{
    // 把deque的结构都产生并安排好
    create_map_and_nodes(n);
    map_pointer cur;
    __STL_TRY{
        //为每个节点的缓冲区设定初值
        for (cur = start.node; cur < finish.node; ++cur);
            uninitialized_fill(*cur, *cur + buffer_size(), value);
        //最后一个节点的设定稍有不同
        uninitialized_fill(finish.first, finish.cur, value);
    }
    catch(...) {
        ...
    }
}

void create_map_and_nodes(size_type num_elements)
{
    //需要节点数
    size_type num_nodes = num_elements / buffers_size() + 1;
    
    //map要管理的节点数
    map_size = max(initial_map_size(), num_nodes + 2);
    map = map_allocator::allocate(map_size);

    //令nstart和nfinish指向map所拥有的全部节点的最中央区段
    map_pointer nstart = map + (map_size - num_nodes) / 2;
    map_pointer nfinish = nstart + num_nodes - 1;

    map_pointer cur;
    __STL_TRY {
        for (cur = nstart; cur <= nfinish; ++cur)
            *cur = allocate_node();
    }
    catch(...) {
        ...
    }

    //为start和end设定正确内容
    start.set_node(nstart);
    finish.set_node(nfinish);
    start.cur = start.first;
    finish.cur = finish.first + num_elements % buffer_size();
}

头部/尾部插入元素:

1.如果能在当前buffe直接插入元素则构造该元素并返回

2.否则根据需要决定map是否应当扩容

3.构造新的节点

4.改变start/finish, start.cur/finish.cur状态

5.在start.cur/finish.cur上构造元素

push_back:

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_back_aux(const value_type &t) {
    value_type t_copy = t;
    reserve_map_at_back();
    *(finish.node + 1) = allocate_node();  //配置新节点
    __STL_TRY{
        construct(finish.cur, t_copy);
        finish.set_node(finish.node + 1);
        finish.cur = finish.first;
    }
    __STL_UNWIND(deallocate_node(*(finish.node + 1)));
}

push_front:

void push_front(const value_type& t) {
    if (start.cur != start.first) {
        //第一缓冲区尚有备用空间
        construct(start.cur - 1, t);
        --start.cur;
    }
    else
        push_front_aux(t);
}

void push_front_aux(const value_type &t)
{
    value_type t_copy = t;
    reserve_map_at_front();
    *(start.node - 1) = allocate_node(); //配置一个新节点
    __STL_TRY {
        start.set_node(start.node - 1);
        start.cur = start.last - 1;
        construct(tsart.cur, t_copy);
    }
    catch(...) {
        start.set_node(start.node + 1);
        start.cur = start.first;
        deallocate_node(*(start.node - 1));
        throw;
    }
}

 

reserve_map_at_front/back:判断是否需要扩充map

如果需要扩容:

1.配置新的空间,新的空间至少为原来的两倍

2.把原map内容拷贝到新空间中部位置

3.释放原map

4.设定新map和map_size

5.设定迭代器start和finish

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)
{
    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);
}

pop_front和pop_back

void pop_back() {
    if (finish.cur != finish.first) {
        --finish.cur;
        destroy(finish.cur);
    }
    else
        pop_back_aux();
    }
}

void pop_back_aux() {
    deallocate_node(finish.first);
    finish.set_node(finish.node - 1);
    finish.cur = finish.last - 1;
    destroy(finish.cur);
}

 

void pop_front() {
    if (start.cur != start.last) {
        destroy(start.cur);
        --start.cur;
    }
    else
        pop_front_aux();
    }
}

void pop_front_aux() {
    destroy(start.cur);
    deallocate_node(start.first);
    finish.set_node(start.node + 1);
    start.cur = start.first;
}

clear

最终保留一个缓冲区

void clear() {
    for (map_pointer node = start.node + 1; node < finish.node; ++node) {
        destroy(*node, *node + buffer_size());
        data_allocator::deallocate(*node, buffer_size());
    }
    //保留一个缓冲区
    if (start.node != finish.node) {
        destroy(start.cur, start.last);
        destroy(finish.first, finish.cur);
        data_allocator::deallocate(finish.first, buffer_size());
    }
    else
        destroy(start.cur, finish.cur);
    finish = start;
}

erase

iterator erase(iterator pos) {
    iterator next = pos;
    ++next;
    difference_type index = pos - start;
    if (index < size() >> 1)) {
        //如果清除点之前的元素较少
        //就移动清除点之前的元素
        copy_backward(start, pos, next);
        pop_front();
    }
    else {
        //如果清除点之后的元素较少
        //就移动清除点之后的元素
        copy(next, finish, pos);
        pop_back();
    }
    return start + index;
}

iterator erase(iterator first, iterator last) {
    if (first == start && last == finish) {
        clear();
        return finish;
    }
    else {
        difference_type n = last - first;
        difference_type elems_before = first - start;
        if (elems_before < (size() - n) / 2) {
            copy_backward(start, first, last);
            iterator new_start = start + n;
            destroy(start, new_start);
            for (map_pointer cur = start.node; cur < new_start.node; ++cur)
                data_allocator::deallocate(*cur, buffer_size());
            start = new_start;
        }
        else {
            copy(last, finish, first);
            iterator new_finish = finish - n;
            destroy(new_finish, finish);
            for (map_pointer cur = new_finish.node + 1; cur <= finish.node); ++cur)
                data_allocator::deallocate(*cur, buffer_size());
            finish = new_finish;
        }
        return start + elems_before;
    }
}

insert

iterator insert(iterator position, const value_type& x) {
    if (position.cur == start.cur) {
        push_front(x);
        return start;
    }
    if (position.cur == finish.cur) {
        push_back(x);
        iterator tmp = finish;
        --tmp;
        return tmp;
    }
    return insert_aux(position, x);
}

iterator insert_aux(iterator pos, const value_type& x) {
    difference_type index = pos - start;
    value_type x_copy = x;
    if (index < s.size() / 2) {
        //如果插入点之前的元素较少,则移动插入点之前的元素
        push_front(front());
        iterator front1 = start;
        ++front1;
        iterator front2 = front1;
        ++front2;
        pos = start + index;
        iterator pos1 = pos;
        ++pos1;
        copy(front2, pos1, front1);
    }
    else {
        push_back(back());
        iterator back1 = finish;
        --back1;
        iterator back2 = back1;
        --back2;
        pos = start + index;
        copy_backward(pos, back2, back1);    
    }
    *pos = x_copy;
    return pos;
}

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值