All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
IntegerRanges.h
Go to the documentation of this file.
1 /**
2  * @file icarusalg/Utilities/IntegerRanges.h
3  * @brief Class compacting a list of integers.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date May 18, 2021
6  *
7  * This is a header-only, pure standard C++ library.
8  */
9 
10 
11 #ifndef ICARUSALG_UTILITIES_INTEGERRANGES_H
12 #define ICARUSALG_UTILITIES_INTEGERRANGES_H
13 
14 // C/C++ standard libraries
15 #include <ostream>
16 #include <vector>
17 #include <initializer_list>
18 #include <numeric> // std::accumulate()
19 #include <stdexcept> // std::runtime_error
20 #include <type_traits> // std::is_integral_v
21 
22 
23 // -----------------------------------------------------------------------------
24 namespace icarus {
25 
26  // ---------------------------------------------------------------------------
27  namespace details {
28 
29  template <typename T = int> class IntegerRangesBase;
30 
31  template <typename T>
32  std::ostream& operator<< (
33  std::ostream& out,
34  typename IntegerRangesBase<T>::Data_t const& range
35  );
36 
37  } // namespace details
38  // ---------------------------------------------------------------------------
39 
40 
41  template <typename T = int, bool CheckGrowing = false> class IntegerRanges;
42 
43  template <bool CheckGrowing = true , typename Coll>
45  (Coll const& coll);
46 
47 
48  template <typename T, bool CheckGrowing>
49  std::ostream& operator<<
50  (std::ostream& out, IntegerRanges<T, CheckGrowing> const& ranges);
51 
52  template <typename T, bool CheckGrowing>
53  std::ostream& operator<<
54  (std::ostream& out, typename IntegerRanges<T, CheckGrowing>::Range_t const& r);
55 } // namespace icarus
56 
57 
58 // -----------------------------------------------------------------------------
59 /**
60  * @brief A sequence of contiguous ranges of integral numbers.
61  * @tparam T type of the integral numbers
62  * @tparam CheckGrowing if `true`, checks will be performed on construction
63  *
64  * This class parses a sequence in input grouping the consecutive elements.
65  * The current interface is very simple, allowing only for query of groups
66  * ("ranges") and printing to a stream.
67  * The input is required and assumed to be a monotonously growing sequence,
68  * with the exception that duplicate consecutive entries are allowed
69  * (and ignored).
70  *
71  * Each range is stored as a semi-open interval: [ _lower_, _upper_ [.
72  */
73 template <typename T /* = int */>
75  static_assert
76  (std::is_integral_v<T>, "IntegerRanges only support integral types.");
77 
78  public:
79  using Data_t = T; ///< Type of data for the range set.
80 
81  struct Range_t {
82 
85 
86  constexpr Range_t() noexcept = default;
87  constexpr Range_t(Data_t lower, Data_t upper) noexcept;
88 
89  constexpr bool empty() const noexcept;
90  constexpr std::size_t size() const noexcept;
91  constexpr bool isOne() const noexcept;
92  constexpr bool isTwo() const noexcept;
93 
94  void dump(
95  std::ostream& out,
96  std::string const& sep, std::string const& simpleSep
97  ) const;
98  void dump(std::ostream& out, std::string const& sep = "--") const;
99 
100  }; // struct Range_t
101 
102 
103  /// Removes all the entries and makes the set as default-constructed.
104  void clear() noexcept;
105 
106 
107  // --- BEGIN -- Queries ------------------------------------------------------
108  /// @name Queries
109  /// @{
110 
111  /// Returns whether there is any element in the range set.
112  bool empty() const noexcept;
113 
114  /// Returns the number of elements in the ranges (gaps excluded).
115  std::size_t size() const noexcept;
116 
117  /// Returns the number of non-contiguous ranges in the set.
118  std::size_t nRanges() const noexcept;
119 
120  /// Returns an iterable object with all sorted ranges as elements.
121  decltype(auto) ranges() const noexcept;
122 
123  /// @}
124  // --- END ---- Queries ------------------------------------------------------
125 
126 
127  /// Prints the range into the specified stream.
128  /// @param out the stream to print into
129  /// @param sep separator between ranges
130  /// @param inRangeSep separator between lower and higher limit of each range
131  void dump(std::ostream& out,
132  std::string const& sep = " ", std::string const& inRangeSep = "--"
133  ) const;
134 
135 
136  protected:
137 
138  /// Default constructor: starts with no elements.
139  IntegerRangesBase() = default;
140 
141  /// Constructor for the derived classes.
143 
144 
145  /// Fills the ranges.
146  template <bool CheckGrowing, typename BIter, typename EIter>
147  static std::vector<Range_t> compactRange(BIter b, EIter e);
148 
149 
150  /// Returns `value` incremented by 1.
151  static constexpr Data_t plusOne(Data_t value) noexcept;
152 
153  /// Returns `value` decremented by 1.
154  static constexpr Data_t minusOne(Data_t value) noexcept;
155 
156  private:
157 
158  std::vector<Range_t> fRanges; ///< List of current ranges.
159 
160 
161 }; // class icarus::details::IntegerRangesBase<>
162 
163 
164 
165 // -----------------------------------------------------------------------------
166 /**
167  * @brief A sequence of contiguous ranges of integral numbers.
168  * @tparam T type of the integral numbers
169  * @tparam CheckGrowing if `true`, checks will be performed on construction
170  *
171  * This class parses a sequence in input grouping the consecutive elements.
172  * The current interface is very simple, allowing only for query of groups
173  * ("ranges") and printing to a stream.
174  * The input is required and assumed to be a monotonously growing sequence,
175  * with the exception that duplicate consecutive entries are allowed
176  * (and ignored).
177  *
178  * Each range is stored as a semi-open interval: [ _lower_, _upper_ [.
179  *
180  * If `CheckGrowing` is `true`, on input an exception will be thrown if the
181  * input is not strictly sorted (but duplicate elements are still allowed).
182  *
183  * Example of usage:
184  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
185  * std::array data { 1, 2, 4, 5, 6, 8, 10 };
186  *
187  * icarus::IntegerRanges ranges { data };
188  * std::cout << "Ranges: " << ranges << std::endl;
189  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190  * will print something like `Ranges: 1 2 4--6 8 10`.
191  *
192  */
193 template <typename T /* = int */, bool CheckGrowing /* = false */>
194 class icarus::IntegerRanges: public icarus::details::IntegerRangesBase<T> {
195 
197 
198  public:
199  static constexpr bool IsChecked = CheckGrowing;
200 
201  using Data_t = typename Base_t::Data_t;
202 
203  /// Default constructor: an empty set of ranges.
204  IntegerRanges() = default;
205 
206  /// Constructor: range from the values pointed between `b` and `e` iterators.
207  template <typename BIter, typename EIter>
208  IntegerRanges(BIter b, EIter e);
209 
210  IntegerRanges(std::initializer_list<Data_t> data);
211 
212 }; // class icarus::IntegerRanges<>
213 
214 
215 // -----------------------------------------------------------------------------
216 /// Returns a `IntegerRanges` object from the elements in `coll`.
217 template <bool CheckGrowing, typename Coll>
218 auto icarus::makeIntegerRanges(Coll const& coll)
220 {
222  { begin(coll), end(coll) };
223 } // icarus::makeIntegerRanges(Coll const& coll)
224 
225 
226 
227 // -----------------------------------------------------------------------------
228 // --- template implementation
229 // -----------------------------------------------------------------------------
230 // --- icarus::details::IntegerRangesBase<>::Range_t
231 // -----------------------------------------------------------------------------
232 template <typename T /* = int */>
234  (Data_t lower, Data_t upper) noexcept
235  : lower(lower), upper(upper)
236  {}
237 
238 
239 // -----------------------------------------------------------------------------
240 template <typename T /* = int */>
242  () const noexcept
243  { return lower == upper; }
244 
245 
246 // -----------------------------------------------------------------------------
247 template <typename T /* = int */>
249  () const noexcept
250  { return upper - lower; }
251 
252 
253 // -----------------------------------------------------------------------------
254 template <typename T /* = int */>
256  () const noexcept
257  { return plusOne(lower) == upper; }
258 
259 
260 // -----------------------------------------------------------------------------
261 template <typename T /* = int */>
263  () const noexcept
264  { return plusOne(lower) == minusOne(upper); }
265 
266 
267 // -----------------------------------------------------------------------------
268 template <typename T /* = int */>
270  (std::ostream& out, std::string const& sep, std::string const& simpleSep)
271  const
272 {
273 
274  if (empty()) {
275  // let's say we don't print nothing at all
276  return;
277  }
278 
279  out << lower;
280  if (isOne()) return;
281 
282  out << (isTwo()? simpleSep: sep) << icarus::details::IntegerRangesBase<T>::minusOne(upper);
283  return;
284 
285 } // icarus::details::IntegerRangesBase<>::Range_t::dump()
286 
287 
288 // -----------------------------------------------------------------------------
289 template <typename T /* = int */>
291  (std::ostream& out, std::string const& sep /* = "--" */) const
292  { dump(out, sep, sep); }
293 
294 
295 // -----------------------------------------------------------------------------
296 // --- icarus::details::IntegerRangesBase<>
297 // -----------------------------------------------------------------------------
298 template <typename T /* = int */>
300  (std::vector<Range_t> ranges): fRanges(std::move(ranges))
301  {}
302 
303 
304 // -----------------------------------------------------------------------------
305 template <typename T /* = int */>
307  { return fRanges.clear(); }
308 
309 
310 // -----------------------------------------------------------------------------
311 template <typename T /* = int */>
313  { return fRanges.empty(); }
314 
315 
316 // -----------------------------------------------------------------------------
317 template <typename T /* = int */>
319 
320  return std::accumulate(fRanges.begin(), fRanges.end(), 0U,
321  [](std::size_t s, Range_t const& r){ return s + r.size(); });
322 
323 } // icarus::details::IntegerRangesBase<>::size()
324 
325 
326 // -----------------------------------------------------------------------------
327 template <typename T /* = int */>
329  { return fRanges.size(); }
330 
331 
332 // -----------------------------------------------------------------------------
333 template <typename T /* = int */>
334 decltype(auto) icarus::details::IntegerRangesBase<T>::ranges() const noexcept
335  { return fRanges; }
336 
337 
338 // -----------------------------------------------------------------------------
339 template <typename T /* = int */>
340 template <bool CheckGrowing, typename BIter, typename EIter>
342  -> std::vector<Range_t>
343 {
344  if (b == e) return {};
345 
346  std::vector<Range_t> ranges;
347 
348  auto it = b;
349  auto iPrev = it; // not sure if BIter default-constructible, so copy instead
350  auto iFirst = b;
351 
352  while (it != e) {
353 
354  iPrev = it++;
355 
356  if (it != e) { // check current and previous elements
357  if (*iPrev == *it) continue; // duplicate entry: quietly skip
358  if constexpr (CheckGrowing) {
359  if (*it < *iPrev) {
360  using std::to_string;
361  throw std::runtime_error{ "icarus::IntegerRanges"
362  " initialized with non-monotonically growing sequence ("
363  + to_string(*iPrev) + " then " + to_string(*it)
364  + ")"
365  };
366  }
367  } // if checking growth
368  } // if not at the end
369 
370  auto const nextExpected = plusOne(*iPrev);
371 
372  if ((it != e) && (*it == nextExpected)) continue; // contiguous to previous
373 
374  ranges.emplace_back(*iFirst, nextExpected);
375 
376  iFirst = it;
377 
378  } // while
379 
380  return ranges;
381 } // icarus::details::IntegerRangesBase<>::compactRange()
382 
383 
384 // -----------------------------------------------------------------------------
385 template <typename T /* = int */>
387  (Data_t value) noexcept -> Data_t
388  { return ++value; }
389 
390 
391 // -----------------------------------------------------------------------------
392 template <typename T /* = int */>
394  (Data_t value) noexcept -> Data_t
395  { return --value; }
396 
397 
398 // -----------------------------------------------------------------------------
399 template <typename T /* = int */>
401  std::ostream& out,
402  std::string const& sep /* = " " */,
403  std::string const& inRangeSep /* = "--" */
404 ) const {
405 
406  if (empty()) return;
407 
408  auto iRange = fRanges.begin();
409  auto const rend = fRanges.end();
410  iRange->dump(out, inRangeSep, sep);
411  while (++iRange != rend) iRange->dump(out << sep, inRangeSep, sep);
412 
413 } // icarus::details::IntegerRangesBase<>::dump()
414 
415 
416 // -----------------------------------------------------------------------------
417 // --- icarus::IntegerRanges<>
418 // -----------------------------------------------------------------------------
419 template <typename T /* = int */, bool CheckGrowing /* = true */>
420 template <typename BIter, typename EIter>
422  : Base_t{ Base_t::template compactRange<CheckGrowing>(b, e) }
423  {}
424 
425 
426 // -----------------------------------------------------------------------------
427 template <typename T /* = int */, bool CheckGrowing /* = true */>
429  (std::initializer_list<Data_t> data)
430  : IntegerRanges(data.begin(), data.end()) {}
431 
432 
433 // -----------------------------------------------------------------------------
434 template <typename T, bool CheckGrowing>
435 std::ostream& icarus::operator<<
436  (std::ostream& out, typename IntegerRanges<T, CheckGrowing>::Range_t const& r)
437  { r.dump(out); return out; }
438 
439 
440 // -----------------------------------------------------------------------------
441 template <typename T, bool CheckGrowing>
442 std::ostream& icarus::operator<<
443  (std::ostream& out, IntegerRanges<T, CheckGrowing> const& r)
444  { r.dump(out); return out; }
445 
446 
447 // -----------------------------------------------------------------------------
448 
449 
450 #endif // ICARUSALG_UTILITIES_INTEGERRANGES_H
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
static std::vector< Range_t > compactRange(BIter b, EIter e)
Fills the ranges.
std::size_t nRanges() const noexcept
Returns the number of non-contiguous ranges in the set.
T Data_t
Type of data for the range set.
Definition: IntegerRanges.h:79
constexpr Range_t() noexcept=default
static constexpr Data_t plusOne(Data_t value) noexcept
Returns value incremented by 1.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
IntegerRanges< typename Coll::value_type, CheckGrowing > makeIntegerRanges(Coll const &coll)
void clear() noexcept
Removes all the entries and makes the set as default-constructed.
constexpr bool empty() const noexcept
BEGIN_PROLOG default
void dump(std::ostream &out, std::string const &sep, std::string const &simpleSep) const
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
constexpr std::size_t size() const noexcept
std::size_t size() const noexcept
Returns the number of elements in the ranges (gaps excluded).
IntegerRangesBase()=default
Default constructor: starts with no elements.
static constexpr Data_t minusOne(Data_t value) noexcept
Returns value decremented by 1.
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
constexpr bool isTwo() const noexcept
bool empty() const noexcept
Returns whether there is any element in the range set.
IntegerRanges()=default
Default constructor: an empty set of ranges.
std::string to_string(WindowPattern const &pattern)
then echo File list $list not found else cat $list while read file do echo $file sed s
Definition: file_to_url.sh:60
A sequence of contiguous ranges of integral numbers.
Definition: IntegerRanges.h:41
do i e
constexpr bool isOne() const noexcept
std::vector< Range_t > fRanges
List of current ranges.
A sequence of contiguous ranges of integral numbers.
Definition: IntegerRanges.h:29
void dump(std::ostream &out, std::string const &sep=" ", std::string const &inRangeSep="--") const
temporary value
decltype(auto) ranges() const noexcept
Returns an iterable object with all sorted ranges as elements.
esac echo uname r
std::ostream & operator<<(std::ostream &out, typename IntegerRangesBase< T >::Data_t const &range)