|
| 1 | +/// \file |
| 2 | +/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback |
| 3 | +/// is welcome! |
| 4 | + |
| 5 | +#ifndef ROOT_RBinIndexRange |
| 6 | +#define ROOT_RBinIndexRange |
| 7 | + |
| 8 | +#include "RBinIndex.hxx" |
| 9 | + |
| 10 | +#include <cassert> |
| 11 | +#include <cstddef> |
| 12 | +#include <iterator> |
| 13 | + |
| 14 | +namespace ROOT { |
| 15 | +namespace Experimental { |
| 16 | + |
| 17 | +// forward declarations for friend declaration |
| 18 | +class RBinIndexRange; |
| 19 | +namespace Internal { |
| 20 | +RBinIndexRange CreateBinIndexRange(RBinIndex begin, RBinIndex end, std::size_t nNormalBins); |
| 21 | +} // namespace Internal |
| 22 | + |
| 23 | +/** |
| 24 | +A range of bin indices \f$[fBegin, fEnd)\f$. |
| 25 | +
|
| 26 | +The interface allows convenient iteration over RBinIndex. If included, RBinIndex::Underflow() is encountered before the |
| 27 | +normal bins and RBinIndex::Overflow() is the last value. |
| 28 | +
|
| 29 | +\warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is |
| 30 | +welcome! |
| 31 | +*/ |
| 32 | +class RBinIndexRange final { |
| 33 | + friend RBinIndexRange Internal::CreateBinIndexRange(RBinIndex, RBinIndex, std::size_t); |
| 34 | + |
| 35 | + /// The begin of the range (inclusive) |
| 36 | + RBinIndex fBegin; |
| 37 | + /// The end of the range (exclusive) |
| 38 | + RBinIndex fEnd; |
| 39 | + /// The number of normal bins, after which iteration advances to RBinIndex::Overflow() |
| 40 | + std::size_t fNNormalBins = 0; |
| 41 | + |
| 42 | +public: |
| 43 | + /// Construct an invalid bin index range. |
| 44 | + RBinIndexRange() = default; |
| 45 | + |
| 46 | + RBinIndex GetBegin() const { return fBegin; } |
| 47 | + RBinIndex GetEnd() const { return fEnd; } |
| 48 | + // fNNormalBins is not exposed because it might be confusing for partial ranges. |
| 49 | + |
| 50 | + friend bool operator==(const RBinIndexRange &lhs, const RBinIndexRange &rhs) |
| 51 | + { |
| 52 | + return lhs.fBegin == rhs.fBegin && lhs.fEnd == rhs.fEnd && lhs.fNNormalBins == rhs.fNNormalBins; |
| 53 | + } |
| 54 | + |
| 55 | + friend bool operator!=(const RBinIndexRange &lhs, const RBinIndexRange &rhs) { return !(lhs == rhs); } |
| 56 | + |
| 57 | + /// Iterator over RBinIndex. |
| 58 | + class Iterator final { |
| 59 | + /// The current bin index |
| 60 | + RBinIndex fIndex; |
| 61 | + /// The number of normal bins, after which iteration advances to RBinIndex::Overflow() |
| 62 | + std::size_t fNNormalBins = 0; |
| 63 | + |
| 64 | + public: |
| 65 | + using difference_type = std::size_t; |
| 66 | + using value_type = RBinIndex; |
| 67 | + using pointer = RBinIndex *; |
| 68 | + using reference = RBinIndex &; |
| 69 | + using iterator_category = std::forward_iterator_tag; |
| 70 | + |
| 71 | + Iterator() = default; |
| 72 | + Iterator(RBinIndex index, std::size_t nNormalBins) : fIndex(index), fNNormalBins(nNormalBins) {} |
| 73 | + |
| 74 | + Iterator &operator++() |
| 75 | + { |
| 76 | + if (fIndex.IsUnderflow()) { |
| 77 | + fIndex = 0; |
| 78 | + } else if (fIndex.IsOverflow()) { |
| 79 | + fIndex = RBinIndex(); |
| 80 | + } else if (fIndex.IsInvalid()) { |
| 81 | + // This should never happen! In the worst case, when built with NDEBUG, the iterator stays at Invalid. |
| 82 | + assert(0); |
| 83 | + } else { |
| 84 | + fIndex++; |
| 85 | + if (fIndex.GetIndex() == fNNormalBins) { |
| 86 | + fIndex = RBinIndex::Overflow(); |
| 87 | + } |
| 88 | + } |
| 89 | + return *this; |
| 90 | + } |
| 91 | + Iterator operator++(int) |
| 92 | + { |
| 93 | + Iterator old = *this; |
| 94 | + operator++(); |
| 95 | + return old; |
| 96 | + } |
| 97 | + |
| 98 | + RBinIndex operator*() const { return fIndex; } |
| 99 | + |
| 100 | + friend bool operator==(Iterator lhs, Iterator rhs) |
| 101 | + { |
| 102 | + return lhs.fIndex == rhs.fIndex && lhs.fNNormalBins == rhs.fNNormalBins; |
| 103 | + } |
| 104 | + friend bool operator!=(Iterator lhs, Iterator rhs) { return !(lhs == rhs); } |
| 105 | + }; |
| 106 | + |
| 107 | + Iterator begin() const { return Iterator(fBegin, fNNormalBins); } |
| 108 | + Iterator end() const { return Iterator(fEnd, fNNormalBins); } |
| 109 | + |
| 110 | + static RBinIndexRange Full(std::size_t nNormalBins) |
| 111 | + { |
| 112 | + RBinIndexRange full; |
| 113 | + full.fBegin = RBinIndex::Underflow(); |
| 114 | + full.fEnd = RBinIndex(); |
| 115 | + full.fNNormalBins = nNormalBins; |
| 116 | + return full; |
| 117 | + } |
| 118 | +}; |
| 119 | + |
| 120 | +namespace Internal { |
| 121 | + |
| 122 | +/// Internal function to create RBinIndexRange. |
| 123 | +/// |
| 124 | +/// \param[in] begin the begin of the bin index range (inclusive) |
| 125 | +/// \param[in] end the end of the bin index range (exclusive) |
| 126 | +/// \param[in] nNormalBins the number of normal bins, after which iteration advances to RBinIndex::Overflow() |
| 127 | +RBinIndexRange CreateBinIndexRange(RBinIndex begin, RBinIndex end, std::size_t nNormalBins) |
| 128 | +{ |
| 129 | + RBinIndexRange range; |
| 130 | + range.fBegin = begin; |
| 131 | + range.fEnd = end; |
| 132 | + range.fNNormalBins = nNormalBins; |
| 133 | + return range; |
| 134 | +} |
| 135 | + |
| 136 | +} // namespace Internal |
| 137 | + |
| 138 | +} // namespace Experimental |
| 139 | +} // namespace ROOT |
| 140 | + |
| 141 | +#endif |
0 commit comments