From a173a4bb77799fbe85a481b427f1a915487b09b9 Mon Sep 17 00:00:00 2001
From: ralfulrich <ralf.ulrich@kit.edu>
Date: Mon, 28 Jan 2019 21:14:30 +0100
Subject: [PATCH] first workin version of testStackInterface

---
 Framework/StackInterface/ParticleBase.h       |  11 +-
 Framework/StackInterface/Stack.h              |  20 ++-
 Framework/StackInterface/StackIterator.h      | 137 +++++++++++++++---
 .../StackInterface/testStackInterface.cc      |  77 ++++++----
 Stack/SuperStupidStack/SuperStupidStack.h     |   3 +
 5 files changed, 199 insertions(+), 49 deletions(-)

diff --git a/Framework/StackInterface/ParticleBase.h b/Framework/StackInterface/ParticleBase.h
index 5ef6ca662..1a854a90b 100644
--- a/Framework/StackInterface/ParticleBase.h
+++ b/Framework/StackInterface/ParticleBase.h
@@ -31,10 +31,15 @@ namespace corsika::stack {
   class ParticleBase {
 
   public:
-    ParticleBase() {}
+    ParticleBase() = default;
 
   private:
-    ParticleBase(ParticleBase&);
+    ParticleBase(ParticleBase&) = delete;
+    ParticleBase operator=(ParticleBase&) = delete;
+    ParticleBase(ParticleBase&&) = delete;
+    ParticleBase operator=(ParticleBase&&) = delete;
+    ParticleBase(const ParticleBase&) = delete;
+    ParticleBase operator=(const ParticleBase&) = delete;
 
   public:
     /// delete this particle on the stack. The corresponding iterator
@@ -52,6 +57,8 @@ namespace corsika::stack {
     /// access to underling stack data
     auto& GetStackData() { return GetIterator().GetStackData(); }
     const auto& GetStackData() const { return GetIterator().GetStackData(); }
+    auto& GetStack() { return GetIterator().GetStack(); }
+    const auto& GetStack() const { return GetIterator().GetStack(); }
 
     /// return the index number of the underlying iterator object
     int GetIndex() const { return GetIterator().GetIndex(); }
diff --git a/Framework/StackInterface/Stack.h b/Framework/StackInterface/Stack.h
index f47c15d3d..9d57b7b3c 100644
--- a/Framework/StackInterface/Stack.h
+++ b/Framework/StackInterface/Stack.h
@@ -14,6 +14,8 @@
 
 #include <corsika/stack/StackIterator.h> // include here, to help application programmres
 
+#include <stdexcept>
+
 /**
    All classes around management of particles on a stack.
  */
@@ -35,9 +37,11 @@ namespace corsika::stack {
   public:
     typedef Stack<StackData, PI> StackType;
     typedef StackIteratorInterface<StackData, PI> StackIterator;
-    typedef const StackIterator ConstStackIterator;
+    typedef ConstStackIteratorInterface<StackData, PI> ConstStackIterator;
+    // typedef const StackIterator ConstStackIterator;
     typedef typename StackIterator::ParticleInterfaceType ParticleType;
     friend class StackIteratorInterface<StackData, PI>;
+    friend class ConstStackIteratorInterface<StackData, PI>;
 
   public:
     using StackData::GetCapacity;
@@ -57,20 +61,28 @@ namespace corsika::stack {
     StackIterator end() { return StackIterator(*this, GetSize()); }
     StackIterator last() { return StackIterator(*this, GetSize() - 1); }
 
-    /// these are functions required by std containers and std loops
+    ConstStackIterator begin() const { return ConstStackIterator(*this, 0); }
+    ConstStackIterator end() const { return ConstStackIterator(*this, GetSize()); }
+    ConstStackIterator last() const { return ConstStackIterator(*this, GetSize() - 1); }
+
     ConstStackIterator cbegin() const { return ConstStackIterator(*this, 0); }
     ConstStackIterator cend() const { return ConstStackIterator(*this, GetSize()); }
     ConstStackIterator clast() const { return ConstStackIterator(*this, GetSize() - 1); }
 
     /// increase stack size, create new particle at end of stack
-    StackIterator NewParticle() {
+    template <typename... Args>
+    StackIterator AddParticle(Args... v) {
       IncrementSize();
-      return StackIterator(*this, GetSize() - 1);
+      return StackIterator(*this, GetSize() - 1, v...);
+      // auto p = StackIterator(*this, GetSize() - 1);
+      // p.SetParticleData(v...);
+      // return p;
     }
     void Copy(StackIterator& a, StackIterator& b) { Copy(a.GetIndex(), b.GetIndex()); }
     /// delete this particle
     void Delete(StackIterator& p) {
       if (GetSize() == 0) { /*error*/
+        throw std::runtime_error("Stack, cannot delete entry since size is zero");
       }
       if (p.GetIndex() < GetSize() - 1) Copy(GetSize() - 1, p.GetIndex());
       DeleteLast();
diff --git a/Framework/StackInterface/StackIterator.h b/Framework/StackInterface/StackIterator.h
index 47424f60d..266492094 100644
--- a/Framework/StackInterface/StackIterator.h
+++ b/Framework/StackInterface/StackIterator.h
@@ -14,6 +14,8 @@
 
 #include <corsika/stack/ParticleBase.h>
 
+#include <type_traits>
+
 class StackData; // forward decl
 
 namespace corsika::stack {
@@ -47,10 +49,15 @@ namespace corsika::stack {
 
   template <typename StackData, template <typename> typename ParticleInterface>
   class StackIteratorInterface
-      : public ParticleInterface<StackIteratorInterface<StackData, ParticleInterface> > {
+      : public ParticleInterface<StackIteratorInterface<
+            StackData /*typename std::decay<StackData>::type*/, ParticleInterface>> {
 
     typedef Stack<StackData, ParticleInterface> StackType;
-    typedef ParticleInterface<StackIteratorInterface<StackData, ParticleInterface> >
+    /*typedef
+        typename std::conditional<std::is_const<StackData>::value,
+                                  const Stack<const StackData, ParticleInterface>&,
+                                  Stack<StackData, ParticleInterface>&>::type StackType;*/
+    typedef ParticleInterface<StackIteratorInterface<StackData, ParticleInterface>>
         ParticleInterfaceType;
 
     // friend class ParticleInterface<StackIterator<StackData>>; // to access GetStackData
@@ -59,24 +66,33 @@ namespace corsika::stack {
 
   private:
     int fIndex = 0;
-    StackType* fData = 0; // todo is this problematic, when stacks are copied?
+    StackType* fData = 0; // info: Particles and StackIterators become invalid when parent
+                          // Stack is copied or deleted!
+
+    StackIteratorInterface() = delete;
 
   public:
-    // StackIterator() : fData(0), fIndex(0) { }
+    /*
+    StackIteratorInterface(const StackType& data, const int index)
+      : fIndex(index)
+      , fData(&data) {}*/
     StackIteratorInterface(StackType& data, const int index)
         : fIndex(index)
         , fData(&data) {}
-
-  private:
-    StackIteratorInterface(const StackIteratorInterface& mit)
-        : fIndex(mit.fIndex)
-        , fData(mit.fData) {}
-
-  public:
-    StackIteratorInterface& operator=(const StackIteratorInterface& mit) {
-      fIndex = mit.fIndex;
-      fData = mit.fData;
-      return *this;
+    /*
+  StackIteratorInterface(StackType& data, const int index, typename
+  std::enable_if<!std::is_const<StackData>::value>::type* = 0) : fIndex(index) ,
+  fData(&data) {}
+
+  StackIteratorInterface(const StackType& data, const int index, typename
+  std::enable_if<std::is_const<StackData>::value>::type* = 0) : fIndex(index) ,
+  fData(&data) {}
+    */
+    template <typename... Args>
+    StackIteratorInterface(StackType& data, const int index, const Args... args)
+        : fIndex(index)
+        , fData(&data) {
+      (**this).SetParticleData(args...);
     }
 
   public:
@@ -103,11 +119,96 @@ namespace corsika::stack {
     int GetIndex() const { return fIndex; }
     StackType& GetStack() { return *fData; }
     const StackType& GetStack() const { return *fData; }
-    StackData& GetStackData() { return fData->GetStackData(); }
-    const StackData& GetStackData() const { return fData->GetStackData(); }
-
+    StackData& /*typename std::decay<StackData>::type&*/ GetStackData() {
+      return fData->GetStackData();
+    }
+    const StackData& /*typename std::decay<StackData>::type&*/ GetStackData() const {
+      return fData->GetStackData();
+    }
   }; // end class StackIterator
 
+  template <typename StackData, template <typename> typename ParticleInterface>
+  class ConstStackIteratorInterface
+      : public ParticleInterface<ConstStackIteratorInterface<
+            StackData /*typename std::decay<StackData>::type*/, ParticleInterface>> {
+
+    typedef Stack<StackData, ParticleInterface> StackType;
+    /*typedef
+        typename std::conditional<std::is_const<StackData>::value,
+                                  const Stack<const StackData, ParticleInterface>&,
+                                  Stack<StackData, ParticleInterface>&>::type StackType;*/
+    typedef ParticleInterface<ConstStackIteratorInterface<StackData, ParticleInterface>>
+        ParticleInterfaceType;
+
+    // friend class ParticleInterface<StackIterator<StackData>>; // to access GetStackData
+    friend class Stack<StackData, ParticleInterface>;       // for access to GetIndex
+    friend class ParticleBase<ConstStackIteratorInterface>; // for access to GetStackData
+
+  private:
+    int fIndex = 0;
+    const StackType* fData = 0; // info: Particles and StackIterators become invalid when
+                                // parent Stack is copied or deleted!
+
+    ConstStackIteratorInterface() = delete;
+
+  public:
+    // StackIteratorInterface(const StackType& data, const int index)
+    //     : fIndex(index)
+    //  , fData(&data) {}
+    ConstStackIteratorInterface(const StackType& data, const int index)
+        : fIndex(index)
+        , fData(&data) {}
+    /*
+  StackIteratorInterface(StackType& data, const int index, typename
+  std::enable_if<!std::is_const<StackData>::value>::type* = 0) : fIndex(index) ,
+  fData(&data) {}
+
+  StackIteratorInterface(const StackType& data, const int index, typename
+  std::enable_if<std::is_const<StackData>::value>::type* = 0) : fIndex(index) ,
+  fData(&data) {}
+    */
+    template <typename... Args>
+    ConstStackIteratorInterface(StackType data, const int index, const Args... args)
+        : fIndex(index)
+        , fData(data) {
+      (**this).SetParticleData(args...);
+    }
+
+  public:
+    ConstStackIteratorInterface& operator++() {
+      ++fIndex;
+      return *this;
+    }
+    ConstStackIteratorInterface operator++(int) {
+      ConstStackIteratorInterface tmp(*this);
+      ++fIndex;
+      return tmp;
+    }
+    bool operator==(const ConstStackIteratorInterface& rhs) {
+      return fIndex == rhs.fIndex;
+    }
+    bool operator!=(const ConstStackIteratorInterface& rhs) {
+      return fIndex != rhs.fIndex;
+    }
+
+    ParticleInterfaceType& operator*() {
+      return static_cast<ParticleInterfaceType&>(*this);
+    }
+    const ParticleInterfaceType& operator*() const {
+      return static_cast<const ParticleInterfaceType&>(*this);
+    }
+
+  protected:
+    int GetIndex() const { return fIndex; }
+    // StackType GetStack() { return *fData; }
+    const StackType& GetStack() const { return *fData; }
+    // StackData& /*typename std::decay<StackData>::type&*/ GetStackData() { return
+    // fData->GetStackData(); }
+    const StackData& /*typename std::decay<StackData>::type&*/ GetStackData() const {
+      return fData->GetStackData();
+    }
+  }; // end class ConstStackIterator
+
 } // namespace corsika::stack
 
 #endif
diff --git a/Framework/StackInterface/testStackInterface.cc b/Framework/StackInterface/testStackInterface.cc
index 078a09407..8e165d5c9 100644
--- a/Framework/StackInterface/testStackInterface.cc
+++ b/Framework/StackInterface/testStackInterface.cc
@@ -23,7 +23,7 @@ using namespace corsika::stack;
 using namespace std;
 
 // definition of stack-data object
-class StackOneData {
+class TestStackData {
 
 public:
   // these functions are needed for the Stack interface
@@ -57,22 +57,38 @@ private:
 // defintion of a stack-readout object, the iteractor dereference
 // operator will deliver access to these function
 template <typename StackIteratorInterface>
-class ParticleInterface : public ParticleBase<StackIteratorInterface> {
-  //  using ParticleBase<StackIteratorInterface>::Delete;
+class TestParticleInterface : public ParticleBase<StackIteratorInterface> {
+  using ParticleBase<StackIteratorInterface>::GetStack;
   using ParticleBase<StackIteratorInterface>::GetStackData;
   using ParticleBase<StackIteratorInterface>::GetIndex;
 
 public:
+  // one version
+  void AddSecondary(const double v) { GetStack().AddParticle(v); }
+  // another version
+  void AddSecondary(const double v, const double p) { GetStack().AddParticle(v + p); }
+
+  void SetParticleData(const double v) { SetData(v); }
+
   void SetData(const double v) { GetStackData().SetData(GetIndex(), v); }
   double GetData() const { return GetStackData().GetData(GetIndex()); }
 };
 
+typedef Stack<TestStackData, TestParticleInterface> StackTest;
+typedef StackTest::ParticleType Particle;
+
 TEST_CASE("Stack", "[Stack]") {
 
+  // helper function for sum over stack data
+  auto sum = [](const StackTest& stack) {
+    double v = 0;
+    for (const auto&& p : stack) v += p.GetData();
+    return v;
+  };
+
   SECTION("StackInterface") {
 
     // construct a valid Stack object
-    typedef Stack<StackOneData, ParticleInterface> StackTest;
     StackTest s;
     s.Init();
     s.Clear();
@@ -85,44 +101,55 @@ TEST_CASE("Stack", "[Stack]") {
     REQUIRE(s.GetSize() == 0);
   }
 
-  SECTION("write") {
+  SECTION("construct") {
 
-    // construct a valid Stack object
-    typedef Stack<StackOneData, ParticleInterface> StackTest;
+    // construct a valid, empty Stack object
     StackTest s;
   }
 
-  SECTION("read") {
+  SECTION("write and read") {
 
-    typedef Stack<StackOneData, ParticleInterface> StackTest;
     StackTest s;
-    s.NewParticle().SetData(9.9);
-    cout << "kk" << endl;
-    double v = 0;
-    for (auto& p : s) {
-      cout << typeid(p).name() << endl;
-      v += p.GetData();
-    }
-    cout << "k222k" << endl;
-
+    s.AddParticle(9.9);
+    const double v = sum(s);
     REQUIRE(v == 9.9);
   }
 
-  SECTION("delete_stack") {
+  SECTION("delete from stack") {
 
-    typedef Stack<StackOneData, ParticleInterface> StackTest;
     StackTest s;
-    auto p = s.NewParticle();
+    REQUIRE(s.GetSize() == 0);
+    StackTest::StackIterator p = s.AddParticle(0.); // valid way to access particle data
     p.SetData(9.9);
+    REQUIRE(s.GetSize() == 1);
     s.Delete(p);
+    REQUIRE(s.GetSize() == 0);
   }
 
-  SECTION("delete_particle") {
+  SECTION("delete particle") {
 
-    typedef Stack<StackOneData, ParticleInterface> StackTest;
     StackTest s;
-    auto p = s.NewParticle();
-    p.SetData(9.9);
+    REQUIRE(s.GetSize() == 0);
+    auto p =
+        s.AddParticle(9.9); // also valid way to access particle data, identical to above
+    REQUIRE(s.GetSize() == 1);
     p.Delete();
+    REQUIRE(s.GetSize() == 0);
+  }
+
+  SECTION("create secondaries") {
+
+    StackTest s;
+    REQUIRE(s.GetSize() == 0);
+    auto iter = s.AddParticle(9.9);
+    Particle& p = *iter; // also this is valid to access particle data
+    REQUIRE(s.GetSize() == 1);
+    p.AddSecondary(4.4);
+    REQUIRE(s.GetSize() == 2);
+    p.AddSecondary(3.3, 2.2);
+    REQUIRE(s.GetSize() == 3);
+    double v = 0;
+    for (auto& p : s) { v += p.GetData(); }
+    REQUIRE(v == 9.9 + 4.4 + 3.3 + 2.2);
   }
 }
diff --git a/Stack/SuperStupidStack/SuperStupidStack.h b/Stack/SuperStupidStack/SuperStupidStack.h
index 044ae32a1..5e314fd4a 100644
--- a/Stack/SuperStupidStack/SuperStupidStack.h
+++ b/Stack/SuperStupidStack/SuperStupidStack.h
@@ -38,10 +38,12 @@ namespace corsika::stack {
     template <typename StackIteratorInterface>
     class ParticleInterface : public ParticleBase<StackIteratorInterface> {
 
+      using corsika::stack::ParticleBase<StackIteratorInterface>::GetStack;
       using corsika::stack::ParticleBase<StackIteratorInterface>::GetStackData;
       using corsika::stack::ParticleBase<StackIteratorInterface>::GetIndex;
 
     public:
+      /// individual setters
       void SetPID(const corsika::particles::Code id) {
         GetStackData().SetPID(GetIndex(), id);
       }
@@ -62,6 +64,7 @@ namespace corsika::stack {
         GetStackData().SetTime(GetIndex(), v);
       }
 
+      /// individual getters
       corsika::particles::Code GetPID() const {
         return GetStackData().GetPID(GetIndex());
       }
-- 
GitLab