STL源码剖析(十一)序列式容器之forward_list

STL list是个双向链表,forward_list为单向链表。
list的迭代器是双向的Bidirectional Iterator,forward_list的迭代器是单向的Forward Iterator,单向链表耗用空间更小,部分操作更快。
forward_list的insert、erase、splice等操作不会造成原有迭代器失效,删除操作指向被删除元素的迭代器会失效。
STL的习惯,插入操作会将新元素插入到指定位置之前,但forward_list作为单向链表没有办法定位出前一个位置,需要从头找起,因此forward_list特别提供insert_after()、erase_after(),基于同样效率考虑,forward_list不提供push_back(),只提供push_front(),因此forward_list元素次序会与元素插入进来的次序相反。

namespace std _GLIBCXX_VISIBILITY(default)
{
  struct _Fwd_list_node_base //节点设计
  {
    _Fwd_list_node_base() = default;
    _Fwd_list_node_base(_Fwd_list_node_base&& __x) noexcept
      : _M_next(__x._M_next)
    { __x._M_next = nullptr; }

    _Fwd_list_node_base(const _Fwd_list_node_base&) = delete; //拷贝构造函数=delete,不可使用拷贝构造函数
    _Fwd_list_node_base& operator=(const _Fwd_list_node_base&) = delete; //不可使用赋值运算符

    _Fwd_list_node_base& //赋值运算符右值引用
    operator=(_Fwd_list_node_base&& __x) noexcept
    {
      _M_next = __x._M_next;
      __x._M_next = nullptr;
      return *this;
    }

    _Fwd_list_node_base* _M_next = nullptr;

    _Fwd_list_node_base*
    _M_transfer_after(_Fwd_list_node_base* __begin,
		      _Fwd_list_node_base* __end) noexcept
    {
      _Fwd_list_node_base* __keep = __begin->_M_next;
      if (__end)
	{
	  __begin->_M_next = __end->_M_next;
	  __end->_M_next = _M_next;
	}
      else
	__begin->_M_next = nullptr;
      _M_next = __keep;
      return __end;
    }

    void
    _M_reverse_after() noexcept
    {
      _Fwd_list_node_base* __tail = _M_next;
      if (!__tail)
	return;
      while (_Fwd_list_node_base* __temp = __tail->_M_next)
	{
	  _Fwd_list_node_base* __keep = _M_next;
	  _M_next = __temp;
	  __tail->_M_next = __temp->_M_next;
	  _M_next->_M_next = __keep;
	}
    }
  };

  template<typename _Tp>
    struct _Fwd_list_node //节点元素设计
    : public _Fwd_list_node_base
    {
      _Fwd_list_node() = default;

      __gnu_cxx::__aligned_buffer<_Tp> _M_storage; //节点元素

      _Tp*
      _M_valptr() noexcept
      { return _M_storage._M_ptr(); }

      const _Tp*
      _M_valptr() const noexcept
      { return _M_storage._M_ptr(); }
    };

  template<typename _Tp>
    struct _Fwd_list_iterator //迭代器设计
    {
      typedef _Fwd_list_iterator<_Tp>		_Self;
      typedef _Fwd_list_node<_Tp>		_Node;

      typedef _Tp				value_type;
      typedef _Tp*				pointer;
      typedef _Tp&				reference;
      typedef ptrdiff_t				difference_type;
      typedef std::forward_iterator_tag		iterator_category; //单向

      _Fwd_list_iterator() noexcept
      : _M_node() { }

      explicit
      _Fwd_list_iterator(_Fwd_list_node_base* __n) noexcept
      : _M_node(__n) { }

      reference
      operator*() const noexcept
      { return *static_cast<_Node*>(this->_M_node)->_M_valptr(); }

      pointer
      operator->() const noexcept
      { return static_cast<_Node*>(this->_M_node)->_M_valptr(); }

      _Self&
      operator++() noexcept
      {
	_M_node = _M_node->_M_next;
	return *this;
      }

      _Self
      operator++(int) noexcept
      {
	_Self __tmp(*this);
	_M_node = _M_node->_M_next;
	return __tmp;
      }

      bool
      operator==(const _Self& __x) const noexcept
      { return _M_node == __x._M_node; }

      bool
      operator!=(const _Self& __x) const noexcept
      { return _M_node != __x._M_node; }

