/////////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. /////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // This is a small templated list implementation which suffices for our // purposes but is not optimal. It is present in order to avoid dependencies // on external libraries. ///////////////////////////////////////////////////////////////////////////// #ifndef EATHREAD_EATHREAD_LIST_H #define EATHREAD_EATHREAD_LIST_H #include #include #include // size_t, etc. #include #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 EA { namespace Thread { namespace details { /// Default allocator implementation used by the simple_list class template struct ListDefaultAllocatorImpl { template struct rebind { typedef ListDefaultAllocatorImpl other; }; T* construct() { Allocator* pAllocator = GetAllocator(); if(pAllocator) return new(pAllocator->Alloc(sizeof(T))) T; else return new T; } void destroy(T* obj) { Allocator* pAllocator = GetAllocator(); if(pAllocator) { obj->~T(); pAllocator->Free(obj); } else delete obj; } }; } /// Simple version of an STL bidirectional list. /// Implemented to avoid dependency on container implementations. /// /// This implementation has some non-stl standard methods like find. /// template > class simple_list { simple_list(const simple_list&); simple_list& operator=(const simple_list&); protected: struct list_node { T mValue; list_node* mpPrev; list_node* mpNext; }; typedef list_node node_t; typedef typename Allocator::template rebind::other allocator_t; allocator_t mAllocator; node_t* mpNodeHead; node_t* mpNodeTail; size_t mnSize; public: typedef T value_type; //< list value type typedef const T const_value_type; //< constant list value type typedef const T& const_value_ref_type; //< constant reference list value type struct const_iterator; struct iterator; friend struct const_iterator; friend struct iterator; struct const_iterator { friend class simple_list; const_iterator() : mpNode(NULL) { } const_iterator(const const_iterator& rhs) : mpNode(rhs.mpNode) { } const_iterator& operator=(const const_iterator& rhs) { mpNode = rhs.mpNode; return *this; } const T& operator*() const { return mpNode->mValue; } const T* operator->() const { return &**this; } bool operator==(const const_iterator& rhs) const { return rhs.mpNode == mpNode; } bool operator!=(const const_iterator& rhs) const { return rhs.mpNode != mpNode; } const_iterator& operator++() { mpNode = mpNode->mpNext; return *this; } protected: const node_t* mpNode; protected: const_iterator(node_t* pNode) : mpNode(pNode) { } const_iterator& operator=(const node_t* pNode) { mpNode = pNode; return *this; } }; // const_iterator struct iterator : public const_iterator { friend class simple_list; iterator() : const_iterator(){ } iterator(const const_iterator& rhs) : const_iterator(rhs) { } iterator& operator=(const const_iterator& rhs) { *static_cast(this)= rhs; return *this; } T& operator*() const { return const_cast(**static_cast(this)); } T& operator->() const { return const_cast(&**static_cast(this)); } iterator& operator++() { ++(*static_cast(this)); return *this; } protected: iterator(node_t* pNode) : const_iterator(pNode) { } iterator& operator=(node_t* pNode) { const_cast(*this) = pNode; return *this; } }; // iterator simple_list() : mnSize(0) { mpNodeHead = mAllocator.construct(); mpNodeTail = mAllocator.construct(); mpNodeHead->mpNext = mpNodeTail; mpNodeHead->mpPrev = mpNodeTail; mpNodeTail->mpNext = mpNodeHead; mpNodeTail->mpPrev = mpNodeHead; } ~simple_list() { clear(); mAllocator.destroy(mpNodeHead); mAllocator.destroy(mpNodeTail); } bool empty() const { return mpNodeHead->mpNext == mpNodeTail; } void push_back(const T& value) { node_t* const pNode = mAllocator.construct(); pNode->mValue = value; pNode->mpPrev = mpNodeTail->mpPrev; pNode->mpNext = mpNodeTail; pNode->mpPrev->mpNext = pNode; mpNodeTail->mpPrev = pNode; ++mnSize; } void push_front(const T& value) { node_t* const pNode = mAllocator.construct(); pNode->mValue = value; pNode->mpPrev = mpNodeHead; pNode->mpNext = mpNodeHead->mpNext; mpNodeHead->mpNext = pNode; ++mnSize; } void pop_front() { if(!empty()) { node_t* const pNode = mpNodeHead->mpNext; mpNodeHead->mpNext = pNode->mpNext; pNode->mpNext->mpPrev = mpNodeHead; mAllocator.destroy(pNode); --mnSize; } } size_t size() const { return mnSize; } iterator erase(iterator& iter) { if(!empty()) { node_t* const pNext = iter.mpNode->mpNext; iter.mpNode->mpNext->mpPrev = iter.mpNode->mpPrev; iter.mpNode->mpPrev->mpNext = iter.mpNode->mpNext; --mnSize; mAllocator.destroy(const_cast(iter.mpNode)); return pNext; } return end(); } void clear() { if(!empty()) { node_t* pNode = mpNodeHead->mpNext; while(pNode != mpNodeTail) { node_t* const pNext = pNode->mpNext; pNode->mpNext->mpPrev = pNode->mpPrev; pNode->mpPrev->mpNext = pNext; mAllocator.destroy(pNode); pNode = pNext; } mnSize = 0; } } T& front() const { return mpNodeHead->mpNext->mValue; } const const_iterator begin() const { return mpNodeHead->mpNext; } const const_iterator end() const { return mpNodeTail; } /// returns end()if not found iterator find(const T& element) { iterator iter = begin(); while((iter != end()) && !(element == *iter)) ++iter; return iter; } }; // simple_list } // namespace Thread } // namespace EA #endif // EATHREAD_EATHREAD_LIST_H