Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-16 09:21:12

0001 /// \file
0002 /// \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
0003 /// Feedback is welcome!
0004 
0005 #ifndef ROOT_RBinIndexMultiDimRange
0006 #define ROOT_RBinIndexMultiDimRange
0007 
0008 #include "RBinIndex.hxx"
0009 #include "RBinIndexRange.hxx"
0010 
0011 #include <cassert>
0012 #include <cstddef>
0013 #include <cstdint>
0014 #include <iterator>
0015 #include <utility>
0016 #include <vector>
0017 
0018 namespace ROOT {
0019 namespace Experimental {
0020 
0021 /**
0022 A multidimensional range of bin indices.
0023 
0024 The interface allows convenient iteration over multiple RBinIndexRange. The result is available as vector of RBinIndex.
0025 
0026 \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
0027 Feedback is welcome!
0028 */
0029 class RBinIndexMultiDimRange final {
0030    /// The original ranges
0031    std::vector<RBinIndexRange> fRanges;
0032    /// Whether there is an empty range
0033    bool fHasEmptyRange = false;
0034 
0035 public:
0036    /// Construct an invalid bin index range.
0037    RBinIndexMultiDimRange() = default;
0038    /// Construct a multidimensional range of bin indices.
0039    RBinIndexMultiDimRange(std::vector<RBinIndexRange> ranges) : fRanges(std::move(ranges))
0040    {
0041       for (auto &&range : fRanges) {
0042          if (range.GetBegin() == range.GetEnd()) {
0043             fHasEmptyRange = true;
0044          }
0045       }
0046    }
0047 
0048    const std::vector<RBinIndexRange> &GetRanges() const { return fRanges; }
0049 
0050    friend bool operator==(const RBinIndexMultiDimRange &lhs, const RBinIndexMultiDimRange &rhs)
0051    {
0052       return lhs.fRanges == rhs.fRanges;
0053    }
0054 
0055    friend bool operator!=(const RBinIndexMultiDimRange &lhs, const RBinIndexMultiDimRange &rhs)
0056    {
0057       return !(lhs == rhs);
0058    }
0059 
0060    /// Iterator over RBinIndexMultiDimRange.
0061    class RIterator final {
0062       friend class RBinIndexMultiDimRange;
0063 
0064       /// The current iterators
0065       std::vector<RBinIndexRange::RIterator> fIterators;
0066       /// The current bin indices
0067       std::vector<RBinIndex> fIndices;
0068       /// Pointer to the original RBinIndexMultiDimRange
0069       const RBinIndexMultiDimRange *fMultiDimRange = nullptr;
0070 
0071       RIterator(const RBinIndexMultiDimRange &multiDimRange) : fMultiDimRange(&multiDimRange) {}
0072 
0073    public:
0074       using difference_type = std::ptrdiff_t;
0075       using value_type = std::vector<RBinIndex>;
0076       using pointer = const std::vector<RBinIndex> *;
0077       using reference = const std::vector<RBinIndex> &;
0078       using iterator_category = std::input_iterator_tag;
0079 
0080       RIterator() = default;
0081 
0082       RIterator &operator++()
0083       {
0084          const std::size_t N = fIterators.size();
0085          std::size_t j = 0;
0086          for (; j < N; j++) {
0087             // Reverse iteration order to advance the innermost index first.
0088             const std::size_t i = N - 1 - j;
0089 
0090             // Advance this iterator and get the index by dereferencing.
0091             // NB: We dereference even if reaching the end. This is fine because we know the implementation of
0092             // RBinIndexRange, in the worst case the returned RBinIndex will be invalid.
0093             fIterators[i]++;
0094             fIndices[i] = *fIterators[i];
0095             // If we have not reached the end, we are done (with this loop).
0096             if (fIndices[i] != fMultiDimRange->fRanges[i].GetEnd()) {
0097                break;
0098             }
0099          }
0100          // If we iterated until j = N, all fIterators and fIndices are at the end.
0101          if (j == N) {
0102             // Clear fIterators to compare equal to the empty iterator returned by end().
0103             fIterators.clear();
0104          } else {
0105             // Otherwise we need to wrap around the innermost dimensions.
0106             for (std::size_t k = 0; k < j; k++) {
0107                // Reverse the iteration order as above.
0108                const std::size_t i = N - 1 - k;
0109                fIterators[i] = fMultiDimRange->fRanges[i].begin();
0110                fIndices[i] = *fIterators[i];
0111             }
0112          }
0113          return *this;
0114       }
0115       RIterator operator++(int)
0116       {
0117          RIterator old = *this;
0118          operator++();
0119          return old;
0120       }
0121 
0122       const std::vector<RBinIndex> &operator*() const { return fIndices; }
0123       const std::vector<RBinIndex> *operator->() const { return &fIndices; }
0124 
0125       friend bool operator==(const RIterator &lhs, const RIterator &rhs)
0126       {
0127          return lhs.fIterators == rhs.fIterators && lhs.fMultiDimRange == rhs.fMultiDimRange;
0128       }
0129       friend bool operator!=(const RIterator &lhs, const RIterator &rhs) { return !(lhs == rhs); }
0130    };
0131 
0132    RIterator begin() const
0133    {
0134       RIterator it(*this);
0135       // If there is an empty range, return an empty iterator.
0136       if (fHasEmptyRange) {
0137          return it;
0138       }
0139 
0140       for (auto &&range : fRanges) {
0141          it.fIterators.push_back(range.begin());
0142          it.fIndices.push_back(*it.fIterators.back());
0143       }
0144       return it;
0145    }
0146    RIterator end() const { return RIterator(*this); }
0147 };
0148 
0149 } // namespace Experimental
0150 } // namespace ROOT
0151 
0152 #endif