      _Self
      _M_next() const noexcept
      {
	if (_M_node)
	  return _Fwd_list_iterator(_M_node->_M_next);
	else
	  return _Fwd_list_iterator(nullptr);
      }

      _Fwd_list_node_base* _M_node;
    };

   //省略const_iterator设计
  //迭代器比较运算符
  template<typename _Tp>
    inline bool
    operator==(const _Fwd_list_iterator<_Tp>& __x,
	       const _Fwd_list_const_iterator<_Tp>& __y) noexcept
    { return __x._M_node == __y._M_node; }

  template<typename _Tp>
    inline bool
    operator!=(const _Fwd_list_iterator<_Tp>& __x,
	       const _Fwd_list_const_iterator<_Tp>& __y) noexcept
    { return __x._M_node != __y._M_node; }

  template<typename _Tp, typename _Alloc>
    struct _Fwd_list_base
    {
    protected:
      typedef __alloc_rebind<_Alloc, _Tp> 		  _Tp_alloc_type;
      typedef __alloc_rebind<_Alloc, _Fwd_list_node<_Tp>> _Node_alloc_type;
      typedef __gnu_cxx::__alloc_traits<_Node_alloc_type> _Node_alloc_traits;

      struct _Fwd_list_impl
      : public _Node_alloc_type
      {
	_Fwd_list_node_base _M_head;

	_Fwd_list_impl()
	  noexcept( noexcept(_Node_alloc_type()) )
	: _Node_alloc_type(), _M_head()
	{ }

	_Fwd_list_impl(_Fwd_list_impl&&) = default;

	_Fwd_list_impl(_Fwd_list_impl&& __fl, _Node_alloc_type&& __a)
	: _Node_alloc_type(std::move(__a)), _M_head(std::move(__fl._M_head))
	{ }

	_Fwd_list_impl(_Node_alloc_type&& __a)
	: _Node_alloc_type(std::move(__a)), _M_head()
	{ }
      };

      _Fwd_list_impl _M_impl;

    public:
      typedef _Fwd_list_iterator<_Tp>		iterator;
      typedef _Fwd_list_const_iterator<_Tp>	const_iterator;
      typedef _Fwd_list_node<_Tp>		_Node;

      _Node_alloc_type&
      _M_get_Node_allocator() noexcept
      { return this->_M_impl; }

      const _Node_alloc_type&
      _M_get_Node_allocator() const noexcept
      { return this->_M_impl; }

      _Fwd_list_base() = default;

      _Fwd_list_base(_Node_alloc_type&& __a)
      : _M_impl(std::move(__a)) { }

      // When allocators are always equal.
      _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a,
		     std::true_type)
      : _M_impl(std::move(__lst._M_impl), std::move(__a))
      { }

