From 76358abd3af065dda7f8335ad2eb415c78c6eaa3 Mon Sep 17 00:00:00 2001
From: Markus Blatt <mblatt@dune-project.org>
Date: Tue, 2 Nov 2004 11:07:28 +0000
Subject: [PATCH] Added a reference counting pointer with test.

[[Imported from SVN: r1014]]
---
 common/smartpointer.hh          | 109 ++++++++++++++++++++++++++++++++
 common/test/.gitignore          |   3 +-
 common/test/Makefile.am         |   4 +-
 common/test/smartpointertest.cc |  51 +++++++++++++++
 4 files changed, 165 insertions(+), 2 deletions(-)
 create mode 100644 common/smartpointer.hh
 create mode 100644 common/test/smartpointertest.cc

diff --git a/common/smartpointer.hh b/common/smartpointer.hh
new file mode 100644
index 000000000..776a2e26e
--- /dev/null
+++ b/common/smartpointer.hh
@@ -0,0 +1,109 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+// $Id$
+
+#ifndef __DUNE_SMARTPOINTER_HH__
+#define __DUNE_SMARTPOINTER_HH__
+
+/**
+ * @file
+ * @brief This file implements the class SmartPointer which is a reference counting
+ * pointer.
+ * @author Markus Blatt
+ */
+namespace Dune {
+
+  /**
+   * @brief A reference counting smart pointer.
+   *
+   * It is designed such that it is usable within a std::vector.
+   * The contained object is destroyed only if there are no more
+   * references to it.
+   */
+  template<class T>
+  class SmartPointer {
+  public:
+    /**
+     * @brief The data type we are a pointer for.
+     *
+     * This has to have a parameterless constructor.
+     */
+    typedef T MemberType;
+
+    /**
+     * @brief Constructs a new smart pointer and allocates the referenced Object.
+     */
+    inline SmartPointer();
+
+    /**
+     * @brief Copy constructor.
+     * @param pointer The object to copy.
+     */
+    inline SmartPointer(const SmartPointer& pointer);
+
+    /**
+     * @brief Destructor.
+     */
+    inline ~SmartPointer();
+
+    inline SmartPointer& operator=(const SmartPointer& pointer);
+
+    inline MemberType& operator*();
+
+    inline MemberType* operator->();
+
+    int count();
+  private:
+    /** @brief The object we reference. */
+    class PointerRep {
+      friend class SmartPointer<MemberType>;
+      /** @brief The number of references. */
+      int count_;
+      /** @brief The representative. */
+      MemberType rep_;
+      /** @brief Constructor. */
+      PointerRep(const MemberType& rep) : count_(1), rep_(rep){}
+    } *rep_;
+  };
+
+  template<class T>
+  inline SmartPointer<T>::SmartPointer(){
+    rep_ = new PointerRep(MemberType());
+  }
+
+  template<class T>
+  inline SmartPointer<T>::SmartPointer(const SmartPointer<T>& other) : rep_(other.rep_){
+    ++(rep_->count_);
+  }
+
+  template<class T>
+  inline SmartPointer<T>& SmartPointer<T>::operator=(const SmartPointer<T>& other){
+    (other.rep_->count_)++;
+    if(--(rep_->count_)<=0) delete rep_;
+    rep_ = other.rep_;
+    return *this;
+  }
+
+  template<class T>
+  inline SmartPointer<T>::~SmartPointer(){
+    if(--(rep_->count_)<=0) {
+      delete rep_;
+    }
+  }
+
+  template<class T>
+  inline T& SmartPointer<T>::operator*(){
+    return rep_->rep_;
+  }
+
+  template<class T>
+  inline T *SmartPointer<T>::operator->(){
+    return &(rep_->rep_);
+  }
+
+  template<class T>
+  inline int SmartPointer<T>::count(){
+    return rep_->count_;
+  }
+}
+#endif
diff --git a/common/test/.gitignore b/common/test/.gitignore
index 31b9864db..ab73500fa 100644
--- a/common/test/.gitignore
+++ b/common/test/.gitignore
@@ -5,4 +5,5 @@ Makefile.in
 semantic.cache
 parsetest
 test-stack
-arraylisttest
\ No newline at end of file
+arraylisttest
+smartpointertest
\ No newline at end of file
diff --git a/common/test/Makefile.am b/common/test/Makefile.am
index f0fd04638..eb1bd5968 100644
--- a/common/test/Makefile.am
+++ b/common/test/Makefile.am
@@ -1,6 +1,6 @@
 # $Id$
 
-TESTPROGS = parsetest test-stack arraylisttest
+TESTPROGS = parsetest test-stack arraylisttest smartpointertest
 
 # which tests to run
 TESTS = $(TESTPROGS)
@@ -15,3 +15,5 @@ parsetest_SOURCES = parsetest.cc
 test_stack_SOURCES = test-stack.cc
 
 arraylisttest_SOURCES = arraylisttest.cc
+
+smartpointertest_SOURCES = smartpointertest.cc
diff --git a/common/test/smartpointertest.cc b/common/test/smartpointertest.cc
new file mode 100644
index 000000000..813ef3752
--- /dev/null
+++ b/common/test/smartpointertest.cc
@@ -0,0 +1,51 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+// $Id$
+
+#include <dune/common/smartpointer.hh>
+#include <iostream>
+#include <vector>
+
+int main(){
+  using namespace Dune;
+  int ret=0;
+  {
+    SmartPointer<double> b;
+    {
+      SmartPointer<double> d(b);
+      *b = 7;
+    }
+    if(b.count()!=1) {
+      std::cout << "Reference count is wrong! "<<__LINE__<<":"<<
+      __FILE__<<std::endl;
+      ret=1;
+    }
+    {
+      SmartPointer<double> c(b);
+
+      if(*b!=*c) {
+        std::cerr<<"References do not match! "<<__LINE__<<":"<<
+        __FILE__<<std::endl;
+        ret=1;
+      }
+      if(b.count()!=2 || c.count()!=2) {
+        std::cout << "Reference count is wrong! "<<__LINE__<<":"<<
+        __FILE__<<std::endl;
+        ret=1;
+      }
+      *b=8;
+      if(*b!=8 || *c!=8) {
+        std::cout<<"Assigning new value failed! "<<__LINE__<<":"<<
+        __FILE__<<std::endl;
+        ret=1;
+      }
+    }
+
+    if(b.count()!=1) {
+      std::cout << "Reference count is wrong! "<<__LINE__<<":"<<
+      __FILE__<<std::endl;
+      ret=1;
+    }
+  }
+  exit(ret);
+}
-- 
GitLab