Skip to content
Snippets Groups Projects
sllist.hh 19.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
    // vi: set et ts=4 sw=2 sts=2:
    
    Oliver Sander's avatar
    Oliver Sander committed
    #ifndef DUNE_SLLIST_HH
    #define DUNE_SLLIST_HH
    
    #include <cassert>
    
    #include "iteratorfacades.hh"
    
    Markus Blatt's avatar
    Markus Blatt committed
    #include <ostream>
    
    Oliver Sander's avatar
    Oliver Sander committed
       * \brief Implements a singly linked list together with
    
       * the necessary iterators.
       * @author Markus Blatt
       */
      template<typename T, class A>
      class SLListIterator;
    
      template<typename T, class A>
      class SLListConstIterator;
    
    
      template<typename T, class A>
      class SLListModifyIterator;
    
    
      /**
       * @brief A single linked list.
       *
    
    Oliver Sander's avatar
    Oliver Sander committed
       * The list is capable of insertions at the front and at
    
       * the end and of removing elements at the front. Those
       * operations require constant time.
       */
      template<typename T, class A=std::allocator<T> >
      class SLList
      {
    
        friend class SLListIterator<T,A>;
        friend class SLListConstIterator<T,A>;
    
      public:
    
    
        /**
         * @brief The size type.
         */
        typedef typename A::size_type size_type;
    
    
        /**
         * @brief The type we store.
         */
        typedef T MemberType;
    
        /**
         * @brief The allocator to use.
         */
        typedef typename A::template rebind<Element>::other Allocator;
    
        /**
         * @brief The mutable iterator of the list.
         */
        typedef SLListIterator<T,A> iterator;
    
        /**
    
         * @brief The constant iterator of the list.
    
         */
        typedef SLListConstIterator<T,A> const_iterator;
    
    
        /**
         * @brief Constructor.
         */
    
        /**
         * @brief Copy constructor with type conversion.
         */
        template<typename T1, typename A1>
        SLList(const SLList<T1,A1>& other);
    
        /**
         * @brief Copy constructor.
         */
        SLList(const SLList<T,A>& other);
    
    
        /**
         * @brief Destructor.
         *
         * Deallocates all elements in the list.
         */
        ~SLList();
    
    
        /**
         * @brief The type of the iterator capable of deletion
         * and insertion.
         */
        typedef SLListModifyIterator<T,A> ModifyIterator;
    
    
        /**
         * @brief Assignment operator.
         */
        SLList<T,A>& operator=(const SLList<T,A>& other);
    
    
    
        /**
         * @brief Add a new entry to the end of the list.
         * @param item The item to add.
         */
        inline void push_back(const MemberType& item);
    
        /**
         * @brief Add a new entry to the beginning of the list.
         * @param item The item to add.
         */
        inline void push_front(const MemberType& item);
    
        /**
         * @brief Remove the first item in the list.
         */
        inline void pop_front();
    
    
        /** @brief Remove all elements from the list. */
    
        inline void clear();
    
        /**
         * @brief Get an iterator pointing to the first
         * element in the list.
         *
         * @return An iterator pointing to the first
         * element or the end if the list is empty.
         */
        inline iterator begin();
    
        /**
         * @brief Get an iterator pointing to the first
         * element in the list.
         *
         * @return An iterator pointing to the first
         * element or the end if the list is empty.
         */
        inline const_iterator begin() const;
    
        /**
         * @brief Get an iterator capable of deleting and
         * inserting elements.
         *
         * @return Modifying iterator positioned at the beginning
         * of the list.
         */
        inline ModifyIterator beginModify();
    
        /**
         * @brief Get an iterator capable of deleting and
         * inserting elements.
         *
         * @return Modifying iterator positioned after the end
         * of the list.
    
        inline ModifyIterator endModify();
    
        /**
         * @brief Get an iterator pointing to the
         * end of the list.
         *
         * @return An iterator pointing to the end.
         */
        inline iterator end();
    
        /**
         * @brief Get an iterator pointing to the
         * end of the list.
         *
         * @return An iterator pointing to the end.
         */
        inline const_iterator end() const;
    
    
        /**
         * @brief Check whether the list is empty.
         *
         * @return True if the list is empty;
         */
        inline bool empty() const;
    
    
    Markus Blatt's avatar
    Markus Blatt committed
        /**
         * @brief Get the number of elements the list
         * contains.
         */
        inline int size() const;
    
    
    Markus Blatt's avatar
    Markus Blatt committed
        bool operator==(const SLList& sl) const;
    
    
        bool operator!=(const SLList& sl) const;
    
    
        struct Element
        {
          /**
           * @brief The next element in the list.
           */
          Element* next_;
          /**
           * @brief The element we hold.
           */
          MemberType item_;
    
    
    Markus Blatt's avatar
     
    Markus Blatt committed
          Element(const MemberType& item, Element* next_=0);
    
    Markus Blatt's avatar
     
    Markus Blatt committed
          ~Element();
    
        /**
         * @brief Delete the next element in the list.
         * @param current Element whose next element should be deleted.
         */
        void deleteNext(Element* current);
    
    
        /**
         * @brief Copy the elements from another list.
         * @param other The other list.
         */
    
        void copyElements(const SLList<T,A>& other);
    
    
        /**
         * @brief Delete the next element in the list.
         *
         * If the template parameter watchForTail is true, it is checked whether
         * the deleted element is the tail and therefore the tail must be updated.
         * @param current Element whose next element should be deleted.
         */
        template<bool watchForTail>
        void deleteNext(Element* current);
        /**
         * @brief Insert an element after another one in the list.
         * @param current The element after which we insert.
         * @param item The item to insert.
         */
        void insertAfter(Element* current, const T& item);
    
        /** @brief Pseudo element before the first entry. */
        Element beforeHead_;
    
        /**
         * @brief Pointer to he last element in the list.
         *
         * If list is empty this will point to beforeHead_
         */
    
        Element* tail_;
    
        /** @brief The allocator we use. */
        Allocator allocator_;
    
    
    Markus Blatt's avatar
    Markus Blatt committed
        /** brief The number of elements the list holds. */
        int size_;
    
      };
    
      /**
       * @brief A mutable iterator for the SLList.
       */
      template<typename T, class A>
      class SLListIterator : public Dune::ForwardIteratorFacade<SLListIterator<T,A>, T, T&, std::size_t>
      {
        friend class SLListConstIterator<T,A>;
    
        friend class SLListModifyIterator<T,A>;
    
        inline SLListIterator(typename SLList<T,A>::Element* item,
    
                              SLList<T,A>* sllist)
          : current_(item), list_(sllist)
    
        inline SLListIterator(const SLListModifyIterator<T,A>& other)
    
          : current_(other.iterator_.current_), list_(other.iterator_.list_)
    
        /**
         * @brief Dereferencing function for the iterator facade.
         * @return A reference to the element at the current position.
         */
        inline T& dereference() const
        {
          return current_->item_;
        }
    
        /**
         * @brief Equality test for the iterator facade.
         * @param other The other iterator to check.
         * @return true If the other iterator is at the same position.
         */
        inline bool equals(const SLListConstIterator<T,A>& other) const
        {
          return current_==other.current_;
        }
    
        /**
         * @brief Equality test for the iterator facade.
         * @param other The other iterator to check.
         * @return true If the other iterator is at the same position.
         */
        inline bool equals(const SLListIterator<T,A>& other) const
        {
          return current_==other.current_;
        }
    
    
        /**
         * @brief Equality test for the iterator facade.
         * @param other The other iterator to check.
         * @return true If the other iterator is at the same position.
         */
        inline bool equals(const SLListModifyIterator<T,A>& other) const
        {
          return current_==other.iterator_.current_;
        }
    
    
        /**
         * @brief Increment function for the iterator facade.
         */
        inline void increment()
        {
          current_ = current_->next_;
        }
    
    
        /**
         * @brief Insert an element in the underlying list after
         * the current position.
         * @param v The value to insert.
         */
        inline void insertAfter(const T& v) const
        {
    
          assert(list_ );
          list_->insertAfter(current_, v);
    
        /**
         * @brief Delete the entry after the current position.
    
         *
         * @warning This will invalidate all iterators positioned at the delete position! Use with care!
    
          assert(list_);
          list_->deleteNext(current_);
    
      private:
        /**  @brief The current element. */
        typename SLList<T,A>::Element* current_;
    
        /** @brief The list we iterate over. */
        SLList<T,A>* list_;
    
      };
    
      /**
       * @brief A constant iterator for the SLList.
       */
      template<class T, class A>
      class SLListConstIterator : public Dune::ForwardIteratorFacade<SLListConstIterator<T,A>, const T, const T&, std::size_t>
      {
        friend class SLListIterator<T,A>;
    
        inline SLListConstIterator()
          : current_(0)
        {}
    
    
        inline SLListConstIterator(typename SLList<T,A>::Element* item)
          : current_(item)
        {}
    
        inline SLListConstIterator(const SLListIterator<T,A>& other)
    
        inline SLListConstIterator(const SLListConstIterator<T,A>& other)
          : current_(other.current_)
        {}
    
    
        inline SLListConstIterator(const SLListModifyIterator<T,A>& other)
          : current_(other.iterator_.current_)
        {}
    
    
        /**
         * @brief Dereferencing function for the facade.
         * @return A reference to the element at the current position.
         */
        inline const T& dereference() const
        {
          return current_->item_;
        }
    
        /**
         * @brief Equality test for the iterator facade.
         * @param other The other iterator to check.
         * @return true If the other iterator is at the same position.
         */
        inline bool equals(const SLListConstIterator<T,A>& other) const
        {
          return current_==other.current_;
        }
    
        /**
         * @brief Increment function for the iterator facade.
         */
        inline void increment()
        {
          current_ = current_->next_;
        }
    
      private:
        /**  @brief The current element. */
        typename SLList<T,A>::Element* current_;
      };
    
    
      /**
       * @brief A mutable iterator for the SLList.
       */
      template<typename T, class A>
    
      class SLListModifyIterator : public Dune::ForwardIteratorFacade<SLListModifyIterator<T,A>, T, T&, std::size_t>
    
      {
        friend class SLListConstIterator<T,A>;
        friend class SLListIterator<T,A>;
      public:
        inline SLListModifyIterator(SLListIterator<T,A> beforeIterator,
    
                                    SLListIterator<T,A> _iterator)
    
          : beforeIterator_(beforeIterator), iterator_(_iterator)
        {}
    
    
        inline SLListModifyIterator(const SLListModifyIterator<T,A>& other)
          : beforeIterator_(other.beforeIterator_), iterator_(other.iterator_)
        {}
    
    
        inline SLListModifyIterator()
          : beforeIterator_(), iterator_()
        {}
    
        /**
         * @brief Dereferencing function for the iterator facade.
         * @return A reference to the element at the current position.
         */
        inline T& dereference() const
        {
    
          return *iterator_;
        }
    
        /**
         * @brief Test whether another iterator is equal.
         * @return true if the other iterator is at the same position as
         * this one.
         */
        inline bool equals(const SLListConstIterator<T,A>& other) const
        {
          return iterator_== other;
        }
    
    
        /**
         * @brief Test whether another iterator is equal.
         * @return true if the other iterator is at the same position as
         * this one.
         */
        inline bool equals(const SLListIterator<T,A>& other) const
        {
          return iterator_== other;
        }
    
    
        /**
         * @brief Test whether another iterator is equal.
         * @return true if the other iterator is at the same position as
         * this one.
         */
        inline bool equals(const SLListModifyIterator<T,A>& other) const
        {
          return iterator_== other.iterator_;
    
        }
    
        /**
         * @brief Increment function for the iterator facade.
         */
        inline void increment()
        {
          ++iterator_;
          ++beforeIterator_;
        }
    
        /**
         * @brief Insert an element at the current position.
         *
         * Starting from the element at the current position all
         * elements will be shifted by one position to the back.
    
         * The iterator will point to the same element as before
         * after the insertion, i.e the number of increments to
         * reach the same position from a begin iterator increases
         * by one.
    
         * This means the inserted element is the one before the one
         * the iterator points to.
         * @param v The value to insert.
         */
        inline void insert(const T& v)
        {
          beforeIterator_.insertAfter(v);
          ++beforeIterator_;
        }
    
        /**
         * @brief Delete the entry at the current position.
         *
         * The iterator will be positioned at the next postion after the
         * deletion
         * @warning This will invalidate all iterators positioned at the delete position! Use with care!
         */
        inline void remove()
        {
          ++iterator_;
          beforeIterator_.deleteNext();
        }
    
      private:
        /** @brief Iterator positioned at the position before the current. */
        SLListIterator<T,A> beforeIterator_;
        /** @brief Iterator positioned at the current position. */
    
        SLListIterator<T,A> iterator_;
    
    } // namespace Dune
    
    namespace std
    {
    
      template<typename T, typename A>
      ostream& operator<<(ostream& os, const Dune::SLList<T,A> sllist)
      {
        typedef typename Dune::SLList<T,A>::const_iterator Iterator;
        Iterator end = sllist.end();
        Iterator current= sllist.begin();
    
        os << "{ ";
    
        if(current!=end) {
          os<<*current<<" ("<<static_cast<const void*>(&(*current))<<")";
          ++current;
    
          for(; current != end; ++current)
            os<<", "<<*current<<" ("<<static_cast<const void*>(&(*current))<<")";
        }
        os<<"} ";
        return os;
      }
    } //namespace std
    
    namespace Dune
    {
    
    
      template<typename T, class A>
    
    Christian Engwer's avatar
    Christian Engwer committed
      SLList<T,A>::Element::Element(const MemberType& item, Element* next)
    
    Markus Blatt's avatar
     
    Markus Blatt committed
        : next_(next), item_(item)
    
      {}
    
      template<typename T, class A>
      SLList<T,A>::Element::Element()
        : next_(0), item_()
    
    Markus Blatt's avatar
     
    Markus Blatt committed
      template<typename T, class A>
      SLList<T,A>::Element::~Element()
      {
        next_=0;
      }
    
    
      template<typename T, class A>
      SLList<T,A>::SLList()
    
        : beforeHead_(), tail_(&beforeHead_), allocator_(), size_(0)
      {
        beforeHead_.next_=0;
        assert(&beforeHead_==tail_);
        assert(tail_->next_==0);
      }
    
    
      template<typename T, class A>
      SLList<T,A>::SLList(const SLList<T,A>& other)
        : beforeHead_(), tail_(&beforeHead_), allocator_(), size_(0)
      {
        copyElements(other);
      }
    
      template<typename T, class A>
      template<typename T1, class A1>
      SLList<T,A>::SLList(const SLList<T1,A1>& other)
        : beforeHead_(), tail_(&beforeHead_), allocator_(), size_(0)
      {
        copyElements(other);
      }
    
      template<typename T, typename A>
    
      void SLList<T,A>::copyElements(const SLList<T,A>& other)
    
      {
        assert(tail_==&beforeHead_);
        assert(size_==0);
        typedef typename SLList<T,A>::const_iterator Iterator;
        Iterator iend = other.end();
        for(Iterator element=other.begin(); element != iend; ++element)
          push_back(*element);
    
        assert(other.size()==size());
      }
    
    
      template<typename T, class A>
      SLList<T,A>::~SLList()
      {
        clear();
      }
    
    Markus Blatt's avatar
    Markus Blatt committed
      template<typename T, class A>
      bool SLList<T,A>::operator==(const SLList& other) const
      {
    
        if(size()!=other.size())
    
    Markus Blatt's avatar
    Markus Blatt committed
          return false;
        for(const_iterator iter=begin(), oiter=other.begin();
            iter != end(); ++iter, ++oiter)
          if(*iter!=*oiter)
            return false;
        return true;
      }
    
      template<typename T, class A>
      bool SLList<T,A>::operator!=(const SLList& other) const
      {
        if(size()==other.size()) {
          for(const_iterator iter=begin(), oiter=other.begin();
              iter != end(); ++iter, ++oiter)
            if(*iter!=*oiter)
              return true;
          return false;
        }else
          return true;
      }
    
      template<typename T, class A>
      SLList<T,A>& SLList<T,A>::operator=(const SLList<T,A>& other)
      {
        clear();
        copyElements(other);
        return *this;
      }
    
    
      template<typename T, class A>
    
    Christian Engwer's avatar
    Christian Engwer committed
      inline void SLList<T,A>::push_back(const MemberType& item)
    
        assert(size_>0 || tail_==&beforeHead_);
    
        tail_->next_ = allocator_.allocate(1, 0);
    
        assert(size_>0 || tail_==&beforeHead_);
    
        tail_ = tail_->next_;
        ::new (static_cast<void*>(&(tail_->item_)))T(item);
        tail_->next_=0;
        assert(tail_->next_==0);
        ++size_;
      }
    
      template<typename T, class A>
      inline void SLList<T,A>::insertAfter(Element* current, const T& item)
      {
        assert(current);
    
    
        bool changeTail = (current == tail_);
    
    
        // Save old next element
        Element* tmp = current->next_;
    
        assert(!changeTail || !tmp);
    
        // Allocate space
        current->next_ = allocator_.allocate(1, 0);
    
        // Use copy constructor to initialize memory
    
    Markus Blatt's avatar
     
    Markus Blatt committed
        allocator_.construct(current->next_, Element(item,tmp));
    
    Markus Blatt's avatar
     
    Markus Blatt committed
        //::new(static_cast<void*>(&(current->next_->item_))) T(item);
    
    
        if(!current->next_->next_) {
          // Update tail
          assert(changeTail);
          tail_ = current->next_;
    
    Markus Blatt's avatar
    Markus Blatt committed
        ++size_;
    
        assert(!tail_->next_);
    
      }
    
      template<typename T, class A>
    
    Christian Engwer's avatar
    Christian Engwer committed
      inline void SLList<T,A>::push_front(const MemberType& item)
    
        if(tail_ == &beforeHead_) {
    
          // list was empty
          beforeHead_.next_ = tail_ = allocator_.allocate(1, 0);
    
          ::new(static_cast<void*>(&beforeHead_.next_->item_))T(item);
    
          Element* added = allocator_.allocate(1, 0);
    
          ::new(static_cast<void*>(&added->item_))T(item);
    
          added->next_=beforeHead_.next_;
          beforeHead_.next_=added;
    
        assert(tail_->next_==0);
    
    Markus Blatt's avatar
    Markus Blatt committed
        ++size_;
    
      template<typename T, class A>
    
      inline void SLList<T,A>::deleteNext(Element* current)
    
        this->template deleteNext<true>(current);
      }
    
      template<typename T, class A>
      template<bool watchForTail>
      inline void SLList<T,A>::deleteNext(Element* current)
      {
        assert(current->next_);
        Element* next = current->next_;
    
    
        if(watchForTail)
          if(next == tail_) {
            // deleting last element changes tail!
            tail_ = current;
          }
    
    
        current->next_ = next->next_;
    
    Markus Blatt's avatar
     
    Markus Blatt committed
        allocator_.destroy(next);
    
        allocator_.deallocate(next, 1);
    
    Markus Blatt's avatar
    Markus Blatt committed
        --size_;
    
        assert(!watchForTail || &beforeHead_ != tail_ || size_==0);
      }
    
      template<typename T, class A>
      inline void SLList<T,A>::pop_front()
      {
        deleteNext(&beforeHead_);
    
      }
    
      template<typename T, class A>
      inline void SLList<T,A>::clear()
      {
    
          this->template deleteNext<false>(&beforeHead_);
    
    
        assert(size_==0);
        // update the tail!
        tail_ = &beforeHead_;
    
      template<typename T, class A>
      inline bool SLList<T,A>::empty() const
      {
    
        return  (&beforeHead_ == tail_);
    
    Markus Blatt's avatar
    Markus Blatt committed
      template<typename T, class A>
      inline int SLList<T,A>::size() const
      {
        return size_;
      }
    
    
      template<typename T, class A>
      inline SLListIterator<T,A> SLList<T,A>::begin()
      {
    
        return iterator(beforeHead_.next_, this);
    
      }
    
      template<typename T, class A>
      inline SLListConstIterator<T,A> SLList<T,A>::begin() const
      {
    
        return const_iterator(beforeHead_.next_);
    
      }
    
      template<typename T, class A>
      inline SLListIterator<T,A> SLList<T,A>::end()
      {
    
      template<typename T, class A>
      inline SLListModifyIterator<T,A> SLList<T,A>::endModify()
      {
    
        return SLListModifyIterator<T,A>(iterator(tail_, this),iterator());
    
      }
    
    
      template<typename T, class A>
      inline SLListModifyIterator<T,A> SLList<T,A>::beginModify()
      {
        return SLListModifyIterator<T,A>(iterator(&beforeHead_, this),
                                         iterator(beforeHead_.next_, this));
      }
    
    
      template<typename T, class A>
      inline SLListConstIterator<T,A> SLList<T,A>::end() const
      {