Files
EASTL/test/packages/EAStdC/include/EAStdC/internal/IntrusiveList.h
T
jeanlemotan 48ab06b1d9 First
2024-07-02 18:10:39 +02:00

707 lines
23 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This is a curtailed version of eastl::intrusive_list.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTDC_INTRUSIVELIST_H
#define EASTDC_INTRUSIVELIST_H
#include <EABase/eabase.h>
EA_DISABLE_ALL_VC_WARNINGS()
#include <stddef.h>
EA_RESTORE_ALL_VC_WARNINGS()
// Disabled because we want to remove our dependence on STL.
//
//#ifdef _MSC_VER
// #pragma warning(push, 0)
//#endif
//#include <iterator>
//#ifdef _MSC_VER
// #pragma warning(pop)
//#endif
namespace EA
{
namespace StdC
{
template <typename Category, typename T, typename Distance = ptrdiff_t,
typename Pointer = T*, typename Reference = T&>
struct iterator
{
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
};
/* Disabled because we want to remove our dependence on STL.
// struct iterator_traits
template <typename Iterator>
struct iterator_traits
{
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
};
template <typename T>
struct iterator_traits<T*>
{
typedef std::random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
template <typename T>
struct iterator_traits<const T*>
{
typedef std::random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
};
/// reverse_iterator
///
/// From the C++ standard:
/// Bidirectional and random access iterators have corresponding reverse
/// iterator adaptors that iterate through the data structure in the
/// opposite direction. They have the same signatures as the corresponding
/// iterators. The fundamental relation between a reverse iterator and its
/// corresponding iterator i is established by the identity:
/// &*(reverse_iterator(i)) == &*(i - 1).
/// This mapping is dictated by the fact that while there is always a pointer
/// past the end of an array, there might not be a valid pointer before the
/// beginning of an array.
///
template <typename Iterator>
class reverse_iterator : public iterator<typename EA::StdC::iterator_traits<Iterator>::iterator_category,
typename EA::StdC::iterator_traits<Iterator>::value_type,
typename EA::StdC::iterator_traits<Iterator>::difference_type,
typename EA::StdC::iterator_traits<Iterator>::pointer,
typename EA::StdC::iterator_traits<Iterator>::reference>
{
public:
typedef Iterator iterator_type;
typedef typename EA::StdC::iterator_traits<Iterator>::pointer pointer;
typedef typename EA::StdC::iterator_traits<Iterator>::reference reference;
typedef typename EA::StdC::iterator_traits<Iterator>::difference_type difference_type;
protected:
Iterator mIterator;
public:
reverse_iterator() // It's important that we construct mIterator, because if Iterator
: mIterator() { } // is a pointer, there's a difference between doing it and not.
explicit reverse_iterator(iterator_type i)
: mIterator(i) { }
reverse_iterator(const reverse_iterator& ri)
: mIterator(ri.mIterator) { }
template <typename U>
reverse_iterator(const reverse_iterator<U>& ri)
: mIterator(ri.base()) { }
// This operator= isn't in the standard, but the the C++
// library working group has tentatively approved it, as it
// allows const and non-const reverse_iterators to interoperate.
template <typename U>
reverse_iterator<Iterator>& operator=(const reverse_iterator<U>& ri)
{ mIterator = ri.base(); return *this; }
iterator_type base() const
{ return mIterator; }
reference operator*() const
{
iterator_type i(mIterator);
return *--i;
}
pointer operator->() const
{ return &(operator*()); }
reverse_iterator& operator++()
{ --mIterator; return *this; }
reverse_iterator operator++(int)
{
reverse_iterator ri(*this);
--mIterator;
return ri;
}
reverse_iterator& operator--()
{ ++mIterator; return *this; }
reverse_iterator operator--(int)
{
reverse_iterator ri(*this);
++mIterator;
return ri;
}
reverse_iterator operator+(difference_type n) const
{ return reverse_iterator(mIterator - n); }
reverse_iterator& operator+=(difference_type n)
{ mIterator -= n; return *this; }
reverse_iterator operator-(difference_type n) const
{ return reverse_iterator(mIterator + n); }
reverse_iterator& operator-=(difference_type n)
{ mIterator += n; return *this; }
reference operator[](difference_type n) const
{ return mIterator[-n - 1]; }
};
*/
/// intrusive_list_node
///
struct intrusive_list_node
{
intrusive_list_node* mpNext;
intrusive_list_node* mpPrev;
};
/// intrusive_list_iterator
///
template <typename T, typename Pointer, typename Reference>
class intrusive_list_iterator
{
public:
typedef intrusive_list_iterator<T, Pointer, Reference> this_type;
typedef intrusive_list_iterator<T, T*, T&> iterator;
typedef intrusive_list_iterator<T, const T*, const T&> const_iterator;
typedef T value_type;
typedef T node_type;
typedef ptrdiff_t difference_type;
typedef Pointer pointer;
typedef Reference reference;
//typedef std::bidirectional_iterator_tag iterator_category;
public:
pointer mpNode; // Needs to be public for operator==() to work
public:
intrusive_list_iterator();
explicit intrusive_list_iterator(pointer pNode); // Note that you can also construct an iterator from T via this, since value_type == node_type.
intrusive_list_iterator(const iterator& x);
reference operator*() const;
pointer operator->() const;
intrusive_list_iterator& operator++();
intrusive_list_iterator& operator--();
intrusive_list_iterator operator++(int);
intrusive_list_iterator operator--(int);
}; // class intrusive_list_iterator
/// intrusive_list_base
///
class intrusive_list_base
{
public:
typedef size_t size_type; // See config.h for the definition of this, which defaults to uint32_t.
typedef ptrdiff_t difference_type;
protected:
intrusive_list_node mAnchor; ///< Sentinel node (end). All data nodes are linked in a ring from this node.
public:
intrusive_list_base();
bool empty() const;
size_t size() const; ///< Returns the number of elements in the list; O(n).
void clear(); ///< Clears the list; O(1). No deallocation occurs.
void pop_front(); ///< Removes an element from the front of the list; O(1). The element must exist, but is not deallocated.
void pop_back(); ///< Removes an element from the back of the list; O(1). The element must exist, but is not deallocated.
}; // class intrusive_list_base
template <typename T = intrusive_list_node>
class intrusive_list : public intrusive_list_base
{
public:
typedef intrusive_list<T> this_type;
typedef intrusive_list_base base_type;
typedef T node_type;
typedef T value_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef intrusive_list_iterator<T, T*, T&> iterator;
typedef intrusive_list_iterator<T, const T*, const T&> const_iterator;
//typedef EA::StdC::reverse_iterator<iterator> reverse_iterator;
//typedef EA::StdC::reverse_iterator<const_iterator> const_reverse_iterator;
public:
intrusive_list(); ///< Creates an empty list.
intrusive_list(const this_type& x); ///< Creates an empty list; ignores the argument.
this_type& operator=(const this_type& x); ///< Clears the list; ignores the argument.
iterator begin(); ///< Returns an iterator pointing to the first element in the list.
const_iterator begin() const; ///< Returns a const_iterator pointing to the first element in the list.
iterator end(); ///< Returns an iterator pointing one-after the last element in the list.
const_iterator end() const; ///< Returns a const_iterator pointing one-after the last element in the list.
//reverse_iterator rbegin(); ///< Returns a reverse_iterator pointing at the end of the list (start of the reverse sequence).
//const_reverse_iterator rbegin() const; ///< Returns a const_reverse_iterator pointing at the end of the list (start of the reverse sequence).
//reverse_iterator rend(); ///< Returns a reverse_iterator pointing at the start of the list (end of the reverse sequence).
//const_reverse_iterator rend() const; ///< Returns a const_reverse_iterator pointing at the start of the list (end of the reverse sequence).
reference front(); ///< Returns a reference to the first element. The list must be empty.
const_reference front() const; ///< Returns a const reference to the first element. The list must be empty.
reference back(); ///< Returns a reference to the last element. The list must be empty.
const_reference back() const; ///< Returns a const reference to the last element. The list must be empty.
void push_front(T& x); ///< Adds an element to the front of the list; O(1). The element is not copied. The element must not be in any other list.
void push_back(T& x); ///< Adds an element to the back of the list; O(1). The element is not copied. The element must not be in any other list.
bool contains(const T& x) const; ///< Returns true if the given element is in the list; O(n). Equivalent to (locate(x) != end()).
iterator locate(T& x); ///< Converts a reference to an object in the list back to an iterator, or returns end() if it is not part of the list. O(n)
const_iterator locate(const T& x) const; ///< Converts a const reference to an object in the list back to a const iterator, or returns end() if it is not part of the list. O(n)
iterator insert(iterator pos, T& x); ///< Inserts an element before the element pointed to by the iterator. O(1)
iterator erase(iterator pos); ///< Erases the element pointed to by the iterator. O(1)
iterator erase(iterator pos, iterator last); ///< Erases elements within the iterator range [pos, last). O(1)
void swap(intrusive_list&); ///< Swaps the contents of two intrusive lists; O(1).
static void remove(T& value); ///< Erases an element from a list; O(1). Note that this is static so you don't need to know which list the element, although it must be in some list.
}; // intrusive_list
///////////////////////////////////////////////////////////////////////
// intrusive_list_iterator
///////////////////////////////////////////////////////////////////////
template <typename T, typename Pointer, typename Reference>
inline intrusive_list_iterator<T, Pointer, Reference>::intrusive_list_iterator()
{
// Empty
}
template <typename T, typename Pointer, typename Reference>
inline intrusive_list_iterator<T, Pointer, Reference>::intrusive_list_iterator(pointer pNode)
: mpNode(pNode)
{
// Empty
}
template <typename T, typename Pointer, typename Reference>
inline intrusive_list_iterator<T, Pointer, Reference>::intrusive_list_iterator(const iterator& x)
: mpNode(x.mpNode)
{
// Empty
}
template <typename T, typename Pointer, typename Reference>
inline typename intrusive_list_iterator<T, Pointer, Reference>::reference
intrusive_list_iterator<T, Pointer, Reference>::operator*() const
{
return *mpNode;
}
template <typename T, typename Pointer, typename Reference>
inline typename intrusive_list_iterator<T, Pointer, Reference>::pointer
intrusive_list_iterator<T, Pointer, Reference>::operator->() const
{
return mpNode;
}
template <typename T, typename Pointer, typename Reference>
inline typename intrusive_list_iterator<T, Pointer, Reference>::this_type&
intrusive_list_iterator<T, Pointer, Reference>::operator++()
{
mpNode = static_cast<node_type*>(mpNode->mpNext);
return *this;
}
template <typename T, typename Pointer, typename Reference>
inline typename intrusive_list_iterator<T, Pointer, Reference>::this_type
intrusive_list_iterator<T, Pointer, Reference>::operator++(int)
{
intrusive_list_iterator it(*this);
mpNode = static_cast<node_type*>(mpNode->mpNext);
return it;
}
template <typename T, typename Pointer, typename Reference>
inline typename intrusive_list_iterator<T, Pointer, Reference>::this_type&
intrusive_list_iterator<T, Pointer, Reference>::operator--()
{
mpNode = static_cast<node_type*>(mpNode->mpPrev);
return *this;
}
template <typename T, typename Pointer, typename Reference>
inline typename intrusive_list_iterator<T, Pointer, Reference>::this_type
intrusive_list_iterator<T, Pointer, Reference>::operator--(int)
{
intrusive_list_iterator it(*this);
mpNode = static_cast<node_type*>(mpNode->mpPrev);
return it;
}
// 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 intrusive_list_iterator<T, PointerA, ReferenceA>& a,
const intrusive_list_iterator<T, PointerB, ReferenceB>& b)
{
return a.mpNode == b.mpNode;
}
template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB>
inline bool operator!=(const intrusive_list_iterator<T, PointerA, ReferenceA>& a,
const intrusive_list_iterator<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 intrusive_list_iterator<T, Pointer, Reference>& a,
const intrusive_list_iterator<T, Pointer, Reference>& b)
{
return a.mpNode != b.mpNode;
}
///////////////////////////////////////////////////////////////////////
// intrusive_list_base
///////////////////////////////////////////////////////////////////////
inline intrusive_list_base::intrusive_list_base()
{
mAnchor.mpNext = mAnchor.mpPrev = &mAnchor;
}
inline bool intrusive_list_base::empty() const
{
return mAnchor.mpPrev == &mAnchor;
}
inline intrusive_list_base::size_type intrusive_list_base::size() const
{
const intrusive_list_node* p = &mAnchor;
size_type n = (size_type)-1;
do {
++n;
p = p->mpNext;
} while(p != &mAnchor);
return n;
}
inline void intrusive_list_base::clear()
{
mAnchor.mpNext = mAnchor.mpPrev = &mAnchor;
}
inline void intrusive_list_base::pop_front()
{
mAnchor.mpNext->mpNext->mpPrev = &mAnchor;
mAnchor.mpNext = mAnchor.mpNext->mpNext;
}
inline void intrusive_list_base::pop_back()
{
mAnchor.mpPrev->mpPrev->mpNext = &mAnchor;
mAnchor.mpPrev = mAnchor.mpPrev->mpPrev;
}
///////////////////////////////////////////////////////////////////////
// intrusive_list
///////////////////////////////////////////////////////////////////////
template <typename T>
inline intrusive_list<T>::intrusive_list()
{
}
template <typename T>
inline intrusive_list<T>::intrusive_list(const this_type& /*x*/)
{
// We intentionally ignore argument x.
}
template <typename T>
inline typename intrusive_list<T>::this_type& intrusive_list<T>::operator=(const this_type& /*x*/)
{
return *this; // We intentionally ignore argument x.
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::begin()
{
return iterator(static_cast<T*>(mAnchor.mpNext));
}
template <typename T>
inline typename intrusive_list<T>::const_iterator intrusive_list<T>::begin() const
{
return const_iterator(static_cast<T*>(mAnchor.mpNext));
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::end()
{
return iterator(static_cast<T*>(&mAnchor));
}
template <typename T>
inline typename intrusive_list<T>::const_iterator intrusive_list<T>::end() const
{
return const_iterator(static_cast<const T*>(&mAnchor));
}
//template <typename T>
//inline typename intrusive_list<T>::reverse_iterator intrusive_list<T>::rbegin()
//{
// return reverse_iterator(iterator(static_cast<T*>(&mAnchor)));
//}
//template <typename T>
//inline typename intrusive_list<T>::const_reverse_iterator intrusive_list<T>::rbegin() const
//{
// return const_reverse_iterator(const_iterator(static_cast<const T*>(&mAnchor)));
//}
//template <typename T>
//inline typename intrusive_list<T>::reverse_iterator intrusive_list<T>::rend()
//{
// return reverse_iterator(iterator(static_cast<T*>(mAnchor.mpNext)));
//}
//template <typename T>
//inline typename intrusive_list<T>::const_reverse_iterator intrusive_list<T>::rend() const
//{
// return const_reverse_iterator(const_iterator(static_cast<const T*>(mAnchor.mpNext)));
//}
template <typename T>
inline typename intrusive_list<T>::reference intrusive_list<T>::front()
{
return *static_cast<T*>(mAnchor.mpNext);
}
template <typename T>
inline typename intrusive_list<T>::const_reference intrusive_list<T>::front() const
{
return *static_cast<const T*>(mAnchor.mpNext);
}
template <typename T>
inline typename intrusive_list<T>::reference intrusive_list<T>::back()
{
return *static_cast<T*>(mAnchor.mpPrev);
}
template <typename T>
inline typename intrusive_list<T>::const_reference intrusive_list<T>::back() const
{
return *static_cast<const T*>(mAnchor.mpPrev);
}
template <typename T>
inline void intrusive_list<T>::push_front(T& x)
{
x.mpNext = mAnchor.mpNext;
x.mpPrev = &mAnchor;
mAnchor.mpNext = &x;
x.mpNext->mpPrev = &x;
}
template <typename T>
inline void intrusive_list<T>::push_back(T& x)
{
x.mpPrev = mAnchor.mpPrev;
x.mpNext = &mAnchor;
mAnchor.mpPrev = &x;
x.mpPrev->mpNext = &x;
}
template <typename T>
inline bool intrusive_list<T>::contains(const T& x) const
{
for(const intrusive_list_node* p = mAnchor.mpNext; p != &mAnchor; p = p->mpNext)
{
if(p == &x)
return true;
}
return false;
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::locate(T& x)
{
for(intrusive_list_node* p = (T*)mAnchor.mpNext; p != &mAnchor; p = p->mpNext)
{
if(p == &x)
return iterator(static_cast<T*>(p));
}
return iterator((T*)&mAnchor);
}
template <typename T>
inline typename intrusive_list<T>::const_iterator intrusive_list<T>::locate(const T& x) const
{
for(const intrusive_list_node* p = mAnchor.mpNext; p != &mAnchor; p = p->mpNext)
{
if(p == &x)
return const_iterator(static_cast<const T*>(p));
}
return const_iterator((T*)&mAnchor);
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::insert(iterator pos, T& x)
{
node_type& next = *pos;
node_type& prev = *static_cast<node_type*>(next.mpPrev);
prev.mpNext = next.mpPrev = &x;
x.mpPrev = &prev;
x.mpNext = &next;
return iterator(&x);
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::erase(iterator pos)
{
node_type& prev = *static_cast<node_type*>(pos.mpNode->mpPrev);
node_type& next = *static_cast<node_type*>(pos.mpNode->mpNext);
prev.mpNext = &next;
next.mpPrev = &prev;
return iterator(&next);
}
template <typename T>
inline typename intrusive_list<T>::iterator intrusive_list<T>::erase(iterator pos, iterator last)
{
node_type& prev = *static_cast<node_type*>(pos.mpNode->mpPrev);
node_type& next = *last.mpNode;
prev.mpNext = &next;
next.mpPrev = &prev;
return last;
}
template <typename T>
void intrusive_list<T>::swap(intrusive_list& x)
{
// swap anchors
const intrusive_list_node temp(mAnchor);
mAnchor = x.mAnchor;
x.mAnchor = temp;
// Fixup node pointers into the anchor, since the addresses of
// the anchors must stay the same with each list.
if(mAnchor.mpNext == &x.mAnchor)
mAnchor.mpNext = mAnchor.mpPrev = &mAnchor;
else
mAnchor.mpNext->mpPrev = mAnchor.mpPrev->mpNext = &mAnchor;
if(x.mAnchor.mpNext == &mAnchor)
x.mAnchor.mpNext = x.mAnchor.mpPrev = &x.mAnchor;
else
x.mAnchor.mpNext->mpPrev = x.mAnchor.mpPrev->mpNext = &x.mAnchor;
}
} // namespace StdC
} // namespace EA
#endif // Header include guard