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