Newer
Older
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_ARRAYLIST_HH
#define DUNE_ARRAYLIST_HH
#include "iteratorfacades.hh"
class ArrayListIterator;
* \brief Implements a random-access container that can efficiently change size (similar to std::deque)
*
* This file implements the class ArrayList which behaves like
* dynamically growing array together with
* the class ArrayListIterator which is random access iterator as needed
* by the stl for sorting and other algorithms.
* @author Markus Blatt
*/
* @brief A dynamically growing random access list.
*
* Internally the data is organised in a list of arrays of fixed size.
* Whenever the capacity of the array list is not sufficient a new
* Dune::array is allocated. In contrast to
* std::vector this approach prevents data copying. On the outside
* we provide the same interface as the stl random access containers.
*
* While the concept sounds quite similar to std::deque there are slight
* but crucial differences:
* - In contrast to std:deque the actual implementation (a list of arrays)
* is known. While
* for std::deque there are at least two possible implementations
* (dynamic array or using a double linked list.
* - In contrast to std:deque there is not insert which invalidates iterators
* but our push_back method leaves all iterators valid.
* - Additional functionality lets one delete entries before and at an
* iterator while moving the iterator to the next valid position.
template<class T, int N=100, class A=std::allocator<T> >
* @brief The member type that is stored.
*
* Has to be assignable and has to have an empty constructor.
/**
* @brief Value type for stl compliance.
*/
typedef T value_type;
/**
* @brief The type of a reference to the type we store.
*/
typedef T& reference;
/**
* @brief The type of a const reference to the type we store.
*/
typedef const T& const_reference;
/**
* @brief The type of a pointer to the type we store.
*/
typedef T* pointer;
/**
* @brief The type of a const pointer to the type we store.
*/
typedef const T* const_pointer;
/**
* @brief The number of elements in one chunk of the list.
* This has to be at least one. The default is 100.
*/
chunkSize_ = (N > 0) ? N : 1
};
/**
* @brief A random access iterator.
*/
typedef ArrayListIterator<MemberType,N,A> iterator;
/**
* @brief A constant random access iterator.
*/
typedef ConstArrayListIterator<MemberType,N,A> const_iterator;
/**
* @brief The size type.
*/
typedef std::size_t size_type;
/**
* @brief The difference type.
*/
typedef std::ptrdiff_t difference_type;
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/**
* @brief Get an iterator that is positioned at the first element.
* @return The iterator.
*/
iterator begin();
/**
* @brief Get a random access iterator that is positioned at the
* first element.
* @return The iterator.
*/
const_iterator begin() const;
/**
* @brief Get a random access iterator positioned after the last
* element
*/
iterator end();
/**
* @brief Get a random access iterator positioned after the last
* element
*/
const_iterator end() const;
/**
* @brief Append an entry to the list.
* @param entry The new entry.
*/
inline void push_back(const_reference entry);
/**
* @brief Get the element at specific position.
* @param i The index of the position.
* @return The element at that position.
*/
inline reference operator[](size_type i);
/**
* @brief Get the element at specific position.
* @param i The index of the position.
* @return The element at that position.
*/
inline const_reference operator[](size_type i) const;
* @brief Get the number of elements in the list.
inline size_type size() const;
/**
* @brief Purge the list.
*
* If there are empty chunks at the front all nonempty
* chunks will be moved towards the front and the capacity
* increases.
*/
inline void purge();
/**
* @brief Delete all entries from the list.
*/
inline void clear();
/**
* @brief Constructs an Array list with one chunk.
* @brief The allocators for the smart pointer.
typedef typename A::template rebind<shared_ptr<array<MemberType,chunkSize_> > >::other
/**
* @brief The allocator for the fixed array.
*/
typedef typename A::template rebind<array<MemberType,chunkSize_> >::other
ArrayAllocator;
/**
* @brief The iterator needs access to the private variables.
*/
friend class ArrayListIterator<T,N,A>;
friend class ConstArrayListIterator<T,N,A>;
/** @brief the data chunks of our list. */
std::vector<shared_ptr<array<MemberType,chunkSize_> >,
/** @brief The current data capacity.
* This is the capacity that the list could have theoretically
* with this number of chunks. That is chunks * chunkSize.
* In practice some of the chunks at the beginning might be empty
* (i.e. null pointers in the first start_/chunkSize chunks)
* because of previous calls to eraseToHere.
* start_+size_<=capacity_ holds.
*/
/** @brief The current number of elements in our data structure. */
size_type start_;
/**
* @brief Get the element at specific position.
*
* Index 0 always refers to the first entry in the list
* whether it is erased or not!
* @param i The index of the position.
* @return The element at that position.
*/
inline reference elementAt(size_type i);
/**
* @brief Get the element at specific position.
*
* Index 0 always refers to the first entry in the list
* whether it is erased or not!
* @param i The index of the position.
* @return The element at that position.
*/
inline const_reference elementAt(size_type i) const;
/**
* @brief A random access iterator for the Dune::ArrayList class.
*/
class ArrayListIterator : public RandomAccessIteratorFacade<ArrayListIterator<T,N,A>,
typename A::value_type,
typename A::reference,
typename A::difference_type>
friend class ArrayList<T,N,A>;
friend class ConstArrayListIterator<T,N,A>;
public:
/**
* @brief The member type.
*/
typedef typename A::value_type MemberType;
typedef typename A::difference_type difference_type;
typedef typename A::size_type size_type;
typedef typename A::reference reference;
typedef typename A::const_reference const_reference;
enum
{
/**
* @brief The number of elements in one chunk of the list.
*
* This has to be at least one. The default is 100.
*/
chunkSize_ = (N > 0) ? N : 1
};
/**
* @brief Comares two iterators.
* @return True if the iterators are for the same list and
* at the position.
*/
inline bool equals(const ArrayListIterator<MemberType,N,A>& other) const;
/**
* @brief Comares two iterators.
* @return True if the iterators are for the same list and
* at the position.
*/
inline bool equals(const ConstArrayListIterator<MemberType,N,A>& other) const;
/**
* @brief Increment the iterator.
*/
inline void increment();
/**
* @brief decrement the iterator.
*/
inline void decrement();
/**
* @brief Get the value of the list at an arbitrary position.
* @return The value at that postion.
*/
inline reference elementAt(size_type i) const;
/**
* @brief Access the element at the current position.
* @return The element at the current position.
*/
inline reference dereference() const;
* @brief Erase all entries before the current position
* and the one at the current position.
*
* Afterwards the iterator will be positioned at the next
* unerased entry or the end if the list is empty.
* This does not invalidate any iterators positioned after
* the current position but those positioned at previous ones.
* @return An iterator to the first position after the deleted
* ones or to the end if the list is empty.
/** \todo Please doc me! */
inline size_type position(){return position_;}
/** \todo Please doc me! */
inline void advance(difference_type n);
/** \todo Please doc me! */
inline difference_type distanceTo(const ArrayListIterator<T,N,A>& other) const;
/** \todo Please doc me! */
inline ArrayListIterator<T,N,A>& operator=(const ArrayListIterator<T,N,A>& other);
//! Standard constructor
inline ArrayListIterator() : position_(0)
{}
private:
/**
* @brief Constructor.
* @param list The list we are an iterator for.
* @param position The initial position of the iterator.
*/
inline ArrayListIterator(ArrayList<T,N,A>& arrayList, size_type position);
/**
* @brief The current postion.
*/
size_type position_;
/**
* @brief The list we are an iterator for.
*/
* @brief A constant random access iterator for the Dune::ArrayList class.
: public RandomAccessIteratorFacade<ConstArrayListIterator<T,N,A>,
const typename A::value_type,
typename A::const_reference,
typename A::difference_type>
friend class ArrayList<T,N,A>;
friend class ArrayListIterator<T,N,A>;
public:
/**
* @brief The member type.
*/
typedef typename A::value_type MemberType;
typedef typename A::difference_type difference_type;
typedef typename A::size_type size_type;
typedef typename A::reference reference;
typedef typename A::const_reference const_reference;
/**
* @brief The number of elements in one chunk of the list.
*
* This has to be at least one. The default is 100.
*/
chunkSize_ = (N > 0) ? N : 1
};
/**
* @brief Comares to iterators.
* @return true if the iterators are for the same list and
* at the position.
*/
inline bool equals(const ConstArrayListIterator<MemberType,N,A>& other) const;
/**
* @brief Increment the iterator.
*/
/**
* @brief decrement the iterator.
*/
/** \todo Please doc me! */
inline void advance(difference_type n);
/** \todo Please doc me! */
inline difference_type distanceTo(const ConstArrayListIterator<T,N,A>& other) const;
/**
* @brief Get the value of the list at an arbitrary position.
* @return The value at that postion.
*/
inline const_reference elementAt(size_type i) const;
/**
* @brief Access the element at the current position.
* @return The element at the current position.
*/
inline const_reference dereference() const;
inline const ConstArrayListIterator<T,N,A>& operator=(const ConstArrayListIterator<T,N,A>& other);
inline ConstArrayListIterator() : position_(0)
inline ConstArrayListIterator(const ArrayListIterator<T,N,A>& other);
/**
* @brief Constructor.
* @param list The list we are an iterator for.
* @param position The initial position of the iterator.
*/
inline ConstArrayListIterator(const ArrayList<T,N,A>& arrayList, size_type position);
/**
* @brief The current postion.
*/
size_type position_;
/**
* @brief The list we are an iterator for.
*/
template<class T, int N, class A>
ArrayList<T,N,A>::ArrayList()
: capacity_(0), size_(0), start_(0)
{
chunks_.reserve(100);
}
template<class T, int N, class A>
void ArrayList<T,N,A>::clear(){
capacity_=0;
size_=0;
start_=0;
chunks_.clear();
}
size_t ArrayList<T,N,A>::size() const
void ArrayList<T,N,A>::push_back(const_reference entry)
size_t index=start_+size_;
chunks_.push_back(shared_ptr<array<MemberType,chunkSize_> >(new array<MemberType,chunkSize_>()));
capacity_ += chunkSize_;
}
typename ArrayList<T,N,A>::reference ArrayList<T,N,A>::operator[](size_type i)
typename ArrayList<T,N,A>::const_reference ArrayList<T,N,A>::operator[](size_type i) const
typename ArrayList<T,N,A>::reference ArrayList<T,N,A>::elementAt(size_type i)
{
return chunks_[i/chunkSize_]->operator[](i%chunkSize_);
}
typename ArrayList<T,N,A>::const_reference ArrayList<T,N,A>::elementAt(size_type i) const
template<class T, int N, class A>
ArrayListIterator<T,N,A> ArrayList<T,N,A>::begin()
template<class T, int N, class A>
ConstArrayListIterator<T,N,A> ArrayList<T,N,A>::begin() const
return ConstArrayListIterator<T,N,A>(*this, start_);
template<class T, int N, class A>
ArrayListIterator<T,N,A> ArrayList<T,N,A>::end()
return ArrayListIterator<T,N,A>(*this, start_+size_);
template<class T, int N, class A>
ConstArrayListIterator<T,N,A> ArrayList<T,N,A>::end() const
return ConstArrayListIterator<T,N,A>(*this, start_+size_);
template<class T, int N, class A>
void ArrayList<T,N,A>::purge()
{
// Distance to copy to the left.
size_t distance = start_/chunkSize_;
if(distance>0) {
// Number of chunks with entries in it;
size_t chunks = ((start_%chunkSize_ + size_)/chunkSize_ );
// Copy chunks to the left.
std::copy(chunks_.begin()+distance,
chunks_.begin()+(distance+chunks), chunks_.begin());
// Calculate new parameters
start_ = start_ % chunkSize_;
//capacity += distance * chunkSize_;
}
}
template<class T, int N, class A>
void ArrayListIterator<T,N,A>::advance(difference_type i)
void ConstArrayListIterator<T,N,A>::advance(difference_type i)
template<class T, int N, class A>
bool ArrayListIterator<T,N,A>::equals(const ArrayListIterator<MemberType,N,A>& other) const
{
// Makes only sense if we reference a common list
assert(list_==(other.list_));
return position_==other.position_ ;
template<class T, int N, class A>
bool ArrayListIterator<T,N,A>::equals(const ConstArrayListIterator<MemberType,N,A>& other) const
{
// Makes only sense if we reference a common list
assert(list_==(other.list_));
return position_==other.position_ ;
template<class T, int N, class A>
bool ConstArrayListIterator<T,N,A>::equals(const ConstArrayListIterator<MemberType,N,A>& other) const
// Makes only sense if we reference a common list
return position_==other.position_ ;
}
template<class T, int N, class A>
void ArrayListIterator<T,N,A>::increment()
template<class T, int N, class A>
void ConstArrayListIterator<T,N,A>::increment()
template<class T, int N, class A>
void ArrayListIterator<T,N,A>::decrement()
template<class T, int N, class A>
void ConstArrayListIterator<T,N,A>::decrement()
typename ArrayListIterator<T,N,A>::reference ArrayListIterator<T,N,A>::elementAt(size_type i) const
typename ConstArrayListIterator<T,N,A>::const_reference ConstArrayListIterator<T,N,A>::elementAt(size_type i) const
typename ArrayListIterator<T,N,A>::reference ArrayListIterator<T,N,A>::dereference() const
typename ConstArrayListIterator<T,N,A>::const_reference ConstArrayListIterator<T,N,A>::dereference() const
typename ArrayListIterator<T,N,A>::difference_type ArrayListIterator<T,N,A>::distanceTo(const ArrayListIterator<T,N,A>& other) const
{
// Makes only sense if we reference a common list
assert(list_==(other.list_));
return other.position_ - position_;
typename ConstArrayListIterator<T,N,A>::difference_type ConstArrayListIterator<T,N,A>::distanceTo(const ConstArrayListIterator<T,N,A>& other) const
{
// Makes only sense if we reference a common list
assert(list_==(other.list_));
return other.position_ - position_;
template<class T, int N, class A>
ArrayListIterator<T,N,A>& ArrayListIterator<T,N,A>::operator=(const ArrayListIterator<T,N,A>& other)
{
position_=other.position_;
list_=other.list_;
return *this;
template<class T, int N, class A>
const ConstArrayListIterator<T,N,A>& ConstArrayListIterator<T,N,A>::operator=(const ConstArrayListIterator<T,N,A>& other)
position_=other.position_;
list_=other.list_;
return *this;
}
template<class T, int N, class A>
void ArrayListIterator<T,N,A>::eraseToHere()
size_t posChunkStart = position_ / chunkSize_;
size_t chunks = (position_ - list_->start_ + list_->start_ % chunkSize_)
/ chunkSize_;
list_->start_ = position_;
// Deallocate memory not needed any more.
for(size_t chunk=0; chunk<chunks; chunk++) {
--posChunkStart;
list_->chunks_[posChunkStart].reset();
}
// Capacity stays the same as the chunks before us
// are still there. They null pointers.
assert(list_->start_+list_->size_<=list_->capacity_);
ArrayListIterator<T,N,A>::ArrayListIterator(ArrayList<T,N,A>& arrayList, size_type position)
: position_(position), list_(&arrayList)
{}
ConstArrayListIterator<T,N,A>::ConstArrayListIterator(const ArrayList<T,N,A>& arrayList,
size_type position)
: position_(position), list_(&arrayList)
{}
template<class T, int N, class A>
ConstArrayListIterator<T,N,A>::ConstArrayListIterator(const ArrayListIterator<T,N,A>& other)
: position_(other.position_), list_(other.list_)
{}