From 4ccf13bbdc4e2a0ef6047307f28c87885177057a Mon Sep 17 00:00:00 2001
From: ralfulrich <ralf.ulrich@kit.edu>
Date: Fri, 25 Sep 2020 15:22:25 +0200
Subject: [PATCH] added parent() function to get original parent particle back

---
 Framework/StackInterface/SecondaryView.h      | 79 ++++++++++++-------
 .../StackInterface/StackIteratorInterface.h   | 42 +++++++---
 Framework/StackInterface/testSecondaryView.cc |  1 +
 3 files changed, 82 insertions(+), 40 deletions(-)

diff --git a/Framework/StackInterface/SecondaryView.h b/Framework/StackInterface/SecondaryView.h
index 4a33b404c..6061fa1ba 100644
--- a/Framework/StackInterface/SecondaryView.h
+++ b/Framework/StackInterface/SecondaryView.h
@@ -43,13 +43,13 @@ namespace corsika::stack {
      *Further information about implementation (for developers):* All
      data is stored in the original stack privided at construction
      time. The secondary particle (view) indices are stored in an
-     extra std::vector of SecondaryView class 'fIndices' referring to
+     extra std::vector of SecondaryView class 'indices_' referring to
      the original stack slot indices. The index of the primary
      projectle particle is also explicitly stored in
-     'fProjectileIndex'. StackIterator indices
+     'projectile_index_'. StackIterator indices
      'i = StackIterator::GetIndex()' are referring to those numbers,
-     where 'i==0' refers to the 'fProjectileIndex', and
-     'StackIterator::GetIndex()>0' to 'fIndices[i-1]', see function
+     where 'i==0' refers to the 'projectile_index_', and
+     'StackIterator::GetIndex()>0' to 'indices_[i-1]', see function
      GetIndexFromIterator.
    */
 
@@ -62,8 +62,8 @@ namespace corsika::stack {
     /**
      * Helper type for inside this class
      */
-    using InnerStackType = Stack<StackDataType&, ParticleInterface>;
-    using InnerStackType::getDeleted;
+    using InnerStackTypeRef = Stack<StackDataType&, ParticleInterface>;
+    using InnerStackTypeRef::getDeleted;
 
     /**
      * @name We need this "special" types with non-reference StackData for
@@ -76,6 +76,9 @@ namespace corsika::stack {
     using StackIteratorValue =
         StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
                                ParticleInterface, InnerStackTypeValue>;
+    using ConstStackIteratorValue =
+        ConstStackIteratorInterface<typename std::remove_reference<StackDataType>::type,
+                               ParticleInterface, InnerStackTypeValue>;
     /// @}
 
     using StackIterator =
@@ -106,9 +109,9 @@ namespace corsika::stack {
     SecondaryView(Args... args) = delete;
 
   private:
-    InnerStackTypeValue& innerstack_;
-    unsigned int fProjectileIndex;
-    std::vector<unsigned int> fIndices;
+    InnerStackTypeValue& inner_stack_;
+    unsigned int projectile_index_;
+    std::vector<unsigned int> indices_;
 
   public:
     /**
@@ -117,13 +120,29 @@ namespace corsika::stack {
      **/
     SecondaryView(StackIteratorValue& vI)
         : Stack<StackDataType&, ParticleInterface>(vI.GetStackData())
-        , innerstack_(vI.GetStack())
-        , fProjectileIndex(vI.GetIndex()) {}
+        , inner_stack_(vI.GetStack())
+        , projectile_index_(vI.GetIndex()) {}
+
+
+    /**
+     * This returns the projectile/parent in the original Stack, where this
+     * SecondaryView is derived from. This projectile should not be
+     * used to modify the Stack!
+     */
 
+    ConstStackIteratorValue parent() const {
+      return ConstStackIteratorValue(inner_stack_, projectile_index_);
+    }
+
+    /**
+     * This return a projectile of this SecondaryView, which can be
+     * used to modify the SecondaryView
+     */
     StackIterator GetProjectile() {
       // NOTE: 0 is special marker here for PROJECTILE, see GetIndexFromIterator
       return StackIterator(*this, 0);
     }
+  public:
 
     template <typename... Args>
     StackIterator AddSecondary(const Args... v) {
@@ -134,13 +153,13 @@ namespace corsika::stack {
     template <typename... Args>
     StackIterator AddSecondary(StackIterator& proj, const Args... v) {
       // make space on stack
-      InnerStackType::GetStackData().IncrementSize();
-      innerstack_.deleted_.push_back(false);
+      InnerStackTypeRef::GetStackData().IncrementSize();
+      inner_stack_.deleted_.push_back(false);
       // get current number of secondaries on stack
       const unsigned int idSec = getSize();
       // determine index on (inner) stack where new particle will be located
-      const unsigned int index = InnerStackType::GetStackData().GetSize() - 1;
-      fIndices.push_back(index);
+      const unsigned int index = InnerStackTypeRef::GetStackData().GetSize() - 1;
+      indices_.push_back(index);
       // NOTE: "+1" is since "0" is special marker here for PROJECTILE, see
       // GetIndexFromIterator
       return StackIterator(*this, idSec + 1, proj, v...);
@@ -149,7 +168,7 @@ namespace corsika::stack {
     /**
      * overwrite Stack::GetSize to return actual number of secondaries
      */
-    unsigned int getSize() const { return fIndices.size(); }
+    unsigned int getSize() const { return indices_.size(); }
     unsigned int getEntries() const { return getSize() - getDeleted(); }
     bool IsEmpty() const { return getEntries() == 0; }
 
@@ -215,7 +234,7 @@ namespace corsika::stack {
      * SecondaryView::DeleteLast
      *
      * The particle is deleted on the underlying (internal) stack. The
-     * local references in SecondaryView in fIndices must be fixed,
+     * local references in SecondaryView in indices_ must be fixed,
      * too.  The approach is to a) check if the particle 'p' is at the
      * very end of the internal stack, b) if not: move it there by
      * copying the last particle to the current particle location, c)
@@ -229,8 +248,8 @@ namespace corsika::stack {
       if (isDeleted(p.GetIndex() - 1)) { /*error*/
         throw std::runtime_error("Stack, cannot delete entry since already deleted");
       }
-      innerstack_.Delete(GetIndexFromIterator(p.GetIndex()));
-      InnerStackType::nDeleted_++; // also count in SecondaryView
+      inner_stack_.Delete(GetIndexFromIterator(p.GetIndex()));
+      InnerStackTypeRef::nDeleted_++; // also count in SecondaryView
     }
 
     /**
@@ -272,9 +291,9 @@ namespace corsika::stack {
     bool purgeLastIfDeleted() {
       if (!isDeleted(getSize() - 1))
         return false; // the last particle is not marked for deletion. Do nothing.
-      innerstack_.purge(GetIndexFromIterator(getSize()));
-      InnerStackType::nDeleted_--;
-      fIndices.pop_back();
+      inner_stack_.purge(GetIndexFromIterator(getSize()));
+      InnerStackTypeRef::nDeleted_--;
+      indices_.pop_back();
       return true;
     }
 
@@ -291,31 +310,31 @@ namespace corsika::stack {
       unsigned int size = getSize();
       while (iStack < size) {
         if (isDeleted(iStack)) {
-          innerstack_.purge(iStack);
-          fIndices.erase(fIndices.begin() + iStack);
+          inner_stack_.purge(iStack);
+          indices_.erase(indices_.begin() + iStack);
         }
         size = getSize();
         iStack++;
       }
-      InnerStackType::nDeleted_ = 0;
+      InnerStackTypeRef::nDeleted_ = 0;
     }
 
   protected:
     // forward to inner stack
     // this also checks the allowed bounds of 'i'
     bool isDeleted(unsigned int i) const {
-      if (i >= fIndices.size()) return false;
-      return innerstack_.isDeleted(GetIndexFromIterator(i + 1));
+      if (i >= indices_.size()) return false;
+      return inner_stack_.isDeleted(GetIndexFromIterator(i + 1));
     }
 
     /**
-     * We only want to 'see' secondaries indexed in fIndices. In this
+     * We only want to 'see' secondaries indexed in indices_. In this
      * function the conversion form iterator-index to stack-index is
      * performed.
      */
     unsigned int GetIndexFromIterator(const unsigned int vI) const {
-      if (vI == 0) return fProjectileIndex;
-      return fIndices[vI - 1];
+      if (vI == 0) return projectile_index_;
+      return indices_[vI - 1];
     }
   };
 
diff --git a/Framework/StackInterface/StackIteratorInterface.h b/Framework/StackInterface/StackIteratorInterface.h
index c9095263b..010d1fe1e 100644
--- a/Framework/StackInterface/StackIteratorInterface.h
+++ b/Framework/StackInterface/StackIteratorInterface.h
@@ -23,6 +23,10 @@ namespace corsika::stack {
   template <typename TStackData, template <typename> typename TParticleInterface>
   class SecondaryView; // forward decl
 
+  template <typename TStackData, template <typename> typename TParticleInterface,
+    typename StackType>
+    class ConstStackIteratorInterface; // forward decl
+
   /**
      @class StackIteratorInterface
 
@@ -85,8 +89,11 @@ namespace corsika::stack {
   template <typename T>
   friend class corsika::history::HistorySecondaryView;
 
-  private:
+  friend class ConstStackIteratorInterface<TStackData, TParticleInterface, StackType>;
+  
+  protected:
     unsigned int index_ = 0;
+  private:
     StackType* data_ = 0; // info: Particles and StackIterators become invalid when parent
                           // Stack is copied or deleted!
 
@@ -165,11 +172,13 @@ namespace corsika::stack {
           GetStack().isDeleted(*this)); // this also check the allowed bounds of index_
       return tmp;
     }
-    StackIteratorInterface operator+(int delta) {
+    StackIteratorInterface operator+(int delta) const {
       return StackIteratorInterface(*data_, index_ + delta);
     }
-    bool operator==(const StackIteratorInterface& rhs) { return index_ == rhs.index_; }
-    bool operator!=(const StackIteratorInterface& rhs) { return index_ != rhs.index_; }
+    bool operator==(const StackIteratorInterface& rhs) const { return index_ == rhs.index_; }
+    bool operator!=(const StackIteratorInterface& rhs) const { return index_ != rhs.index_; }
+  bool operator==(const ConstStackIteratorInterface<TStackData, TParticleInterface, StackType>& rhs) const; // implement below
+  bool operator!=(const ConstStackIteratorInterface<TStackData, TParticleInterface, StackType>& rhs) const; // implement below
 
     /**
      * Convert iterator to value type, where value type is the user-provided particle
@@ -235,8 +244,11 @@ namespace corsika::stack {
     friend class SecondaryView<TStackData,
                                TParticleInterface>; // access for SecondaryView
 
-  private:
+    friend class StackIteratorInterface<TStackData, TParticleInterface, StackType>;
+
+  protected:
     unsigned int index_ = 0;
+  private:
     const StackType* data_ = 0; // info: Particles and StackIterators become invalid when
                                 // parent Stack is copied or deleted!
 
@@ -282,16 +294,17 @@ namespace corsika::stack {
           GetStack().isDeleted(*this)); // this also check the allowed bounds of index_
       return tmp;
     }
-    ConstStackIteratorInterface operator+(const int delta) {
-      for (int i = 0; i < delta; ++i) operator++();
-      return ConstStackIteratorInterface(*data_, index_);
+    ConstStackIteratorInterface operator+(const int delta) const {
+      return ConstStackIteratorInterface(*data_, index_+delta);
     }
-    bool operator==(const ConstStackIteratorInterface& rhs) {
+    bool operator==(const ConstStackIteratorInterface& rhs) const {
       return index_ == rhs.index_;
     }
-    bool operator!=(const ConstStackIteratorInterface& rhs) {
+    bool operator!=(const ConstStackIteratorInterface& rhs) const {
       return index_ != rhs.index_;
     }
+    bool operator==(const StackIteratorInterface<TStackData, TParticleInterface, StackType>& rhs) const { return index_ == rhs.index_; }
+    bool operator!=(const StackIteratorInterface<TStackData, TParticleInterface, StackType>& rhs) const { return index_ != rhs.index_; }
 
     const ParticleInterfaceType& operator*() const {
       return static_cast<const ParticleInterfaceType&>(*this);
@@ -313,4 +326,13 @@ namespace corsika::stack {
     ///@}
   }; // end class ConstStackIterator
 
+
+    template <typename TStackData, template <typename> typename TParticleInterface,
+            typename StackType>
+  bool StackIteratorInterface<TStackData, TParticleInterface, StackType>::operator==(const ConstStackIteratorInterface<TStackData, TParticleInterface, StackType>& rhs) const { return index_ == rhs.index_; }
+
+      template <typename TStackData, template <typename> typename TParticleInterface,
+            typename StackType>
+  bool StackIteratorInterface<TStackData, TParticleInterface, StackType>::operator!=(const ConstStackIteratorInterface<TStackData, TParticleInterface, StackType>& rhs) const { return index_ != rhs.index_; }
+
 } // namespace corsika::stack
diff --git a/Framework/StackInterface/testSecondaryView.cc b/Framework/StackInterface/testSecondaryView.cc
index fb27467dd..e4c82d15b 100644
--- a/Framework/StackInterface/testSecondaryView.cc
+++ b/Framework/StackInterface/testSecondaryView.cc
@@ -125,6 +125,7 @@ TEST_CASE("SecondaryStack", "[stack]") {
     {
       auto proj = view.GetProjectile();
       CHECK(proj.GetData() == particle.GetData());
+      CHECK(particle == view.parent());
     }
   }
 
-- 
GitLab