diff options
Diffstat (limited to 'include/EASTL/slist.h')
-rw-r--r-- | include/EASTL/slist.h | 1946 |
1 files changed, 0 insertions, 1946 deletions
diff --git a/include/EASTL/slist.h b/include/EASTL/slist.h deleted file mode 100644 index dc3c447..0000000 --- a/include/EASTL/slist.h +++ /dev/null @@ -1,1946 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright (c) Electronic Arts Inc. All rights reserved. -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// An slist is a singly-linked list. The C++ standard library doesn't define -// such a thing as an slist, nor does the C++ TR1. Our implementation of slist -// largely follows the design of the SGI STL slist container, which is also -// found in STLPort. Singly-linked lists use less memory than doubly-linked -// lists, but are less flexible. -// -// In looking at slist, you will notice a lot of references to things like -// 'before first', 'before last', 'insert after', and 'erase after'. This is -// due to the fact that std::list insert and erase works on the node before -// the referenced node, whereas slist is singly linked and operations are only -// efficient if they work on the node after the referenced node. This is because -// with an slist node you know the node after it but not the node before it. -// -/////////////////////////////////////////////////////////////////////////////// - - - -#ifndef EASTL_SLIST_H -#define EASTL_SLIST_H - - -#include <EASTL/internal/config.h> -#include <EASTL/allocator.h> -#include <EASTL/type_traits.h> -#include <EASTL/iterator.h> -#include <EASTL/algorithm.h> -#include <EASTL/initializer_list.h> -#include <EASTL/sort.h> -#include <EASTL/bonus/compressed_pair.h> -#include <stddef.h> - -EA_DISABLE_ALL_VC_WARNINGS(); - - #include <new> - -EA_RESTORE_ALL_VC_WARNINGS(); - -EA_DISABLE_SN_WARNING(828); // The EDG SN compiler has a bug in its handling of variadic template arguments and mistakenly reports "parameter "args" was never referenced" - - -// 4530 - C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc -// 4345 - Behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized -// 4571 - catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught. -EA_DISABLE_VC_WARNING(4530 4345 4571); - - -#if defined(EA_PRAGMA_ONCE_SUPPORTED) - #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. -#endif - - - -namespace eastl -{ - - /// EASTL_SLIST_DEFAULT_NAME - /// - /// Defines a default container name in the absence of a user-provided name. - /// - #ifndef EASTL_SLIST_DEFAULT_NAME - #define EASTL_SLIST_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " slist" // Unless the user overrides something, this is "EASTL slist". - #endif - - - /// EASTL_SLIST_DEFAULT_ALLOCATOR - /// - #ifndef EASTL_SLIST_DEFAULT_ALLOCATOR - #define EASTL_SLIST_DEFAULT_ALLOCATOR allocator_type(EASTL_SLIST_DEFAULT_NAME) - #endif - - - - /// SListNodeBase - /// - /// This is a standalone struct so that operations on it can be done without templates - /// and so that an empty slist can have an SListNodeBase and thus not create any - /// instances of T. - /// - struct SListNodeBase - { - SListNodeBase* mpNext; - } EASTL_LIST_PROXY_MAY_ALIAS; - - - #if EASTL_LIST_PROXY_ENABLED - - /// SListNodeBaseProxy - /// - /// In debug builds, we define SListNodeBaseProxy to be the same thing as - /// SListNodeBase, except it is templated on the parent SListNode class. - /// We do this because we want users in debug builds to be able to easily - /// view the slist's contents in a debugger GUI. We do this only in a debug - /// build for the reasons described above: that SListNodeBase needs to be - /// as efficient as possible and not cause code bloat or extra function - /// calls (inlined or not). - /// - /// SListNodeBaseProxy *must* be separate from its parent class SListNode - /// because the slist class must have a member node which contains no T value. - /// It is thus incorrect for us to have one single SListNode class which - /// has both mpNext and mValue. So we do a recursive template trick in the - /// definition and use of SListNodeBaseProxy. - /// - template <typename SLN> - struct SListNodeBaseProxy - { - SLN* mpNext; - }; - - template <typename T> - struct SListNode : public SListNodeBaseProxy< SListNode<T> > - { - T mValue; - }; - - #else - template <typename T> - struct SListNode : public SListNodeBase - { - T mValue; - }; - #endif - - - /// SListIterator - /// - template <typename T, typename Pointer, typename Reference> - struct SListIterator - { - typedef SListIterator<T, Pointer, Reference> this_type; - typedef SListIterator<T, T*, T&> iterator; - typedef SListIterator<T, const T*, const T&> const_iterator; - typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef SListNode<T> node_type; - typedef Pointer pointer; - typedef Reference reference; - typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; - - public: - node_type* mpNode; - - public: - SListIterator(); - SListIterator(const SListNodeBase* pNode); - SListIterator(const iterator& x); - - reference operator*() const; - pointer operator->() const; - - this_type& operator++(); - this_type operator++(int); - }; - - - - /// SListBase - /// - /// See VectorBase (class vector) for an explanation of why we - /// create this separate base class. - /// - template <typename T, typename Allocator> - struct SListBase - { - public: - typedef Allocator allocator_type; - typedef SListNode<T> node_type; - typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. - typedef ptrdiff_t difference_type; - #if EASTL_LIST_PROXY_ENABLED - typedef SListNodeBaseProxy< SListNode<T> > base_node_type; - #else - typedef SListNodeBase base_node_type; // We use SListNodeBase instead of SListNode<T> because we don't want to create a T. - #endif - - protected: - eastl::compressed_pair<base_node_type, allocator_type> mNodeAllocator; - #if EASTL_SLIST_SIZE_CACHE - size_type mSize; - #endif - - base_node_type& internalNode() EA_NOEXCEPT { return mNodeAllocator.first(); } - base_node_type const& internalNode() const EA_NOEXCEPT { return mNodeAllocator.first(); } - allocator_type& internalAllocator() EA_NOEXCEPT { return mNodeAllocator.second(); } - const allocator_type& internalAllocator() const EA_NOEXCEPT { return mNodeAllocator.second(); } - - public: - const allocator_type& get_allocator() const EA_NOEXCEPT; - allocator_type& get_allocator() EA_NOEXCEPT; - void set_allocator(const allocator_type& allocator); - - protected: - SListBase(); - SListBase(const allocator_type& a); - ~SListBase(); - - node_type* DoAllocateNode(); - void DoFreeNode(node_type* pNode); - - SListNodeBase* DoEraseAfter(SListNodeBase* pNode); - SListNodeBase* DoEraseAfter(SListNodeBase* pNode, SListNodeBase* pNodeLast); - - }; // class SListBase - - - - /// slist - /// - /// This is the equivalent of C++11's forward_list. - /// - /// -- size() is O(n) -- - /// Note that as of this writing, list::size() is an O(n) operation when EASTL_SLIST_SIZE_CACHE is disabled. - /// That is, getting the size of the list is not a fast operation, as it requires traversing the list and - /// counting the nodes. We could make list::size() be fast by having a member mSize variable. There are reasons - /// for having such functionality and reasons for not having such functionality. We currently choose - /// to not have a member mSize variable as it would add four bytes to the class, add a tiny amount - /// of processing to functions such as insert and erase, and would only serve to improve the size - /// function, but no others. The alternative argument is that the C++ standard states that std::list - /// should be an O(1) operation (i.e. have a member size variable), most C++ standard library list - /// implementations do so, the size is but an integer which is quick to update, and many users - /// expect to have a fast size function. The EASTL_SLIST_SIZE_CACHE option changes this. - /// To consider: Make size caching an optional template parameter. - /// - /// Pool allocation - /// If you want to make a custom memory pool for a list container, your pool - /// needs to contain items of type slist::node_type. So if you have a memory - /// pool that has a constructor that takes the size of pool items and the - /// count of pool items, you would do this (assuming that MemoryPool implements - /// the Allocator interface): - /// typedef slist<Widget, MemoryPool> WidgetList; // Delare your WidgetList type. - /// MemoryPool myPool(sizeof(WidgetList::node_type), 100); // Make a pool of 100 Widget nodes. - /// WidgetList myList(&myPool); // Create a list that uses the pool. - /// - template <typename T, typename Allocator = EASTLAllocatorType > - class slist : public SListBase<T, Allocator> - { - typedef SListBase<T, Allocator> base_type; - typedef slist<T, Allocator> this_type; - - public: - typedef T value_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef SListIterator<T, T*, T&> iterator; - typedef SListIterator<T, const T*, const T&> const_iterator; - typedef typename base_type::size_type size_type; - typedef typename base_type::difference_type difference_type; - typedef typename base_type::allocator_type allocator_type; - typedef typename base_type::node_type node_type; - typedef typename base_type::base_node_type base_node_type; - - using base_type::mNodeAllocator; - using base_type::DoEraseAfter; - using base_type::DoAllocateNode; - using base_type::DoFreeNode; - #if EASTL_SLIST_SIZE_CACHE - using base_type::mSize; - #endif - using base_type::internalNode; - using base_type::internalAllocator; - - public: - slist(); - slist(const allocator_type& allocator); - explicit slist(size_type n, const allocator_type& allocator = EASTL_SLIST_DEFAULT_ALLOCATOR); - slist(size_type n, const value_type& value, const allocator_type& allocator = EASTL_SLIST_DEFAULT_ALLOCATOR); - slist(const this_type& x); - slist(std::initializer_list<value_type> ilist, const allocator_type& allocator = EASTL_SLIST_DEFAULT_ALLOCATOR); - slist(this_type&& x); - slist(this_type&& x, const allocator_type& allocator); - - template <typename InputIterator> - slist(InputIterator first, InputIterator last); // allocator arg removed because VC7.1 fails on the default arg. To do: Make a second version of this function without a default arg. - - this_type& operator=(const this_type& x); - this_type& operator=(std::initializer_list<value_type>); - this_type& operator=(this_type&& x); - - void swap(this_type& x); - - void assign(size_type n, const value_type& value); - void assign(std::initializer_list<value_type> ilist); - - template <typename InputIterator> - void assign(InputIterator first, InputIterator last); - - iterator begin() EA_NOEXCEPT; - const_iterator begin() const EA_NOEXCEPT; - const_iterator cbegin() const EA_NOEXCEPT; - - iterator end() EA_NOEXCEPT; - const_iterator end() const EA_NOEXCEPT; - const_iterator cend() const EA_NOEXCEPT; - - iterator before_begin() EA_NOEXCEPT; - const_iterator before_begin() const EA_NOEXCEPT; - const_iterator cbefore_begin() const EA_NOEXCEPT; - - iterator previous(const_iterator position); - const_iterator previous(const_iterator position) const; - - reference front(); - const_reference front() const; - - template <class... Args> - void emplace_front(Args&&... args); - - void push_front(const value_type& value); - reference push_front(); - void push_front(value_type&& value); - - void pop_front(); - - bool empty() const EA_NOEXCEPT; - size_type size() const EA_NOEXCEPT; - - void resize(size_type n, const value_type& value); - void resize(size_type n); - - iterator insert(const_iterator position); - iterator insert(const_iterator position, const value_type& value); - void insert(const_iterator position, size_type n, const value_type& value); - - template <typename InputIterator> - void insert(const_iterator position, InputIterator first, InputIterator last); - - // Returns an iterator pointing to the last inserted element, or position if insertion count is zero. - iterator insert_after(const_iterator position); - iterator insert_after(const_iterator position, const value_type& value); - iterator insert_after(const_iterator position, size_type n, const value_type& value); - iterator insert_after(const_iterator position, std::initializer_list<value_type> ilist); - iterator insert_after(const_iterator position, value_type&& value); - - template <class... Args> - iterator emplace_after(const_iterator position, Args&&... args); - - template <typename InputIterator> - iterator insert_after(const_iterator position, InputIterator first, InputIterator last); - - iterator erase(const_iterator position); - iterator erase(const_iterator first, const_iterator last); - - iterator erase_after(const_iterator position); - iterator erase_after(const_iterator before_first, const_iterator last); - - void clear() EA_NOEXCEPT; - void reset_lose_memory() EA_NOEXCEPT; // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. - - size_type remove(const value_type& value); - - template <typename Predicate> - size_type remove_if(Predicate predicate); - - void reverse() EA_NOEXCEPT; - - // splice splices to before position, like with the list container. However, in order to do so - // it must walk the list from beginning to position, which is an O(n) operation that can thus - // be slow. It's recommended that the splice_after functions be used whenever possible as they are O(1). - void splice(const_iterator position, this_type& x); - void splice(const_iterator position, this_type& x, const_iterator i); - void splice(const_iterator position, this_type& x, const_iterator first, const_iterator last); - void splice(const_iterator position, this_type&& x); - void splice(const_iterator position, this_type&& x, const_iterator i); - void splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last); - - void splice_after(const_iterator position, this_type& x); - void splice_after(const_iterator position, this_type& x, const_iterator i); - void splice_after(const_iterator position, this_type& x, const_iterator first, const_iterator last); - void splice_after(const_iterator position, this_type&& x); - void splice_after(const_iterator position, this_type&& x, const_iterator i); - void splice_after(const_iterator position, this_type&& x, const_iterator first, const_iterator last); - - // The following splice_after funcions are deprecated, as they don't allow for recognizing - // the allocator, cannot maintain the source mSize, and are not in the C++11 Standard definition - // of std::forward_list (which is the equivalent of this class). - void splice_after(const_iterator position, const_iterator before_first, const_iterator before_last); // before_first and before_last come from a source container. - void splice_after(const_iterator position, const_iterator previous); // previous comes from a source container. - - // Sorting functionality - // This is independent of the global sort algorithms, as lists are - // linked nodes and can be sorted more efficiently by moving nodes - // around in ways that global sort algorithms aren't privy to. - void sort(); - - template <class Compare> - void sort(Compare compare); - - // Not yet implemented: - // void merge(this_type& x); - // void merge(this_type&& x); - // template <class Compare> - // void merge(this_type& x, Compare compare); - // template <class Compare> - // void merge(this_type&& x, Compare compare); - // If these get implemented then make sure to override them in fixed_slist. - - bool validate() const; - int validate_iterator(const_iterator i) const; - - protected: - node_type* DoCreateNode(); - - template<typename... Args> - node_type* DoCreateNode(Args&&... args); - - template <typename Integer> - void DoAssign(Integer n, Integer value, true_type); - - template <typename InputIterator> - void DoAssign(InputIterator first, InputIterator last, false_type); - - void DoAssignValues(size_type n, const value_type& value); - - template <typename InputIterator> - node_type* DoInsertAfter(SListNodeBase* pNode, InputIterator first, InputIterator last); - - template <typename Integer> - node_type* DoInsertAfter(SListNodeBase* pNode, Integer n, Integer value, true_type); - - template <typename InputIterator> - node_type* DoInsertAfter(SListNodeBase* pNode, InputIterator first, InputIterator last, false_type); - - node_type* DoInsertValueAfter(SListNodeBase* pNode); - node_type* DoInsertValuesAfter(SListNodeBase* pNode, size_type n, const value_type& value); - - template<typename... Args> - node_type* DoInsertValueAfter(SListNodeBase* pNode, Args&&... args); - - void DoSwap(this_type& x); - - }; // class slist - - - - - - - - /////////////////////////////////////////////////////////////////////// - // SListNodeBase functions - /////////////////////////////////////////////////////////////////////// - - inline SListNodeBase* SListNodeInsertAfter(SListNodeBase* pPrevNode, SListNodeBase* pNode) - { - pNode->mpNext = pPrevNode->mpNext; - pPrevNode->mpNext = pNode; - return pNode; - } - - inline SListNodeBase* SListNodeGetPrevious(SListNodeBase* pNodeBase, const SListNodeBase* pNode) - { - while(pNodeBase && (pNodeBase->mpNext != pNode)) - pNodeBase = pNodeBase->mpNext; - return pNodeBase; - } - - inline const SListNodeBase* SListNodeGetPrevious(const SListNodeBase* pNodeBase, const SListNodeBase* pNode) - { - while(pNodeBase && (pNodeBase->mpNext != pNode)) - pNodeBase = pNodeBase->mpNext; - return pNodeBase; - } - - inline void SListNodeSpliceAfter(SListNodeBase* pNode, SListNodeBase* pNodeBeforeFirst, SListNodeBase* pNodeBeforeLast) - { - if((pNode != pNodeBeforeFirst) && (pNode != pNodeBeforeLast)) - { - SListNodeBase* const pFirst = pNodeBeforeFirst->mpNext; - SListNodeBase* const pPosition = pNode->mpNext; - - pNodeBeforeFirst->mpNext = pNodeBeforeLast->mpNext; - pNode->mpNext = pFirst; - pNodeBeforeLast->mpNext = pPosition; - } - } - - inline void SListNodeSpliceAfter(SListNodeBase* pNode, SListNodeBase* pNodeBase) - { - SListNodeBase* const pNodeBeforeLast = SListNodeGetPrevious(pNodeBase, NULL); - - if(pNodeBeforeLast != pNodeBase) - { - SListNodeBase* const pPosition = pNode->mpNext; - pNode->mpNext = pNodeBase->mpNext; - pNodeBase->mpNext = NULL; - pNodeBeforeLast->mpNext = pPosition; - } - } - - inline SListNodeBase* SListNodeReverse(SListNodeBase* pNode) - { - SListNodeBase* pNodeFirst = pNode; - pNode = pNode->mpNext; - pNodeFirst->mpNext = NULL; - - while(pNode) - { - SListNodeBase* const pTemp = pNode->mpNext; - pNode->mpNext = pNodeFirst; - pNodeFirst = pNode; - pNode = pTemp; - } - return pNodeFirst; - } - - inline uint32_t SListNodeGetSize(SListNodeBase* pNode) - { - uint32_t n = 0; - while(pNode) - { - ++n; - pNode = pNode->mpNext; - } - return n; - } - - - - - /////////////////////////////////////////////////////////////////////// - // SListIterator functions - /////////////////////////////////////////////////////////////////////// - - template <typename T, typename Pointer, typename Reference> - inline SListIterator<T, Pointer, Reference>::SListIterator() - : mpNode(NULL) - { - // Empty - } - - - template <typename T, typename Pointer, typename Reference> - inline SListIterator<T, Pointer, Reference>::SListIterator(const SListNodeBase* pNode) - : mpNode(static_cast<node_type*>((SListNode<T>*)const_cast<SListNodeBase*>(pNode))) // All this casting is in the name of making runtime debugging much easier on the user. - { - // Empty - } - - - template <typename T, typename Pointer, typename Reference> - inline SListIterator<T, Pointer, Reference>::SListIterator(const iterator& x) - : mpNode(const_cast<node_type*>(x.mpNode)) - { - // Empty - } - - - template <typename T, typename Pointer, typename Reference> - inline typename SListIterator<T, Pointer, Reference>::reference - SListIterator<T, Pointer, Reference>::operator*() const - { - return mpNode->mValue; - } - - - template <typename T, typename Pointer, typename Reference> - inline typename SListIterator<T, Pointer, Reference>::pointer - SListIterator<T, Pointer, Reference>::operator->() const - { - return &mpNode->mValue; - } - - - template <typename T, typename Pointer, typename Reference> - inline typename SListIterator<T, Pointer, Reference>::this_type& - SListIterator<T, Pointer, Reference>::operator++() - { - mpNode = static_cast<node_type*>(mpNode->mpNext); - return *this; - } - - - template <typename T, typename Pointer, typename Reference> - inline typename SListIterator<T, Pointer, Reference>::this_type - SListIterator<T, Pointer, Reference>::operator++(int) - { - this_type temp(*this); - mpNode = static_cast<node_type*>(mpNode->mpNext); - return temp; - } - - // The C++ defect report #179 requires that we support comparisons between const and non-const iterators. - // Thus we provide additional template paremeters here to support this. The defect report does not - // require us to support comparisons between reverse_iterators and const_reverse_iterators. - template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB> - inline bool operator==(const SListIterator<T, PointerA, ReferenceA>& a, - const SListIterator<T, PointerB, ReferenceB>& b) - { - return a.mpNode == b.mpNode; - } - - - template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB> - inline bool operator!=(const SListIterator<T, PointerA, ReferenceA>& a, - const SListIterator<T, PointerB, ReferenceB>& b) - { - return a.mpNode != b.mpNode; - } - - - // We provide a version of operator!= for the case where the iterators are of the - // same type. This helps prevent ambiguity errors in the presence of rel_ops. - template <typename T, typename Pointer, typename Reference> - inline bool operator!=(const SListIterator<T, Pointer, Reference>& a, - const SListIterator<T, Pointer, Reference>& b) - { - return a.mpNode != b.mpNode; - } - - - - - - /////////////////////////////////////////////////////////////////////// - // SListBase functions - /////////////////////////////////////////////////////////////////////// - - template <typename T, typename Allocator> - inline SListBase<T, Allocator>::SListBase() - : mNodeAllocator(base_node_type(), allocator_type(EASTL_SLIST_DEFAULT_NAME)) - #if EASTL_SLIST_SIZE_CACHE - , mSize(0) - #endif - { - internalNode().mpNext = NULL; - } - - - template <typename T, typename Allocator> - inline SListBase<T, Allocator>::SListBase(const allocator_type& allocator) - : mNodeAllocator(base_node_type(), allocator) - #if EASTL_SLIST_SIZE_CACHE - , mSize(0) - #endif - { - internalNode().mpNext = NULL; - } - - - template <typename T, typename Allocator> - inline SListBase<T, Allocator>::~SListBase() - { - DoEraseAfter((SListNodeBase*)&internalNode(), NULL); - } - - - template <typename T, typename Allocator> - inline const typename SListBase<T, Allocator>::allocator_type& - SListBase<T, Allocator>::get_allocator() const EA_NOEXCEPT - { - return internalAllocator(); - } - - - template <typename T, typename Allocator> - inline typename SListBase<T, Allocator>::allocator_type& - SListBase<T, Allocator>::get_allocator() EA_NOEXCEPT - { - return internalAllocator(); - } - - - template <typename T, typename Allocator> - void - SListBase<T, Allocator>::set_allocator(const allocator_type& allocator) - { - EASTL_ASSERT((internalAllocator() == allocator) || (static_cast<node_type*>(internalNode().mpNext) == NULL)); // We can only assign a different allocator if we are empty of elements. - internalAllocator() = allocator; - } - - - template <typename T, typename Allocator> - inline SListNode<T>* SListBase<T, Allocator>::DoAllocateNode() - { - return (node_type*)allocate_memory(internalAllocator(), sizeof(node_type), EASTL_ALIGN_OF(node_type), 0); - } - - - template <typename T, typename Allocator> - inline void SListBase<T, Allocator>::DoFreeNode(node_type* pNode) - { - EASTLFree(internalAllocator(), pNode, sizeof(node_type)); - } - - - template <typename T, typename Allocator> - SListNodeBase* SListBase<T, Allocator>::DoEraseAfter(SListNodeBase* pNode) - { - node_type* const pNodeNext = static_cast<node_type*>((base_node_type*)pNode->mpNext); - SListNodeBase* const pNodeNextNext = (SListNodeBase*)pNodeNext->mpNext; - - pNode->mpNext = pNodeNextNext; - pNodeNext->~node_type(); - DoFreeNode(pNodeNext); - #if EASTL_SLIST_SIZE_CACHE - --mSize; - #endif - return pNodeNextNext; - } - - - template <typename T, typename Allocator> - SListNodeBase* SListBase<T, Allocator>::DoEraseAfter(SListNodeBase* pNode, SListNodeBase* pNodeLast) - { - node_type* pNodeCurrent = static_cast<node_type*>((base_node_type*)pNode->mpNext); - - while(pNodeCurrent != (base_node_type*)pNodeLast) - { - node_type* const pNodeTemp = pNodeCurrent; - pNodeCurrent = static_cast<node_type*>((base_node_type*)pNodeCurrent->mpNext); - pNodeTemp->~node_type(); - DoFreeNode(pNodeTemp); - #if EASTL_SLIST_SIZE_CACHE - --mSize; - #endif - } - pNode->mpNext = pNodeLast; - return pNodeLast; - } - - - - - /////////////////////////////////////////////////////////////////////// - // slist functions - /////////////////////////////////////////////////////////////////////// - - template <typename T, typename Allocator> - inline slist<T, Allocator>::slist() - : base_type() - { - // Empty - } - - - template <typename T, typename Allocator> - inline slist<T, Allocator>::slist(const allocator_type& allocator) - : base_type(allocator) - { - // Empty - } - - - template <typename T, typename Allocator> - inline slist<T, Allocator>::slist(size_type n, const allocator_type& allocator) - : base_type(allocator) - { - DoInsertValuesAfter((SListNodeBase*)&internalNode(), n, value_type()); - } - - - template <typename T, typename Allocator> - inline slist<T, Allocator>::slist(size_type n, const value_type& value, const allocator_type& allocator) - : base_type(allocator) - { - DoInsertValuesAfter((SListNodeBase*)&internalNode(), n, value); - } - - - template <typename T, typename Allocator> - inline slist<T, Allocator>::slist(const slist& x) - : base_type(x.internalAllocator()) - { - DoInsertAfter((SListNodeBase*)&internalNode(), const_iterator((SListNodeBase*)x.internalNode().mpNext), const_iterator(NULL), false_type()); - } - - - template <typename T, typename Allocator> - slist<T, Allocator>::slist(this_type&& x) - : base_type(x.internalAllocator()) - { - swap(x); - } - - template <typename T, typename Allocator> - slist<T, Allocator>::slist(this_type&& x, const allocator_type& allocator) - : base_type(allocator) - { - swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. - } - - - template <typename T, typename Allocator> - inline slist<T, Allocator>::slist(std::initializer_list<value_type> ilist, const allocator_type& allocator) - : base_type(allocator) - { - DoInsertAfter((SListNodeBase*)&internalNode(), ilist.begin(), ilist.end()); - } - - - template <typename T, typename Allocator> - template <typename InputIterator> - inline slist<T, Allocator>::slist(InputIterator first, InputIterator last) - : base_type(EASTL_SLIST_DEFAULT_ALLOCATOR) - { - DoInsertAfter((SListNodeBase*)&internalNode(), first, last); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::begin() EA_NOEXCEPT - { - return iterator((SListNodeBase*)internalNode().mpNext); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::const_iterator - slist<T, Allocator>::begin() const EA_NOEXCEPT - { - return const_iterator((SListNodeBase*)internalNode().mpNext); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::const_iterator - slist<T, Allocator>::cbegin() const EA_NOEXCEPT - { - return const_iterator((SListNodeBase*)internalNode().mpNext); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::end() EA_NOEXCEPT - { - return iterator(NULL); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::const_iterator - slist<T, Allocator>::end() const EA_NOEXCEPT - { - return const_iterator(NULL); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::const_iterator - slist<T, Allocator>::cend() const EA_NOEXCEPT - { - return const_iterator(NULL); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::before_begin() EA_NOEXCEPT - { - return iterator((SListNodeBase*)&internalNode()); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::const_iterator - slist<T, Allocator>::before_begin() const EA_NOEXCEPT - { - return const_iterator((SListNodeBase*)&internalNode()); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::const_iterator - slist<T, Allocator>::cbefore_begin() const EA_NOEXCEPT - { - return const_iterator((SListNodeBase*)&internalNode()); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::previous(const_iterator position) - { - return iterator(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode)); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::const_iterator - slist<T, Allocator>::previous(const_iterator position) const - { - return const_iterator(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode)); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::reference - slist<T, Allocator>::front() - { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(internalNode().mpNext == NULL)) - EASTL_FAIL_MSG("slist::front -- empty container"); - #endif - - EA_ANALYSIS_ASSUME(internalNode().mpNext != NULL); - - return ((node_type*)internalNode().mpNext)->mValue; - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::const_reference - slist<T, Allocator>::front() const - { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(internalNode().mpNext == NULL)) - EASTL_FAIL_MSG("slist::front -- empty container"); - #endif - - EA_ANALYSIS_ASSUME(internalNode().mpNext != NULL); - - return static_cast<node_type*>(internalNode().mpNext)->mValue; - } - - - template <typename T, typename Allocator> - template <class... Args> - void slist<T, Allocator>::emplace_front(Args&&... args) - { - DoInsertValueAfter((SListNodeBase*)&internalNode(), eastl::forward<Args>(args)...); - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::push_front(const value_type& value) - { - SListNodeInsertAfter((SListNodeBase*)&internalNode(), (SListNodeBase*)DoCreateNode(value)); - #if EASTL_SLIST_SIZE_CACHE - ++mSize; - #endif - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::reference - slist<T, Allocator>::push_front() - { - SListNodeInsertAfter((SListNodeBase*)&internalNode(), (SListNodeBase*)DoCreateNode()); - #if EASTL_SLIST_SIZE_CACHE - ++mSize; - #endif - return ((node_type*)internalNode().mpNext)->mValue; // Same as return front(); - } - - template <typename T, typename Allocator> - void slist<T, Allocator>::push_front(value_type&& value) - { - emplace_after(before_begin(), eastl::move(value)); - } - - - template <typename T, typename Allocator> - void slist<T, Allocator>::pop_front() - { - #if EASTL_ASSERT_ENABLED - if(EASTL_UNLIKELY(internalNode().mpNext == NULL)) - EASTL_FAIL_MSG("slist::front -- empty container"); - #endif - - EA_ANALYSIS_ASSUME(internalNode().mpNext != NULL); - - node_type* const pNode = static_cast<node_type*>(internalNode().mpNext); - internalNode().mpNext = pNode->mpNext; - pNode->~node_type(); - DoFreeNode(pNode); - #if EASTL_SLIST_SIZE_CACHE - --mSize; - #endif - } - - - template <typename T, typename Allocator> - typename slist<T, Allocator>::this_type& slist<T, Allocator>::operator=(const this_type& x) - { - if(&x != this) - { - // If (EASTL_ALLOCATOR_COPY_ENABLED == 1) and the current contents are allocated by an - // allocator that's unequal to x's allocator, we need to reallocate our elements with - // our current allocator and reallocate it with x's allocator. If the allocators are - // equal then we can use a more optimal algorithm that doesn't reallocate our elements - // but instead can copy them in place. - - #if EASTL_ALLOCATOR_COPY_ENABLED - bool bSlowerPathwayRequired = (internalAllocator() != x.internalAllocator()); - #else - bool bSlowerPathwayRequired = false; - #endif - - if(bSlowerPathwayRequired) - { - clear(); - - #if EASTL_ALLOCATOR_COPY_ENABLED - internalAllocator() = x.internalAllocator(); - #endif - } - - DoAssign(x.begin(), x.end(), eastl::false_type()); - } - - return *this; - } - - - template <typename T, typename Allocator> - typename slist<T, Allocator>::this_type& slist<T, Allocator>::operator=(this_type&& x) - { - if(this != &x) - { - clear(); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor. - swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy. - } - return *this; - } - - - template <typename T, typename Allocator> - typename slist<T, Allocator>::this_type& slist<T, Allocator>::operator=(std::initializer_list<value_type> ilist) - { - DoAssign(ilist.begin(), ilist.end(), false_type()); - return *this; - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::assign(std::initializer_list<value_type> ilist) - { - DoAssign(ilist.begin(), ilist.end(), false_type()); - } - - - template <typename T, typename Allocator> - template <typename InputIterator> // It turns out that the C++ std::list specifies a two argument - inline void slist<T, Allocator>::assign(InputIterator first, InputIterator last) // version of assign that takes (int size, int value). These are not - { // iterators, so we need to do a template compiler trick to do the right thing. - DoAssign(first, last, is_integral<InputIterator>()); - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::assign(size_type n, const value_type& value) - { - // To do: get rid of DoAssignValues and put its implementation directly here. - DoAssignValues(n, value); - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::swap(this_type& x) - { - if(internalAllocator() == x.internalAllocator()) // If allocators are equivalent... - DoSwap(x); - else // else swap the contents. - { - const this_type temp(*this); // Can't call eastl::swap because that would - *this = x; // itself call this member swap function. - x = temp; - } - } - - - template <typename T, typename Allocator> - inline bool slist<T, Allocator>::empty() const EA_NOEXCEPT - { - return internalNode().mpNext == NULL; - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::size_type - slist<T, Allocator>::size() const EA_NOEXCEPT - { - return SListNodeGetSize((SListNodeBase*)internalNode().mpNext); - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::clear() EA_NOEXCEPT - { - DoEraseAfter((SListNodeBase*)&internalNode(), NULL); - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::reset_lose_memory() EA_NOEXCEPT - { - // The reset function is a special extension function which unilaterally - // resets the container to an empty state without freeing the memory of - // the contained objects. This is useful for very quickly tearing down a - // container built into scratch memory. - internalNode().mpNext = NULL; - #if EASTL_SLIST_SIZE_CACHE - mSize = 0; - #endif - } - - - template <typename T, typename Allocator> - void slist<T, Allocator>::resize(size_type n, const value_type& value) - { - SListNodeBase* pNode = (SListNodeBase*)&internalNode(); - - for(; pNode->mpNext && (n > 0); --n) - pNode = pNode->mpNext; - - if(pNode->mpNext) - DoEraseAfter(pNode, NULL); - else - DoInsertValuesAfter(pNode, n, value); - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::resize(size_type n) - { - resize(n, value_type()); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::insert(const_iterator position) - { - return iterator((SListNodeBase*)DoInsertValueAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), value_type())); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::insert(const_iterator position, const value_type& value) - { - return iterator((SListNodeBase*)DoInsertValueAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), value)); - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::insert(const_iterator position, size_type n, const value_type& value) - { - // To do: get rid of DoAssignValues and put its implementation directly here. - DoInsertValuesAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), n, value); - } - - - template <typename T, typename Allocator> - template <typename InputIterator> - inline void slist<T, Allocator>::insert(const_iterator position, InputIterator first, InputIterator last) - { - DoInsertAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), first, last); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::insert_after(const_iterator position) - { - return insert_after(position, value_type()); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::insert_after(const_iterator position, const value_type& value) - { - return iterator((SListNodeBase*)DoInsertValueAfter((SListNodeBase*)position.mpNode, value)); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::insert_after(const_iterator position, size_type n, const value_type& value) - { - return iterator((SListNodeBase*)DoInsertValuesAfter((SListNodeBase*)position.mpNode, n, value)); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::insert_after(const_iterator position, std::initializer_list<value_type> ilist) - { - return iterator((SListNodeBase*)DoInsertAfter((SListNodeBase*)position.mpNode, ilist.begin(), ilist.end(), false_type())); - } - - - template <typename T, typename Allocator> - template <typename InputIterator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::insert_after(const_iterator position, InputIterator first, InputIterator last) - { - return iterator((SListNodeBase*)DoInsertAfter((SListNodeBase*)position.mpNode, first, last)); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::insert_after(const_iterator position, value_type&& value) - { - return emplace_after(position, eastl::move(value)); - } - - - template <typename T, typename Allocator> - template <class... Args> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::emplace_after(const_iterator position, Args&&... args) - { - return iterator((SListNodeBase*)DoInsertValueAfter(position.mpNode, eastl::forward<Args>(args)...)); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::erase(const_iterator position) - { - return DoEraseAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode)); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::erase(const_iterator first, const_iterator last) - { - return DoEraseAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)first.mpNode), (SListNodeBase*)last.mpNode); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::erase_after(const_iterator position) - { - return iterator(DoEraseAfter((SListNodeBase*)position.mpNode)); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::iterator - slist<T, Allocator>::erase_after(const_iterator before_first, const_iterator last) - { - return iterator(DoEraseAfter((SListNodeBase*)before_first.mpNode, (SListNodeBase*)last.mpNode)); - } - - - template <typename T, typename Allocator> - typename slist<T, Allocator>::size_type slist<T, Allocator>::remove(const value_type& value) - { - base_node_type* pNode = &internalNode(); - size_type numErased = 0; - - while(pNode && pNode->mpNext) - { - if (static_cast<node_type*>(pNode->mpNext)->mValue == value) - { - DoEraseAfter((SListNodeBase*)pNode); // This will take care of modifying pNode->mpNext. - ++numErased; - } - else - pNode = pNode->mpNext; - } - return numErased; - } - - template <typename T, typename Allocator> - template <typename Predicate> - inline typename slist<T, Allocator>::size_type slist<T, Allocator>::remove_if(Predicate predicate) - { - base_node_type* pNode = &internalNode(); - size_type numErased = 0; - - while(pNode && pNode->mpNext) - { - if (predicate(static_cast<node_type*>(pNode->mpNext)->mValue)) - { - DoEraseAfter((SListNodeBase*)pNode); // This will take care of modifying pNode->mpNext. - ++numErased; - } - else - pNode = pNode->mpNext; - } - return numErased; - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice(const_iterator position, this_type& x) - { - // Splicing operations cannot succeed if the two containers use unequal allocators. - // This issue is not addressed in the C++ 1998 standard but is discussed in the - // LWG defect reports, such as #431. There is no simple solution to this problem. - // One option is to throw an exception. Another option which probably captures the - // user intent most of the time is to copy the range from the source to the dest and - // remove it from the source. Until then it's simply disallowed to splice with unequal allocators. - // EASTL_ASSERT(internalAllocator() == x.internalAllocator()); // Disabled because our member sort function uses splice but with allocators that may be unequal. There isn't a simple workaround aside from disabling this assert. - - if(x.internalNode().mpNext) // If there is anything to splice... - { - if(internalAllocator() == x.internalAllocator()) - { - SListNodeSpliceAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), - (SListNodeBase*)&x.internalNode(), - SListNodeGetPrevious((SListNodeBase*)&x.internalNode(), NULL)); - - #if EASTL_SLIST_SIZE_CACHE - mSize += x.mSize; - x.mSize = 0; - #endif - } - else - { - insert(position, x.begin(), x.end()); - x.clear(); - } - } - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice(const_iterator position, this_type& x, const_iterator i) - { - if(internalAllocator() == x.internalAllocator()) - { - SListNodeSpliceAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), - SListNodeGetPrevious((SListNodeBase*)&x.internalNode(), (SListNodeBase*)i.mpNode), - (SListNodeBase*)i.mpNode); - - #if EASTL_SLIST_SIZE_CACHE - ++mSize; - --x.mSize; - #endif - } - else - { - insert(position, *i); - x.erase(i); - } - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice(const_iterator position, this_type& x, const_iterator first, const_iterator last) - { - if(first != last) // If there is anything to splice... - { - if(internalAllocator() == x.internalAllocator()) - { - #if EASTL_SLIST_SIZE_CACHE - const size_type n = (size_type)eastl::distance(first, last); - mSize += n; - x.mSize -= n; - #endif - - SListNodeSpliceAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), - SListNodeGetPrevious((SListNodeBase*)&x.internalNode(), (SListNodeBase*)first.mpNode), - SListNodeGetPrevious((SListNodeBase*)first.mpNode, (SListNodeBase*)last.mpNode)); - } - else - { - insert(position, first, last); - x.erase(first, last); - } - } - } - - - template <typename T, typename Allocator> - void slist<T, Allocator>::splice(const_iterator position, this_type&& x) - { - return splice(position, x); // This will splice(const_iterator, this_type&) - } - - template <typename T, typename Allocator> - void slist<T, Allocator>::splice(const_iterator position, this_type&& x, const_iterator i) - { - return splice(position, x, i); // This will splice_after(const_iterator, this_type&, const_iterator) - } - - template <typename T, typename Allocator> - void slist<T, Allocator>::splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last) - { - return splice(position, x, first, last); // This will splice(const_iterator, this_type&, const_iterator, const_iterator) - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice_after(const_iterator position, this_type& x) - { - if(!x.empty()) // If there is anything to splice... - { - if(internalAllocator() == x.internalAllocator()) - { - SListNodeSpliceAfter((SListNodeBase*)position.mpNode, (SListNodeBase*)&x.internalNode()); - - #if EASTL_SLIST_SIZE_CACHE - mSize += x.mSize; - x.mSize = 0; - #endif - } - else - { - insert_after(position, x.begin(), x.end()); - x.clear(); - } - } - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice_after(const_iterator position, this_type& x, const_iterator i) - { - if(internalAllocator() == x.internalAllocator()) - { - SListNodeSpliceAfter((SListNodeBase*)position.mpNode, (SListNodeBase*)i.mpNode); - - #if EASTL_SLIST_SIZE_CACHE - mSize++; - x.mSize--; - #endif - } - else - { - const_iterator iNext(i); - insert_after(position, i, ++iNext); - x.erase(i); - } - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice_after(const_iterator position, this_type& x, const_iterator first, const_iterator last) - { - if(first != last) // If there is anything to splice... - { - if(internalAllocator() == x.internalAllocator()) - { - #if EASTL_SLIST_SIZE_CACHE - const size_type n = (size_type)eastl::distance(first, last); - mSize += n; - x.mSize -= n; - #endif - - SListNodeSpliceAfter((SListNodeBase*)position.mpNode, (SListNodeBase*)first.mpNode, (SListNodeBase*)last.mpNode); - } - else - { - insert_after(position, first, last); - x.erase(first, last); - } - } - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice_after(const_iterator position, this_type&& x) - { - return splice_after(position, x); // This will call splice_after(const_iterator, this_type&) - } - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice_after(const_iterator position, this_type&& x, const_iterator i) - { - return splice_after(position, x, i); // This will call splice_after(const_iterator, this_type&, const_iterator) - } - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice_after(const_iterator position, this_type&& x, const_iterator first, const_iterator last) - { - return splice_after(position, x, first, last); // This will call splice_after(const_iterator, this_type&, const_iterator, const_iterator) - } - - - // This function is deprecated. - // We have no way of knowing what the container or allocator for before_first/before_last is. - // Thus this function requires that the iterators come from equivalent allocators. - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice_after(const_iterator position, const_iterator before_first, const_iterator before_last) - { - if(before_first != before_last) // If there is anything to splice... - { - #if EASTL_SLIST_SIZE_CACHE - // We have a problem here because the inserted range may come from *this or - // it may come from some other list. We have no choice but to implement an O(n) - // brute-force search in our list for 'previous'. - - iterator i((SListNodeBase*)&internalNode()); - iterator iEnd(NULL); - - for( ; i != iEnd; ++i) - { - if(i == before_first) - break; - } - - if(i == iEnd) // If the input came from an external range... - mSize += (size_type)eastl::distance(before_first, before_last); // Note that we have no way of knowing how to decrementing the size from the external container, assuming it came from one. - else - { EASTL_FAIL_MSG("slist::splice_after: Impossible to decrement source mSize. Use the other splice_after function instead."); } - #endif - - // Insert the range of [before_first + 1, before_last + 1) after position. - SListNodeSpliceAfter((SListNodeBase*)position.mpNode, (SListNodeBase*)before_first.mpNode, (SListNodeBase*)before_last.mpNode); - } - } - - - // This function is deprecated. - // We have no way of knowing what the container or allocator for previous is. - // Thus this function requires that the iterators come from equivalent allocators. - template <typename T, typename Allocator> - inline void slist<T, Allocator>::splice_after(const_iterator position, const_iterator previous) - { - #if EASTL_SLIST_SIZE_CACHE - // We have a problem here because the inserted range may come from *this or - // it may come from some other list. We have no choice but to implement an O(n) - // brute-force search in our list for 'previous'. - - iterator i((SListNodeBase*)&internalNode()); - iterator iEnd(NULL); - - for( ; i != iEnd; ++i) - { - if(i == previous) - break; - } - - if(i == iEnd) // If the input came from an external range... - ++mSize; // Note that we have no way of knowing how to decrementing the size from the external container, assuming it came from one. - else - { EASTL_FAIL_MSG("slist::splice_after: Impossible to decrement source mSize. Use the other splice_after function instead."); } - #endif - - // Insert the element at previous + 1 after position. - SListNodeSpliceAfter((SListNodeBase*)position.mpNode, (SListNodeBase*)previous.mpNode, (SListNodeBase*)previous.mpNode->mpNext); - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::sort() - { - // To do: look at using a merge sort, which may well be faster. - eastl::comb_sort(begin(), end()); - } - - - template <typename T, typename Allocator> - template <class Compare> - inline void slist<T, Allocator>::sort(Compare compare) - { - // To do: look at using a merge sort, which may well be faster. - eastl::comb_sort(begin(), end(), compare); - } - - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::reverse() EA_NOEXCEPT - { - if(internalNode().mpNext) - internalNode().mpNext = static_cast<node_type*>((base_node_type*)SListNodeReverse((SListNodeBase*)internalNode().mpNext)); - } - - - template <typename T, typename Allocator> - template<typename... Args> - inline typename slist<T, Allocator>::node_type* - slist<T, Allocator>::DoCreateNode(Args&&... args) - { - node_type* const pNode = DoAllocateNode(); // pNode is of type node_type, but it's uninitialized memory. - - #if EASTL_EXCEPTIONS_ENABLED - try - { - ::new((void*)&pNode->mValue) value_type(eastl::forward<Args>(args)...); - } - catch(...) - { - DoFreeNode(pNode); - throw; - } - #else - ::new((void*)&pNode->mValue) value_type(eastl::forward<Args>(args)...); - #endif - - return pNode; - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::node_type* - slist<T, Allocator>::DoCreateNode() - { - node_type* const pNode = DoAllocateNode(); - #if EASTL_EXCEPTIONS_ENABLED - try - { - ::new((void*)&pNode->mValue) value_type(); - } - catch(...) - { - DoFreeNode(pNode); - throw; - } - #else - ::new((void*)&pNode->mValue) value_type(); - #endif - return pNode; - } - - - template <typename T, typename Allocator> - template <typename Integer> - void slist<T, Allocator>::DoAssign(Integer n, Integer value, true_type) - { - DoAssignValues(static_cast<size_type>(n), static_cast<value_type>(value)); - } - - - template <typename T, typename Allocator> - template <typename InputIterator> - void slist<T, Allocator>::DoAssign(InputIterator first, InputIterator last, false_type) - { - base_node_type* pNodePrev = &internalNode(); - node_type* pNode = static_cast<node_type*>(internalNode().mpNext); - - for(; pNode && (first != last); ++first) - { - pNode->mValue = *first; - pNodePrev = pNode; - pNode = static_cast<node_type*>(pNode->mpNext); - } - - if(first == last) - DoEraseAfter((SListNodeBase*)pNodePrev, NULL); - else - DoInsertAfter((SListNodeBase*)pNodePrev, first, last); - } - - - template <typename T, typename Allocator> - void slist<T, Allocator>::DoAssignValues(size_type n, const value_type& value) - { - base_node_type* pNodePrev = &internalNode(); - node_type* pNode = static_cast<node_type*>(internalNode().mpNext); - - for(; pNode && (n > 0); --n) - { - pNode->mValue = value; - pNodePrev = pNode; - pNode = static_cast<node_type*>(pNode->mpNext); - } - - if(n) - DoInsertValuesAfter((SListNodeBase*)pNodePrev, n, value); - else - DoEraseAfter((SListNodeBase*)pNodePrev, NULL); - } - - - template <typename T, typename Allocator> - template <typename InputIterator> - inline typename slist<T, Allocator>::node_type* - slist<T, Allocator>::DoInsertAfter(SListNodeBase* pNode, InputIterator first, InputIterator last) - { - return DoInsertAfter(pNode, first, last, is_integral<InputIterator>()); - } - - - template <typename T, typename Allocator> - template <typename Integer> - inline typename slist<T, Allocator>::node_type* - slist<T, Allocator>::DoInsertAfter(SListNodeBase* pNode, Integer n, Integer value, true_type) - { - return DoInsertValuesAfter(pNode, n, value); - } - - - template <typename T, typename Allocator> - template <typename InputIterator> - inline typename slist<T, Allocator>::node_type* - slist<T, Allocator>::DoInsertAfter(SListNodeBase* pNode, InputIterator first, InputIterator last, false_type) - { - for(; first != last; ++first) - { - pNode = SListNodeInsertAfter((SListNodeBase*)pNode, (SListNodeBase*)DoCreateNode(*first)); - #if EASTL_SLIST_SIZE_CACHE - ++mSize; - #endif - } - - return static_cast<node_type*>((base_node_type*)pNode); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::node_type* - slist<T, Allocator>::DoInsertValueAfter(SListNodeBase* pNode) - { - #if EASTL_SLIST_SIZE_CACHE - pNode = SListNodeInsertAfter((SListNodeBase*)pNode, (SListNodeBase*)DoCreateNode()); - ++mSize; - return static_cast<node_type*>((base_node_type*)pNode); - #else - return static_cast<node_type*>((base_node_type*)SListNodeInsertAfter((SListNodeBase*)pNode, (SListNodeBase*)DoCreateNode())); - #endif - } - - - template <typename T, typename Allocator> - template<typename... Args> - inline typename slist<T, Allocator>::node_type* - slist<T, Allocator>::DoInsertValueAfter(SListNodeBase* pNode, Args&&... args) - { - SListNodeBase* pNodeNew = (SListNodeBase*)DoCreateNode(eastl::forward<Args>(args)...); - pNode = SListNodeInsertAfter(pNode, pNodeNew); - #if EASTL_LIST_SIZE_CACHE - ++mSize; // Increment the size after the node creation because we need to assume an exception can occur in the creation. - #endif - return static_cast<node_type*>((base_node_type*)pNode); - } - - - template <typename T, typename Allocator> - inline typename slist<T, Allocator>::node_type* - slist<T, Allocator>::DoInsertValuesAfter(SListNodeBase* pNode, size_type n, const value_type& value) - { - for(size_type i = 0; i < n; ++i) - { - pNode = SListNodeInsertAfter((SListNodeBase*)pNode, (SListNodeBase*)DoCreateNode(value)); - #if EASTL_SLIST_SIZE_CACHE - ++mSize; // We don't do a single mSize += n at the end because an exception may result in only a partial range insertion. - #endif - } - return static_cast<node_type*>((base_node_type*)pNode); - } - - - template <typename T, typename Allocator> - inline void slist<T, Allocator>::DoSwap(this_type& x) - { - eastl::swap(internalNode().mpNext, x.internalNode().mpNext); - eastl::swap(internalAllocator(), x.internalAllocator()); // We do this even if EASTL_ALLOCATOR_COPY_ENABLED is 0. - #if EASTL_LIST_SIZE_CACHE - eastl::swap(mSize, x.mSize); - #endif - } - - - template <typename T, typename Allocator> - inline bool slist<T, Allocator>::validate() const - { - #if EASTL_SLIST_SIZE_CACHE - size_type n = 0; - - for(const_iterator i(begin()), iEnd(end()); i != iEnd; ++i) - ++n; - - if(n != mSize) - return false; - #endif - - // To do: More validation. - return true; - } - - - template <typename T, typename Allocator> - inline int slist<T, Allocator>::validate_iterator(const_iterator i) const - { - // To do: Come up with a more efficient mechanism of doing this. - - for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp) - { - if(temp == i) - return (isf_valid | isf_current | isf_can_dereference); - } - - if(i == end()) - return (isf_valid | isf_current); - - return isf_none; - } - - - /////////////////////////////////////////////////////////////////////// - // global operators - /////////////////////////////////////////////////////////////////////// - - template <typename T, typename Allocator> - bool operator==(const slist<T, Allocator>& a, const slist<T, Allocator>& b) - { - typename slist<T, Allocator>::const_iterator ia = a.begin(); - typename slist<T, Allocator>::const_iterator ib = b.begin(); - typename slist<T, Allocator>::const_iterator enda = a.end(); - - #if EASTL_SLIST_SIZE_CACHE - if(a.size() == b.size()) - { - while((ia != enda) && (*ia == *ib)) - { - ++ia; - ++ib; - } - return (ia == enda); - } - return false; - #else - typename slist<T, Allocator>::const_iterator endb = b.end(); - - while((ia != enda) && (ib != endb) && (*ia == *ib)) - { - ++ia; - ++ib; - } - return (ia == enda) && (ib == endb); - #endif - } - -#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) - template <typename T, typename Allocator> - inline synth_three_way_result<T> operator<=>(const slist<T, Allocator>& a, const slist<T, Allocator>& b) - { - return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{}); - } -#else - template <typename T, typename Allocator> - inline bool operator<(const slist<T, Allocator>& a, const slist<T, Allocator>& b) - { - return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); - } - - - template <typename T, typename Allocator> - inline bool operator!=(const slist<T, Allocator>& a, const slist<T, Allocator>& b) - { - return !(a == b); - } - - - template <typename T, typename Allocator> - inline bool operator>(const slist<T, Allocator>& a, const slist<T, Allocator>& b) - { - return b < a; - } - - - template <typename T, typename Allocator> - inline bool operator<=(const slist<T, Allocator>& a, const slist<T, Allocator>& b) - { - return !(b < a); - } - - - template <typename T, typename Allocator> - inline bool operator>=(const slist<T, Allocator>& a, const slist<T, Allocator>& b) - { - return !(a < b); - } -#endif - - template <typename T, typename Allocator> - inline void swap(slist<T, Allocator>& a, slist<T, Allocator>& b) - { - a.swap(b); - } - - - /// erase / erase_if - /// - /// https://en.cppreference.com/w/cpp/container/forward_list/erase2 - template <class T, class Allocator, class U> - typename slist<T, Allocator>::size_type erase(slist<T, Allocator>& c, const U& value) - { - // Erases all elements that compare equal to value from the container. - return c.remove(value); - } - - template <class T, class Allocator, class Predicate> - typename slist<T, Allocator>::size_type erase_if(slist<T, Allocator>& c, Predicate predicate) - { - // Erases all elements that satisfy the predicate pred from the container. - return c.remove_if(predicate); - } - - - /// insert_iterator - /// - /// We borrow a trick from SGI STL here and define an insert_iterator - /// specialization for slist. This allows slist insertions to be O(1) - /// instead of O(n/2), due to caching of the previous node. - /// - template <typename T, typename Allocator> - class insert_iterator< slist<T, Allocator> > - { - public: - typedef slist<T, Allocator> Container; - typedef typename Container::const_reference const_reference; - typedef typename Container::iterator iterator_type; - typedef EASTL_ITC_NS::output_iterator_tag iterator_category; - typedef void value_type; - typedef void difference_type; - typedef void pointer; - typedef void reference; - - protected: - Container& container; - iterator_type it; - - public: - insert_iterator(Container& x, iterator_type i) - : container(x) - { - if(i == x.begin()) - it = x.before_begin(); - else - it = x.previous(i); - } - - insert_iterator<Container>& operator=(const_reference value) - { it = container.insert_after(it, value); return *this; } - - insert_iterator<Container>& operator*() - { return *this; } - - insert_iterator<Container>& operator++() - { return *this; } // This is by design. - - insert_iterator<Container>& operator++(int) - { return *this; } // This is by design. - - }; // insert_iterator<slist> - - -} // namespace eastl - -EA_RESTORE_SN_WARNING() - -EA_RESTORE_VC_WARNING(); - - -#endif // Header include guard |