From 45b57cef804c2371bc6f659a44dbb4c2b8fbe90b Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Thu, 24 Mar 2022 12:30:35 +0100
Subject: [PATCH] L1Algo interface: updates

---
 reco/L1/L1Algo/L1Array.h         | 179 +++++++++++++++++++++++++++++++
 reco/L1/L1Algo/L1Assert.h        |   6 +-
 reco/L1/L1Algo/L1InitManager.cxx |  37 +++----
 3 files changed, 201 insertions(+), 21 deletions(-)
 create mode 100644 reco/L1/L1Algo/L1Array.h

diff --git a/reco/L1/L1Algo/L1Array.h b/reco/L1/L1Algo/L1Array.h
new file mode 100644
index 0000000000..d2754a9773
--- /dev/null
+++ b/reco/L1/L1Algo/L1Array.h
@@ -0,0 +1,179 @@
+/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov, Sergei Zharko [committer] */
+
+#ifndef L1Array_h
+#define L1Array_h 1
+
+#include <FairLogger.h>
+
+#include <array>
+#include <string>
+#include <utility>
+
+#include "L1Assert.h"
+
+/// Idea: std::array based class, where the size() and copacity() return different numbers.
+/// Size returns the effective size of array (i.e. the number of elements, which were really)
+
+// TODO: What is better to be used here - std::size or int. Needs to be tested (S.Zharko)
+
+
+template<class Tvalue, std::size_t MaxCapacity>
+class L1Array : private std::array<Tvalue, MaxCapacity> {
+public:
+  // Type definitions
+  using Tbase        = std::array<Tvalue, MaxCapacity>;
+  using Tsize        = typename Tbase::size_type;
+  using Tpointer     = typename Tbase::pointer;
+  using Tcpointer    = typename Tbase::const_pointer;
+  using Treference   = typename Tbase::reference;
+  using Tcreference  = typename Tbase::const_reference;
+  using Titerator    = typename Tbase::iterator;
+  using Tciterator   = typename Tbase::const_iterator;
+  using Tdifference  = typename Tbase::difference_type;
+  using Triterator   = typename Tbase::reverse_iterator;
+  using Tcriterator  = typename Tbase::const_reverse_iterator;
+  using TarrayTraits = typename _GLIBCXX_STD_C::__array_traits<Tvalue, MaxCapacity>;
+
+  template<typename... Tinput>
+  L1Array(Tinput... value) : Tbase(value...)
+  {
+  }
+
+  template<typename... Tinput>
+  L1Array(int size, const char* name, Tinput... value) : Tbase(value...)
+                                                       , fSize(static_cast<Tsize>(size))
+                                                       , fName(name)
+  {
+  }
+
+  // TODO: Probably, there is a way to do this better... (S.Zharko)
+  L1Array(const char* name, std::initializer_list<Tvalue> init) : Tbase(), fName(name)
+  {
+#ifndef FAST_CODE
+    if _GLIBCXX17_CONSTEXPR (L1Assert::kAssertionLevel >= 2 && Tbase::max_size() < init.size()) {
+      LOG(fatal) << '\n'
+                 << " ***** Level 2 assertion failed: " << '\n'
+                 << " *****   message: in L1Array with the name " << fName << ": the size of the initializer list ("
+                 << init.size() << ") is larger then the maximum size of the array (" << Tbase::max_size() << ')';
+    }
+#endif  // FAST_CODE
+    fSize = init.size();
+    for (auto idx = 0; idx < fSize; ++idx) {
+      operator[](idx) = *(init.begin() + idx);
+    }
+  }
+
+  L1Array(std::initializer_list<Tvalue> init) : L1Array("no name", init) {}
+
+  /// Swap function
+  //friend void swap(L1Array<T, N>& lhs, L1Array<T, N>& rhs)
+  //{
+  //  std::swap(static_cast<Tbase&>(lhs), static_cast<Tbase&>(rhs));
+  //  std::swap(lhs.fName, rhs.fName);
+  //  std::swap(lhs.fSize, rhs.fSize);
+  //}
+
+  /// Gets name of the array
+  std::string GetName() const
+  {
+    std::string str = " L1Array<";
+    str += fName + "> ";
+    return str;
+  }
+
+
+  /// Sets name of array from stringstream
+  void SetName(const std::basic_ostream<char>& name) { fName = dynamic_cast<const std::stringstream&>(name).str(); }
+
+  /// Sets name of array from std::string parameters
+  void SetName(const std::string& name) { fName = name; }
+
+  //
+  // BASE METHODS
+  //
+  // Element access
+
+  Treference operator[](Tsize pos) noexcept
+  {
+#ifndef FAST_CODE
+    if _GLIBCXX17_CONSTEXPR (L1Assert::kAssertionLevel >= 3 && pos >= fSize) {
+      LOG(fatal) << '\n'
+                 << " ***** Level 3 assertion failed: " << '\n'
+                 << " *****   message: in L1Array with the name " << fName << ": index out of range (pos = " << pos
+                 << " >= size = " << fSize << ")";
+    }
+    // TODO: do we need a simple assertion here to prevent the index out of range? (S.Zharko)
+#endif  // FAST_CODE
+    return Tbase::operator[](pos);
+  }
+
+  Tcreference operator[](Tsize pos) const noexcept
+  {
+#ifndef FAST_CODE
+    if _GLIBCXX17_CONSTEXPR (L1Assert::kAssertionLevel >= 3 && pos >= fSize) {
+      LOG(fatal) << '\n'
+                 << " ***** Level 3 assertion failed: " << '\n'
+                 << " *****   message: in L1Array with the name " << fName << ": index out of range (pos = " << pos
+                 << " >= size = " << fSize << ")";
+    }
+    // TODO: do we need a simple assertion here to prevent the index out of range? (S.Zharko)
+#endif  // FAST_CODE
+    return Tbase::operator[](pos);
+  }
+
+  using Tbase::front;
+
+  _GLIBCXX17_CONSTEXPR Treference back() noexcept { return fSize ? *(end() - 1) : *end(); }
+
+  constexpr Tcreference back() const noexcept { return fSize ? *(end() - 1) : *end(); }
+
+  using Tbase::data;
+  // Iterators
+  using Tbase::begin;
+  //using Tbase::end;
+
+  // NOTE: _GLIBCXX17_CONSTEXPR is used in a base class and places constexpr for c++17+ and nothing instead
+  _GLIBCXX17_CONSTEXPR Titerator end() noexcept { return Titerator(data() + fSize); }
+
+  _GLIBCXX17_CONSTEXPR Tciterator end() const noexcept { return Tciterator(data() + fSize); }
+
+  _GLIBCXX17_CONSTEXPR Triterator rbegin() noexcept { return Triterator(end()); }
+
+  _GLIBCXX17_CONSTEXPR Tcriterator rbegin() const noexcept { return Tcriterator(end()); }
+
+  using Tbase::cbegin;
+  using Tbase::rend;
+
+  _GLIBCXX17_CONSTEXPR Tciterator cend() const noexcept { return Tciterator(data() + fSize); }
+
+  _GLIBCXX17_CONSTEXPR Tcriterator crbegin() const noexcept { return Tcriterator(end()); }
+
+  using Tbase::crend;
+
+  //   Capasity
+  constexpr Tsize size() const noexcept { return fSize; }
+
+  using Tbase::max_size;
+  constexpr bool empty();
+
+  //   Operations
+  void fill(const Tvalue& val) { std::fill_n(begin(), size(), val); }
+
+  void swap(L1Array& other) noexcept(TarrayTraits::_Is_nothrow_swappable::value)
+  {
+    std::swap(fName, other.fName);
+    std::swap(fSize, other.fSize);
+    std::swap_ranges(begin(), end(), other.begin());
+  }
+
+private:
+  using Tbase::at;
+
+  Tsize fSize {0};
+  std::string fName {"no name"};
+};
+
+
+#endif  // L1Array_h
diff --git a/reco/L1/L1Algo/L1Assert.h b/reco/L1/L1Algo/L1Assert.h
index af23e3adab..e5bdf5032b 100644
--- a/reco/L1/L1Algo/L1Assert.h
+++ b/reco/L1/L1Algo/L1Assert.h
@@ -22,7 +22,7 @@
 
 #include "FairLogger.h"
 
