Files
SingularityViewer/indra/llui/ailist.h
Lirusaito a3c2009a48 Fix GCC 4.8
Thanks Drake
2016-06-24 21:05:54 -04:00

650 lines
18 KiB
C++

/**
* @file ailist.h
* @brief A linked list with iterators that advance when their element is deleted.
*
* Copyright (c) 2013, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution.
*
* CHANGELOG
* and additional copyright holders.
*
* 05/02/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AILIST_H
#define AILIST_H
#include <list>
template<typename T>
class AIList;
template<typename T>
class AIConstListIterator;
/*
* AINode<T>
*
* The actual data stored in a std::list when using AIList<T>.
* T is the template parameter used with AIList.
* count are the number of iterators that currently point to this element.
* dead is 0 or 1, where 1 means that the element was erased from the AIList
* (but not yet from the internal std::list, so that any iterators to it
* are NOT invalidated).
*/
template<typename T>
struct AINode {
T mElement; // The user visual data.
mutable unsigned short count; // Number of iterators pointing to this element.
mutable unsigned short dead; // Whether or not the element is "erased".
AINode(void) : count(0), dead(0) { }
explicit AINode(T const& __val) : mElement(__val), count(0), dead(0) { }
// Equivalence operators.
// __node may not be dead. Dead nodes in the list are "skipped" (obviously), meaning that they are never equal or always unequal.
bool operator==(AINode const& __node) const { llassert(!__node.dead); return mElement == __node.mElement && !dead; }
bool operator!=(AINode const& __node) const { llassert(!__node.dead); return mElement != __node.mElement || dead; }
// Default ordering for sort().
bool operator<(AINode const& __node) const { return mElement < __node.mElement; }
};
/*
* AIListIterator<T>
*
* A non-const iterator to an element of AIList<T>.
*/
template<typename T>
class AIListIterator {
private:
typedef AIListIterator<T> _Self;
typedef std::list<AINode<T> > _Container;
typedef typename _Container::iterator _Iterator;
_Container* mContainer; // A pointer to the associated container, or NULL when (still) singular.
// Note that this code does not allow a container to be destructed while
// any non-end iterators still exist (although that could be legal).
// If an iterator points to end() and the container is destructed then
// this pointer is NOT reset to NULL.
_Iterator mIterator; // Internal iterator to element of mContainer (or singular when mContainer is NULL).
// Increment reference counter for mIterator (if not singular and not end()).
void ref(void)
{
if (mContainer && mContainer->end() != mIterator)
{
// It would be bad a new iterator was created that pointed to a dead element.
// Also, as a sanity check, make sure there aren't a ridiculous number of iterators
// pointing to this element.
llassert(!mIterator->dead && mIterator->count < 100);
++(mIterator->count);
}
}
// Decrement reference counter for mIterator (if not singular and not end()).
// If this was the last iterator pointing to a dead element, then really erase it.
void unref(void)
{
if (mContainer && mContainer->end() != mIterator)
{
llassert(mIterator->count > 0);
if (--(mIterator->count) == 0 && mIterator->dead)
{
mContainer->erase(mIterator);
}
}
}
public:
// Some standard typedefs that have to exist for iterators.
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::iterator_category iterator_category;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
// Construct a singular iterator.
AIListIterator(void) : mContainer(NULL) { }
// Construct an iterator to a given element of std::list. Only for internal use by AIList<T>.
AIListIterator(_Container* __c, _Iterator const& __i) : mContainer(__c), mIterator(__i)
{
llassert(mContainer);
ref();
}
// Copy constructor.
AIListIterator(AIListIterator const& __i) : mContainer(__i.mContainer), mIterator(__i.mIterator)
{
ref();
}
// Destructor.
~AIListIterator()
{
unref();
}
// Assignment operator.
_Self& operator=(_Self const& __x)
{
unref(); // We no longer point to whatever we were pointing.
mContainer = __x.mContainer;
mIterator = __x.mIterator;
llassert(mContainer);
ref(); // We now point an(other) element.
return *this;
}
// Dereference operator.
reference operator*() const
{
// Iterator may not be singular or dead.
llassert(mContainer && !mIterator->dead);
return mIterator->mElement;
}
// Dereference operator.
pointer operator->() const
{
// Iterator may not be singular or dead.
llassert(mContainer && !mIterator->dead);
return &mIterator->mElement;
}
// Pre-increment operator (not being singular is implied).
_Self& operator++()
{
_Iterator cur = mIterator; // Make copy of mIterator.
++cur; // Advance it.
unref(); // We will no longer be pointing to this element. This might invalidate mIterator!
while(cur != mContainer->end() && cur->dead) // Advance till the first non-dead element.
{
++cur;
}
mIterator = cur; // Put result back into mIterator.
ref(); // We are now pointing to a valid element again.
return *this;
}
// Post-increment operator (not being singular is implied).
_Self operator++(int)
{
_Self tmp = *this;
this->operator++();
return tmp;
}
// Pre-decrement operator (not being singular is implied).
_Self& operator--()
{
_Iterator cur = mIterator; // See operator++().
--cur;
unref();
while(cur->dead)
{
--cur;
}
mIterator = cur;
ref();
return *this;
}
// Post-decrement operator (not being singular is implied).
_Self operator--(int)
{
_Self tmp = *this;
this->operator--();
return tmp;
}
// Equivalence operators.
// We allow comparing with dead iterators, because if one of them is not-dead
// then the result is "unequal" anyway, which is probably what you want.
bool operator==(_Self const& __x) const { return mIterator == __x.mIterator; }
bool operator!=(_Self const& __x) const { return mIterator != __x.mIterator; }
friend class AIList<T>;
friend class AIConstListIterator<T>;
template<typename T2> friend bool operator==(AIListIterator<T2> const& __x, AIConstListIterator<T2> const& __y);
template<typename T2> friend bool operator!=(AIListIterator<T2> const& __x, AIConstListIterator<T2> const& __y);
// Return the total number of iterators pointing the element that this iterator is pointing to.
// Unless the iterator points to end, a positive number will be returned since this iterator is
// pointing to the element. If it points to end (or is singular) then 0 is returned.
int count(void) const
{
if (mContainer && mIterator != mContainer->end())
{
return mIterator->count;
}
return 0;
}
};
/*
* AIConstListIterator<T>
*
* A const iterator to an element of AIList<T>.
*
* Because this class is very simular to AIListIterator<T>, see above for detailed comments.
*/
template<typename T>
class AIConstListIterator {
private:
typedef AIConstListIterator<T> _Self;
typedef std::list<AINode<T> > _Container;
typedef typename _Container::iterator _Iterator;
#if LL_LINUX && GCC_VERSION <= 40899
typedef _Iterator _ConstIterator;
#else
typedef typename _Container::const_iterator _ConstIterator;
#endif
typedef AIListIterator<T> iterator;
_Container const* mContainer;
_ConstIterator mConstIterator;
void ref(void)
{
if (mContainer && mContainer->end() != mConstIterator)
{
llassert(mConstIterator->count < 100);
mConstIterator->count++;
}
}
void unref(void)
{
if (mContainer && mContainer->end() != mConstIterator)
{
llassert(mConstIterator->count > 0);
mConstIterator->count--;
if (mConstIterator->count == 0 && mConstIterator->dead)
{
const_cast<_Container*>(mContainer)->erase(mConstIterator);
}
}
}
public:
typedef typename _ConstIterator::difference_type difference_type;
typedef typename _ConstIterator::iterator_category iterator_category;
typedef T value_type;
typedef T const* pointer;
typedef T const& reference;
AIConstListIterator(void) : mContainer(NULL) { }
AIConstListIterator(_Container const* __c, _ConstIterator const& __i) : mContainer(__c), mConstIterator(__i)
{
llassert(mContainer);
ref();
}
// Allow to construct a const_iterator from an iterator.
AIConstListIterator(iterator const& __x) : mContainer(__x.mContainer), mConstIterator(__x.mIterator)
{
ref();
}
AIConstListIterator(AIConstListIterator const& __i) : mContainer(__i.mContainer), mConstIterator(__i.mConstIterator)
{
ref();
}
~AIConstListIterator()
{
unref();
}
_Self& operator=(_Self const& __x)
{
unref();
mContainer = __x.mContainer;
mConstIterator = __x.mConstIterator;
llassert(mContainer);
ref();
return *this;
}
// Allow to assign from a non-const iterator.
_Self& operator=(iterator const& __x)
{
unref();
mContainer = __x.mContainer;
mConstIterator = __x.mIterator;
llassert(mContainer);
ref();
return *this;
}
reference operator*() const
{
llassert(mContainer && !mConstIterator->dead);
return mConstIterator->mElement;
}
pointer operator->() const
{
llassert(mContainer && !mConstIterator->dead);
return &mConstIterator->mElement;
}
_Self& operator++()
{
_ConstIterator cur = mConstIterator;
++cur;
unref();
while(cur != mContainer->end() && cur->dead)
{
++cur;
}
mConstIterator = cur;
ref();
return *this;
}
_Self operator++(int)
{
_Self tmp = *this;
this->operator++();
return tmp;
}
_Self& operator--()
{
_ConstIterator cur = mConstIterator;
--cur;
unref();
while(cur->dead)
{
--cur;
}
mConstIterator = cur;
ref();
return *this;
}
_Self operator--(int)
{
_Self tmp = *this;
this->operator--();
return tmp;
}
bool operator==(_Self const& __x) const { return mConstIterator == __x.mConstIterator; }
bool operator!=(_Self const& __x) const { return mConstIterator != __x.mConstIterator; }
bool operator==(iterator const& __x) const { return mConstIterator == __x.mIterator; }
bool operator!=(iterator const& __x) const { return mConstIterator != __x.mIterator; }
template<typename T2> friend bool operator==(AIListIterator<T2> const& __x, AIConstListIterator<T2> const& __y);
template<typename T2> friend bool operator!=(AIListIterator<T2> const& __x, AIConstListIterator<T2> const& __y);
int count(void) const
{
if (mContainer && mConstIterator != mContainer->end())
{
return mConstIterator->count;
}
return 0;
}
};
template<typename T>
inline bool operator==(AIListIterator<T> const& __x, AIConstListIterator<T> const& __y)
{
return __x.mIterator == __y.mConstIterator;
}
template<typename T>
inline bool operator!=(AIListIterator<T> const& __x, AIConstListIterator<T> const& __y)
{
return __x.mIterator != __y.mConstIterator;
}
/*
* AIList<T>
*
* A linked list that allows elements to be erased while one or more iterators
* are still pointing to that element, after which pre-increment and pre-decrement
* operators still work.
*
* For example:
*
* for (AIList<int>::iterator i = l.begin(); i != l.end(); ++i)
* {
* int x = *i;
* f(i); // Might erase any element of list l.
* // Should not dereference i anymore here (because it might be erased).
* }
*/
template<typename T>
class AIList {
private:
typedef std::list<AINode<T> > _Container;
typedef typename _Container::iterator _Iterator;
typedef typename _Container::const_iterator _ConstIterator;
_Container mContainer;
size_t mSize;
public:
typedef T value_type;
typedef T* pointer;
typedef T const* const_pointer;
typedef T& reference;
typedef T const& const_reference;
typedef AIListIterator<T> iterator;
typedef AIConstListIterator<T> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
// Default constructor. Create an empty list.
AIList(void) : mSize(0) { }
#ifdef LL_DEBUG
// Destructor calls clear() to check if there are no iterators left pointing to this list. Destructing an empty list is trivial.
~AIList() { clear(); }
#endif
// Construct a list with __n elements of __val.
explicit AIList(size_type __n, value_type const& __val = value_type()) : mContainer(__n, AINode<T>(__val)), mSize(__n) { }
// Copy constructor.
AIList(AIList const& __list) : mSize(0)
{
for (_ConstIterator __i = __list.mContainer.begin(); __i != __list.mContainer.end(); ++__i)
{
if (!__i->dead)
{
mContainer.push_back(AINode<T>(__i->mElement));
++mSize;
}
}
}
// Construct a list from the range [__first, __last>.
template<typename _InputIterator>
AIList(_InputIterator __first, _InputIterator __last) : mSize(0)
{
for (_InputIterator __i = __first; __i != __last; ++__i)
{
mContainer.push_back(AINode<T>(*__i));
++mSize;
}
}
// Assign from another list.
AIList& operator=(AIList const& __list)
{
clear();
for (_ConstIterator __i = __list.mContainer.begin(); __i != __list.mContainer.end(); ++__i)
{
if (!__i->dead)
{
mContainer.push_back(AINode<T>(__i->mElement));
++mSize;
}
}
return *this;
}
iterator begin()
{
_Iterator __i = mContainer.begin();
while(__i != mContainer.end() && __i->dead)
{
++__i;
}
return iterator(&mContainer, __i);
}
const_iterator begin() const
{
_Iterator __i = const_cast<_Container&>(mContainer).begin();
while(__i != mContainer.end() && __i->dead)
{
++__i;
}
return const_iterator(&mContainer, __i);
}
iterator end() { return iterator(&mContainer, mContainer.end()); }
const_iterator end() const { return const_iterator(&mContainer, const_cast<_Container&>(mContainer).end()); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
bool empty() const { return mSize == 0; }
size_type size() const { return mSize; }
size_type max_size() const { return mContainer.max_size(); }
reference front() { iterator __i = begin(); return *__i; }
const_reference front() const { const_iterator __i = begin(); return *__i; }
reference back() { iterator __i = end(); --__i; return *__i; }
const_reference back() const { const_iterator __i = end(); --__i; return *__i; }
void push_front(value_type const& __x)
{
mContainer.push_front(AINode<T>(__x));
++mSize;
}
void pop_front()
{
iterator __i = begin();
erase(__i);
}
void push_back(value_type const& __x)
{
mContainer.push_back(AINode<T>(__x));
++mSize;
}
void pop_back()
{
iterator __i = end();
--__i;
erase(__i);
}
iterator insert(iterator __position, value_type const& __x)
{
++mSize;
return iterator(&mContainer, mContainer.insert(__position.mIterator, AINode<T>(__x)));
}
void clear()
{
#ifdef LL_DEBUG
// There should be no iterators left pointing at any element here.
for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i)
{
llassert(__i->count == 0);
}
#endif
mContainer.clear();
mSize = 0;
}
iterator erase(iterator __position)
{
// Mark the element __position points to as being erased.
// Iterator may not be singular, point to end, or be dead already.
// Obviously count must be larger than zero since __position is still pointing to it.
llassert(__position.mContainer == &mContainer && __position.mIterator != mContainer.end() && __position.mIterator->count > 0 && !__position.mIterator->dead);
__position.mIterator->dead = 1;
--mSize;
return ++__position;
}
// Remove all elements, designated by the iterator where, for which *where == __val.
void remove(value_type const& __val)
{
_Iterator const __e = mContainer.end();
for (_Iterator __i = mContainer.begin(); __i != __e;)
{
if (!__i->dead && __i->mElement == __val)
{
--mSize;
if (__i->count == 0)
{
mContainer.erase(__i++);
continue;
}
// Mark the element as being erased.
__i->dead = 1;
}
++__i;
}
}
void sort()
{
#ifdef LL_DEBUG
// There should be no iterators left pointing at any element here.
for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i)
{
llassert(__i->count == 0);
}
#endif
mContainer.sort();
}
template<typename _StrictWeakOrdering>
struct PredWrapper
{
_StrictWeakOrdering mPred;
PredWrapper(_StrictWeakOrdering const& pred) : mPred(pred) { }
bool operator()(AINode<T> const& __x, AINode<T> const& __y) const { return mPred(__x.mElement, __y.mElement); }
};
template<typename _StrictWeakOrdering>
void sort(_StrictWeakOrdering const& pred)
{
#ifdef LL_DEBUG
// There should be no iterators left pointing at any element here.
for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i)
{
llassert(__i->count == 0);
}
#endif
mContainer.sort(PredWrapper<_StrictWeakOrdering>(pred));
}
};
#endif