      // When allocators are not always equal.
      _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a);

      _Fwd_list_base(_Fwd_list_base&&) = default;

      ~_Fwd_list_base()
      { _M_erase_after(&_M_impl._M_head, nullptr); }

    protected:
      _Node*
      _M_get_node()
      {
	auto __ptr = _Node_alloc_traits::allocate(_M_get_Node_allocator(), 1);
	return std::__to_address(__ptr);
      }

      template<typename... _Args>
	_Node*
	_M_create_node(_Args&&... __args)
	{
	  _Node* __node = this->_M_get_node();
	  __try
	    {
	      _Tp_alloc_type __a(_M_get_Node_allocator());
	      typedef allocator_traits<_Tp_alloc_type> _Alloc_traits;
	      ::new ((void*)__node) _Node;
	      _Alloc_traits::construct(__a, __node->_M_valptr(),
				       std::forward<_Args>(__args)...);
	    }
	  __catch(...)
	    {
	      this->_M_put_node(__node);
	      __throw_exception_again;
	    }
	  return __node;
	}

      template<typename... _Args>
	_Fwd_list_node_base*
	_M_insert_after(const_iterator __pos, _Args&&... __args);

      void
      _M_put_node(_Node* __p)
      {
	typedef typename _Node_alloc_traits::pointer _Ptr;
	auto __ptr = std::pointer_traits<_Ptr>::pointer_to(*__p);
	_Node_alloc_traits::deallocate(_M_get_Node_allocator(), __ptr, 1);
      }

      _Fwd_list_node_base*
      _M_erase_after(_Fwd_list_node_base* __pos);

      _Fwd_list_node_base*
      _M_erase_after(_Fwd_list_node_base* __pos,
		     _Fwd_list_node_base* __last);
    };
  //forward_list数据结构
  template<typename _Tp, typename _Alloc = allocator<_Tp>>
    class forward_list : private _Fwd_list_base<_Tp, _Alloc>
    {
      static_assert(is_same<typename remove_cv<_Tp>::type, _Tp>::value,
	  "std::forward_list must have a non-const, non-volatile value_type");

    private:
      typedef _Fwd_list_base<_Tp, _Alloc>		_Base;
      typedef _Fwd_list_node<_Tp>			_Node;
      typedef _Fwd_list_node_base			_Node_base;
      typedef typename _Base::_Tp_alloc_type		_Tp_alloc_type;
      typedef typename _Base::_Node_alloc_type		_Node_alloc_type;
      typedef typename _Base::_Node_alloc_traits	_Node_alloc_traits;
      typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type>	_Alloc_traits;

    public:
      // types:
      typedef _Tp					value_type;
      typedef typename _Alloc_traits::pointer		pointer;
      typedef typename _Alloc_traits::const_pointer	const_pointer;
      typedef value_type&				reference;
      typedef const value_type&				const_reference;

      typedef _Fwd_list_iterator<_Tp>			iterator;
      typedef _Fwd_list_const_iterator<_Tp>		const_iterator;
      typedef std::size_t				size_type;
      typedef std::ptrdiff_t				difference_type;
      typedef _Alloc					allocator_type;

      forward_list() = default;

      explicit
      forward_list(const _Alloc& __al) noexcept
      : _Base(_Node_alloc_type(__al))
      { }

      forward_list(const forward_list& __list, const _Alloc& __al)
      : _Base(_Node_alloc_type(__al))
      { _M_range_initialize(__list.begin(), __list.end()); }

    private:
      forward_list(forward_list&& __list, _Node_alloc_type&& __al,
		   false_type)
      : _Base(std::move(__list), std::move(__al))
      {
	// If __list is not empty it means its allocator is not equal to __a,
	// so we need to move from each element individually.
	insert_after(cbefore_begin(),
		     std::__make_move_if_noexcept_iterator(__list.begin()),
		     std::__make_move_if_noexcept_iterator(__list.end()));
      }

      forward_list(forward_list&& __list, _Node_alloc_type&& __al,
		   true_type)
      noexcept
      : _Base(std::move(__list), _Node_alloc_type(__al), true_type{})
      { }

    public:

      forward_list(forward_list&& __list, const _Alloc& __al)
      noexcept(_Node_alloc_traits::_S_always_equal())
      : forward_list(std::move(__list), _Node_alloc_type(__al),
		     typename _Node_alloc_traits::is_always_equal{})
      { }

      explicit
      forward_list(size_type __n, const _Alloc& __al = _Alloc())
      : _Base(_Node_alloc_type(__al))
      { _M_default_initialize(__n); }

      forward_list(size_type __n, const _Tp& __value,
		   const _Alloc& __al = _Alloc())
      : _Base(_Node_alloc_type(__al))
      { _M_fill_initialize(__n, __value); }

      template<typename _InputIterator,
	       typename = std::_RequireInputIter<_InputIterator>>
	forward_list(_InputIterator __first, _InputIterator __last,
		     const _Alloc& __al = _Alloc())
	: _Base(_Node_alloc_type(__al))
	{ _M_range_initialize(__first, __last); }

      forward_list(const forward_list& __list)
      : _Base(_Node_alloc_traits::_S_select_on_copy(
		__list._M_get_Node_allocator()))
      { _M_range_initialize(__list.begin(), __list.end()); }

      forward_list(forward_list&&) = default;

      forward_list(std::initializer_list<_Tp> __il,
		   const _Alloc& __al = _Alloc())
      : _Base(_Node_alloc_type(__al))
      { _M_range_initialize(__il.begin(), __il.end()); }

      ~forward_list() noexcept
      { }

      forward_list&
      operator=(const forward_list& __list);

      forward_list&
      operator=(forward_list&& __list)
      noexcept(_Node_alloc_traits::_S_nothrow_move())
      {
	constexpr bool __move_storage =
	  _Node_alloc_traits::_S_propagate_on_move_assign()
	  || _Node_alloc_traits::_S_always_equal();
	_M_move_assign(std::move(__list), __bool_constant<__move_storage>());
	return *this;
      }

      forward_list&
      operator=(std::initializer_list<_Tp> __il)
      {
	assign(__il);
	return *this;
      }

      template<typename _InputIterator,
	       typename = std::_RequireInputIter<_InputIterator>>
	void
	assign(_InputIterator __first, _InputIterator __last)
	{
	  typedef is_assignable<_Tp, decltype(*__first)> __assignable;
	  _M_assign(__first, __last, __assignable());
	}

      void
      assign(size_type __n, const _Tp& __val)
      { _M_assign_n(__n, __val, is_copy_assignable<_Tp>()); }

      void
      assign(std::initializer_list<_Tp> __il)
      { assign(__il.begin(), __il.end()); }

      /// Get a copy of the memory allocation object.
      allocator_type
      get_allocator() const noexcept
      { return allocator_type(this->_M_get_Node_allocator()); }

      iterator
      before_begin() noexcept
      { return iterator(&this->_M_impl._M_head); }

      const_iterator
      before_begin() const noexcept
      { return const_iterator(&this->_M_impl._M_head); }

      iterator
      begin() noexcept
      { return iterator(this->_M_impl._M_head._M_next); }

      const_iterator
      begin() const noexcept
      { return const_iterator(this->_M_impl._M_head._M_next); }

      iterator
      end() noexcept
      { return iterator(nullptr); }

      const_iterator
      end() const noexcept
      { return const_iterator(nullptr); }

      const_iterator
      cbegin() const noexcept
      { return const_iterator(this->_M_impl._M_head._M_next); }

      const_iterator
      cbefore_begin() const noexcept
      { return const_iterator(&this->_M_impl._M_head); }

      const_iterator
      cend() const noexcept
      { return const_iterator(nullptr); }

      bool
      empty() const noexcept
      { return this->_M_impl._M_head._M_next == nullptr; }

      size_type
      max_size() const noexcept
      { return _Node_alloc_traits::max_size(this->_M_get_Node_allocator()); }

      reference
      front()
      {
	_Node* __front = static_cast<_Node*>(this->_M_impl._M_head._M_next);
	return *__front->_M_valptr();
      }

      const_reference
      front() const
      {
	_Node* __front = static_cast<_Node*>(this->_M_impl._M_head._M_next);
	return *__front->_M_valptr();
      }

      template<typename... _Args>
	void
	emplace_front(_Args&&... __args)
	{
	  this->_M_insert_after(cbefore_begin(),
				std::forward<_Args>(__args)...);
	}

      void
      push_front(const _Tp& __val)
      { this->_M_insert_after(cbefore_begin(), __val); }

      void
      push_front(_Tp&& __val)
      { this->_M_insert_after(cbefore_begin(), std::move(__val)); }

      void
      pop_front()
      { this->_M_erase_after(&this->_M_impl._M_head); }

      template<typename... _Args>
	iterator
	emplace_after(const_iterator __pos, _Args&&... __args)
	{ return iterator(this->_M_insert_after(__pos,
					  std::forward<_Args>(__args)...)); }

      iterator
      insert_after(const_iterator __pos, const _Tp& __val)
      { return iterator(this->_M_insert_after(__pos, __val)); }

      iterator
      insert_after(const_iterator __pos, _Tp&& __val)
      { return iterator(this->_M_insert_after(__pos, std::move(__val))); }

      iterator
      insert_after(const_iterator __pos, size_type __n, const _Tp& __val);

      template<typename _InputIterator,
	       typename = std::_RequireInputIter<_InputIterator>>
	iterator
	insert_after(const_iterator __pos,
		     _InputIterator __first, _InputIterator __last);

      iterator
      insert_after(const_iterator __pos, std::initializer_list<_Tp> __il)
      { return insert_after(__pos, __il.begin(), __il.end()); }

      iterator
      erase_after(const_iterator __pos)
      { return iterator(this->_M_erase_after(const_cast<_Node_base*>
					     (__pos._M_node))); }

      iterator
      erase_after(const_iterator __pos, const_iterator __last)
      { return iterator(this->_M_erase_after(const_cast<_Node_base*>
					     (__pos._M_node),
					     const_cast<_Node_base*>
					     (__last._M_node))); }

      void
      swap(forward_list& __list) noexcept
      {
	std::swap(this->_M_impl._M_head._M_next,
		  __list._M_impl._M_head._M_next);
	_Node_alloc_traits::_S_on_swap(this->_M_get_Node_allocator(),
				       __list._M_get_Node_allocator());
      }

      void
      resize(size_type __sz);

      void
      resize(size_type __sz, const value_type& __val);

      void
      clear() noexcept
      { this->_M_erase_after(&this->_M_impl._M_head, nullptr); }

      void
      splice_after(const_iterator __pos, forward_list&& __list) noexcept
      {
	if (!__list.empty())
	  _M_splice_after(__pos, __list.before_begin(), __list.end());
      }

      void
      splice_after(const_iterator __pos, forward_list& __list) noexcept
      { splice_after(__pos, std::move(__list)); }

      void
      splice_after(const_iterator __pos, forward_list&& __list,
		   const_iterator __i) noexcept;

      void
      splice_after(const_iterator __pos, forward_list& __list,
		   const_iterator __i) noexcept
      { splice_after(__pos, std::move(__list), __i); }

      void
      splice_after(const_iterator __pos, forward_list&&,
		   const_iterator __before, const_iterator __last) noexcept
      { _M_splice_after(__pos, __before, __last); }

      void
      splice_after(const_iterator __pos, forward_list&,
		   const_iterator __before, const_iterator __last) noexcept
      { _M_splice_after(__pos, __before, __last); }

      void
      remove(const _Tp& __val);

      template<typename _Pred>
	void
	remove_if(_Pred __pred);

      void
      unique()
      { unique(std::equal_to<_Tp>()); }

      template<typename _BinPred>
	void
	unique(_BinPred __binary_pred);

      void
      merge(forward_list&& __list)
      { merge(std::move(__list), std::less<_Tp>()); }

      void
      merge(forward_list& __list)
      { merge(std::move(__list)); }

      template<typename _Comp>
	void
	merge(forward_list&& __list, _Comp __comp);

      template<typename _Comp>
	void
	merge(forward_list& __list, _Comp __comp)
	{ merge(std::move(__list), __comp); }

      void
      sort()
      { sort(std::less<_Tp>()); }

      template<typename _Comp>
	void
	sort(_Comp __comp);

      void
      reverse() noexcept
      { this->_M_impl._M_head._M_reverse_after(); }
    };

  template<typename _Tp, typename _Alloc>
    bool
    operator==(const forward_list<_Tp, _Alloc>& __lx,
	       const forward_list<_Tp, _Alloc>& __ly);

  template<typename _Tp, typename _Alloc>
    inline bool
    operator<(const forward_list<_Tp, _Alloc>& __lx,
	      const forward_list<_Tp, _Alloc>& __ly)
    { return std::lexicographical_compare(__lx.cbegin(), __lx.cend(),
					  __ly.cbegin(), __ly.cend()); }

  /// Based on operator==
  template<typename _Tp, typename _Alloc>
    inline bool
    operator!=(const forward_list<_Tp, _Alloc>& __lx,
	       const forward_list<_Tp, _Alloc>& __ly)
    { return !(__lx == __ly); }

  /// Based on operator<
  template<typename _Tp, typename _Alloc>
    inline bool
    operator>(const forward_list<_Tp, _Alloc>& __lx,
	      const forward_list<_Tp, _Alloc>& __ly)
    { return (__ly < __lx); }

  /// Based on operator<
  template<typename _Tp, typename _Alloc>
    inline bool
    operator>=(const forward_list<_Tp, _Alloc>& __lx,
	       const forward_list<_Tp, _Alloc>& __ly)
    { return !(__lx < __ly); }

  /// Based on operator<
  template<typename _Tp, typename _Alloc>
    inline bool
    operator<=(const forward_list<_Tp, _Alloc>& __lx,
	       const forward_list<_Tp, _Alloc>& __ly)
    { return !(__ly < __lx); }

  /// See std::forward_list::swap().
  template<typename _Tp, typename _Alloc>
    inline void
    swap(forward_list<_Tp, _Alloc>& __lx,
	 forward_list<_Tp, _Alloc>& __ly)
    noexcept(noexcept(__lx.swap(__ly)))
    { __lx.swap(__ly); }
} // namespace std

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值