-#if defined(NDEBUG) || defined(L1_NO_ASSERT) // TODO: Do we need to add FAST_CODE here? (S.Zharko)
+#if defined(NDEBUG) || defined(L1_NO_ASSERT)  // TODO: Do we need to add FAST_CODE here? (S.Zharko)
 #define L1ASSERT(LEVEL, COND)
 #define L1MASSERT(LEVEL, COND, MSG)
 #else
@@ -42,11 +42,11 @@ namespace L1Assert
   {
     if (!condition) {
       LOG(fatal) << '\n'
-                 << " ***** Level " << level << " assertion failed: " << '\n' 
+                 << " ***** Level " << level << " assertion failed: " << '\n'
                  << " *****   message/condition : " << msg << '\n'
                  << " *****   file:               " << fileName << '\n'
                  << " *****   line:               " << lineNo;
-      std::abort(); // keep it here, because sometimes LOG(fatal) does not work (for example, in your tester)
+      std::abort();  // keep it here, because sometimes LOG(fatal) does not work (for example, in your tester)
     }
     return 1;
   }
diff --git a/reco/L1/L1Algo/L1InitManager.cxx b/reco/L1/L1Algo/L1InitManager.cxx
index 99524ed879..e3adcb2d1e 100644
--- a/reco/L1/L1Algo/L1InitManager.cxx
+++ b/reco/L1/L1Algo/L1InitManager.cxx
@@ -9,10 +9,11 @@
  ***********************************************************************************************************/
 
 #include "L1InitManager.h"
-#include "L1Assert.h"
 
 #include <algorithm>
 #include <sstream>
+
+#include "L1Assert.h"
 //-----------------------------------------------------------------------------------------------------------------------
 //
 L1InitManager::L1InitManager(L1Parameters* pParameters) : fpParameters(pParameters) {}
