From af56d927cedf2aa0abd73885ff4ec4c63206d2d7 Mon Sep 17 00:00:00 2001
From: Markus Blatt <mblatt@dune-project.org>
Date: Tue, 16 Nov 2004 14:44:59 +0000
Subject: [PATCH] Added a single linked list. Provided a test for it.

[[Imported from SVN: r1096]]
---
 common/sllist.hh          | 355 ++++++++++++++++++++++++++++++++++++++
 common/test/.gitignore    |   3 +-
 common/test/Makefile.am   |   4 +-
 common/test/sllisttest.cc |  90 ++++++++++
 4 files changed, 450 insertions(+), 2 deletions(-)
 create mode 100644 common/sllist.hh
 create mode 100644 common/test/sllisttest.cc

diff --git a/common/sllist.hh b/common/sllist.hh
new file mode 100644
index 000000000..1ce1d1266
--- /dev/null
+++ b/common/sllist.hh
@@ -0,0 +1,355 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+#ifndef __DUNE__SLLIST_HH__
+#define __DUNE__SLLIST_HH__
+
+#include <memory>
+#include <dune/common/iteratorfacades.hh>
+
+namespace Dune
+{
+  /**
+   * @file
+   * This file implements a single linked list together with
+   * the necessary iterators.
+   * @author Markus Blatt
+   */
+  /**
+   * @addtogroup Common
+   *
+   * @{
+   */
+  template<typename T, class A>
+  class SLListIterator;
+
+  template<typename T, class A>
+  class SLListConstIterator;
+
+  /**
+   * @brief A single linked list.
+   *
+   * The list is capabale 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
+  {
+    class Element;
+    friend class SLListIterator<T,A>;
+    friend class SLListConstIterator<T,A>;
+
+  public:
+
+    /**
+     * @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 mutable iterator of the list.
+     */
+    typedef SLListConstIterator<T,A> const_iterator;
+    SLList();
+
+    /**
+     * @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 the first item in the list.
+     * @return The last item in the list or 0 if the list is empty.
+       /** @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 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;
+
+  private:
+    struct Element
+    {
+      /**
+       * @brief The next element in the list.
+       */
+      Element* next_;
+      /**
+       * @brief The element we hold.
+       */
+      MemberType item_;
+
+      Element(const MemberType& item);
+
+    };
+
+    /** @brief The first element in the list. */
+    Element* head_;
+
+    /** @brief The last element in the list. */
+    Element* tail_;
+
+    /** @brief The allocator we use. */
+    Allocator allocator_;
+
+
+  };
+
+  /**
+   * @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>;
+
+  public:
+    inline SLListIterator(typename SLList<T,A>::Element* item)
+      : current_(item)
+    {}
+
+    /**
+     * @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 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 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>;
+
+  public:
+    inline SLListConstIterator(typename SLList<T,A>::Element* item)
+      : current_(item)
+    {}
+
+    inline SLListConstIterator(const SLListIterator<T,A>& other)
+    {
+      current_=other.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 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 Increment function for the iterator facade.
+     */
+    inline void increment()
+    {
+      current_ = current_->next_;
+    }
+
+  private:
+    /**  @brief The current element. */
+    typename SLList<T,A>::Element* current_;
+  };
+
+
+  template<typename T, class A>
+  SLList<T,A>::Element::Element(const T& item)
+    : item_(item)
+  {}
+
+  template<typename T, class A>
+  SLList<T,A>::SLList()
+    : head_(0), tail_(0), allocator_()
+  {}
+
+  template<typename T, class A>
+  inline void SLList<T,A>::push_back(const T& item)
+  {
+    if(tail_!=0) {
+      tail_->next_ = allocator_.allocate(1);
+      tail_ = tail_->next_;
+      tail_->item_=item;
+      tail_->next_=0;
+    }else{
+      tail_=head_=allocator_.allocate(1);
+      tail_->next_=0;
+      tail_->item_=item;
+    }
+  }
+
+  template<typename T, class A>
+  inline void SLList<T,A>::push_front(const T& item)
+  {
+    if(head_==0) {
+      head_ = tail_ = allocator_.allocate(1);
+      head_->item_=item;
+      head_->next_=0;
+    }else{
+      Element* added = allocator_.allocate(1);
+      added->item_=item;
+      added->next_=head_;
+      head_=added;
+    }
+  }
+
+  template<typename T, class A>
+  inline void SLList<T,A>::pop_front()
+  {
+    assert(head_!=0);
+    Element* tmp = head_;
+    head_=head_->next_;
+    allocator_.destroy(tmp);
+    allocator_.deallocate(tmp, 1);
+  }
+
+  template<typename T, class A>
+  inline void SLList<T,A>::clear()
+  {
+    while(head_) {
+      Element* current = head_;
+      head_=current->next_;
+      allocator_.destroy(current);
+      allocator_.deallocate(current, 1);
+    }
+    tail_ = head_;
+  }
+
+  template<typename T, class A>
+  inline SLListIterator<T,A> SLList<T,A>::begin()
+  {
+    return iterator(head_);
+  }
+
+  template<typename T, class A>
+  inline SLListConstIterator<T,A> SLList<T,A>::begin() const
+  {
+    return const_iterator(head_);
+  }
+
+
+  template<typename T, class A>
+  inline SLListIterator<T,A> SLList<T,A>::end()
+  {
+    return iterator(static_cast<Element*>(0));
+  }
+
+  template<typename T, class A>
+  inline SLListConstIterator<T,A> SLList<T,A>::end() const
+  {
+    return const_iterator(static_cast<Element*>(0));
+  }
+}
+/** @} */
+#endif
diff --git a/common/test/.gitignore b/common/test/.gitignore
index d4d9f5d27..d1a2c7540 100644
--- a/common/test/.gitignore
+++ b/common/test/.gitignore
@@ -7,4 +7,5 @@ parsetest
 test-stack
 arraylisttest
 smartpointertest