@@ -23,16 +24,16 @@ void L1InitManager::AddStation(const L1BaseStationInfo& inStation)
 {
   // Check if other fields were defined already
   // Active detector IDs
-  
-  L1MASSERT(0, fInitController.GetFlag(InitKey::keActiveDetectorIDs), 
+
+  L1MASSERT(0, fInitController.GetFlag(InitKey::keActiveDetectorIDs),
             "Attempt to add a station info before the active detetors set had been initialized");
 
   // Number of stations check
-  L1MASSERT(0, fInitController.GetFlag(InitKey::keStationsNumberCrosscheck), 
+  L1MASSERT(0, fInitController.GetFlag(InitKey::keStationsNumberCrosscheck),
             "Attempt to add a station info before the numbers of stations for each detector had been initialized");
 
   // Field function
-  L1MASSERT(0, fInitController.GetFlag(InitKey::keFieldFunction), 
+  L1MASSERT(0, fInitController.GetFlag(InitKey::keFieldFunction),
             "Attempt to add a station info before the magnetic field function had been intialized");
 
   // Check activeness of this station type
@@ -49,9 +50,9 @@ void L1InitManager::AddStation(const L1BaseStationInfo& inStation)
                  << inStation.GetInitController().ToString();
       std::stringstream aStream;
       aStream << "Attempt to add an incompletely initialized station info object (detectorID = "
-              << static_cast<int>(inStationCopy.GetDetectorID())
-              << ", stationID = " << inStationCopy.GetStationID() << ")";
-      L1MASSERT(0, inStationCopy.GetInitController().IsFinalized(), aStream.str().c_str()); 
+              << static_cast<int>(inStationCopy.GetDetectorID()) << ", stationID = " << inStationCopy.GetStationID()
+              << ")";
+      L1MASSERT(0, inStationCopy.GetInitController().IsFinalized(), aStream.str().c_str());
     }
     // insert the station in a set
     auto insertionResult = fStationsInfo.insert(std::move(inStationCopy));
@@ -59,8 +60,8 @@ void L1InitManager::AddStation(const L1BaseStationInfo& inStation)
     {
       std::stringstream aStream;
       aStream << "Attempt to add a dublicating station info object (detectorID = "
-              << static_cast<int>(inStationCopy.GetDetectorID())
-              << ", stationID = " << inStationCopy.GetStationID() << ")";
+              << static_cast<int>(inStationCopy.GetDetectorID()) << ", stationID = " << inStationCopy.GetStationID()
+              << ")";
       L1MASSERT(0, insertionResult.second, aStream.str().c_str());
     }
   }
@@ -98,12 +99,13 @@ void L1InitManager::InitTargetField(double zStep)
   }
 
   // Check for field function
-  L1MASSERT(0, fInitController.GetFlag(InitKey::keFieldFunction), 
+  L1MASSERT(0, fInitController.GetFlag(InitKey::keFieldFunction),
             "Attempt to initialze the field value and field region near target before initializing field function");
 
   // Check for target defined
-  L1MASSERT(0, fInitController.GetFlag(InitKey::keTargetPos), 
-            "Attempt to initialize the field value and field region near target before the target position initialization");
+  L1MASSERT(
+    0, fInitController.GetFlag(InitKey::keTargetPos),
+    "Attempt to initialize the field value and field region near target before the target position initialization");
 
   constexpr int nDimensions {3};
   constexpr int nPointsNodal {3};
@@ -150,7 +152,7 @@ void L1InitManager::PrintStations(int verbosityLevel) const
 void L1InitManager::PushBackCAIteration(const L1CAIteration& iteration)
 {
   // TODO: probably some checks must be inserted here (S.Zharko)
-  L1MASSERT(0, fInitController.GetFlag(InitKey::keCAIterationsNumberCrosscheck), 
+  L1MASSERT(0, fInitController.GetFlag(InitKey::keCAIterationsNumberCrosscheck),
             "Attempt to push back a CA track finder iteration before the number of iterations was defined");
 
   L1Vector<L1CAIteration>& iterationsContainer = fpParameters->CAIterationsContainer();
@@ -308,16 +310,15 @@ void L1InitManager::CheckStationsInfoInit()
       }
     }  // loop over active detectors: end
     L1MASSERT(0, ifInitPassed, "Station info initialization failed");
-    
+
     //
     // 2) Check for maximum allowed number of stations
     //
     int nStationsTotal = GetStationsNumber();
     if (nStationsTotal > L1Parameters::kMaxNstations) {
       std::stringstream aStream;
-      aStream << "Actual total number of registered stations (" << nStationsTotal
-              << ") is larger then designed one (" << L1Parameters::kMaxNstations
-              << "). Please, select another set of active tracking detectors";
+      aStream << "Actual total number of registered stations (" << nStationsTotal << ") is larger then designed one ("
+              << L1Parameters::kMaxNstations << "). Please, select another set of active tracking detectors";
       // TODO: We have to provide an instruction of how to increase the kMaxNstations
       //       number keeping the code consistent (S.Zharko)
       ifInitPassed = false;
-- 
GitLab