-iteratorfacadetest
\ No newline at end of file
+iteratorfacadetest
+sllisttest
\ No newline at end of file
diff --git a/common/test/Makefile.am b/common/test/Makefile.am
index 6f84b63d5..e6fcceab8 100644
--- a/common/test/Makefile.am
+++ b/common/test/Makefile.am
@@ -1,7 +1,7 @@
 # $Id$
 
 TESTPROGS = parsetest test-stack arraylisttest smartpointertest \
-	iteratorfacadetest
+	sllisttest iteratorfacadetest
 
 # which tests to run
 TESTS = $(TESTPROGS)
@@ -13,6 +13,8 @@ check_PROGRAMS = $(TESTPROGS)
 
 parsetest_SOURCES = parsetest.cc
 
+sllisttest_SOURCES = sllisttest.cc
+
 test_stack_SOURCES = test-stack.cc
 
 arraylisttest_SOURCES = arraylisttest.cc
diff --git a/common/test/sllisttest.cc b/common/test/sllisttest.cc
new file mode 100644
index 000000000..ff8a64540
--- /dev/null
+++ b/common/test/sllisttest.cc
@@ -0,0 +1,90 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+#include <dune/common/sllist.hh>
+#include <dune/common/test/iteratortest.hh>
+#include <dune/common/poolallocator.hh>
+#include <iostream>
+
+template<class A>
+void randomizeListBack(Dune::SLList<double,A>& alist){
+  using namespace Dune;
+
+  srand((unsigned)time(0));
+
+  int lowest=0, highest=1000, range=(highest-lowest)+1;
+
+  for(int i=0; i < 10; i++)
+    alist.push_back((range*(rand()/(RAND_MAX+1.0))));
+}
+
+template<class A>
+void randomizeListFront(Dune::SLList<double,A>& alist){
+  using namespace Dune;
+
+  srand((unsigned)time(0));
+
+  int lowest=0, highest=1000, range=(highest-lowest)+1;
+
+  for(int i=0; i < 10; i++)
+    alist.push_back((range*(rand()/(RAND_MAX+1.0))));
+}
+
+int testPushPop(){
+  using namespace Dune;
+  int ret=0;
+
+  Dune::SLList<int,PoolAllocator<int,8*1024-16> > alist;
+
+  if(alist.begin() != alist.end()) {
+    ret++;
+    std::cout<<"For empty list begin and end iterator do not match! "<<__FILE__<<":"<<__LINE__<<std::endl;
+    ret++;
+  }
+
+  alist.push_back(1);
+  if(*(alist.begin())!=1) {
+    std::cout<<"Entry should be 1! Push back failed! "<<__FILE__<<":"<<__LINE__<<std::endl;
+    ret++;
+  }
+
+  alist.push_back(2);
+  if(*(alist.begin())!=1) {
+    ret++;
+    std::cout<<"Entry should be 2! Push back failed! "<<__FILE__<<":"<<__LINE__<<std::endl;
+  }
+
+  alist.push_front(3);
+  if(*(alist.begin())!=3) {
+    ret++;
+    std::cout<<"Entry should be 3! Push front failed! "<<__FILE__<<":"<<__LINE__<<std::endl;
+  }
+
+  alist.pop_front();
+  if(*(alist.begin())!=1) {
+    ret++;
+    std::cout<<"Entry should be 1! Push back failed! "<<__FILE__<<":"<<__LINE__<<std::endl;
+  }
+  return ret;
+}
+
+int main()
+{
+  int ret=0;
+
+  Dune::SLList<double> list;
+  Dune::SLList<double,Dune::PoolAllocator<double, 8*1024-20> > list1;
+
+  randomizeListBack(list1);
+  randomizeListFront(list);
+
+  ret+=testIterator(list);
+  ret+=testIterator(list1);
+  ret+=testPushPop();
+
+  list.clear();
+  list1.clear();
+  randomizeListBack(list);
+  randomizeListFront(list1);
+  exit(ret);
+
+}
-- 
GitLab