LevelS C++ support library  3.82
rangeset.h
Go to the documentation of this file.
1 /*
2  * This file is part of libcxxsupport.
3  *
4  * libcxxsupport is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * libcxxsupport is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with libcxxsupport; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 /*
20  * libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik
21  * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
22  * (DLR).
23  */
24 
25 /*! \file rangeset.h
26  * Class for storing sets of ranges of integer numbers
27  *
28  * Copyright (C) 2011-2021 Max-Planck-Society
29  * \author Martin Reinecke
30  */
31 
32 #ifndef PLANCK_RANGESET_H
33 #define PLANCK_RANGESET_H
34 
35 #include <algorithm>
36 #include <vector>
37 #include <utility>
38 #include <iostream>
39 #include "datatypes.h"
40 #include "error_handling.h"
41 #include "math_utils.h"
42 
43 /*! Class for storing sets of ranges of integer numbers */
44 template<typename T> class rangeset
45  {
46  public:
47  typedef std::vector<T> rtype;
48 
49  private:
50  typedef typename rtype::iterator iterator;
51  typedef typename rtype::const_iterator c_iterator;
52  rtype r;
53 
54  /*! Returns the index of the last number in \c r which is <= \a val.
55  If \a val is smaller than all numbers in \c r, returns -1. */
56  tdiff iiv (const T &val) const
57  { return tdiff(std::upper_bound(r.begin(),r.end(),val)-r.begin())-1; }
58 
59  void addRemove (T a, T b, tdiff v)
60  {
61  tdiff pos1=iiv(a), pos2=iiv(b);
62  if ((pos1>=0) && (r[pos1]==a)) --pos1;
63  // first to delete is at pos1+1; last is at pos2
64  bool insert_a = (pos1&1)==v;
65  bool insert_b = (pos2&1)==v;
66  tdiff rmstart=pos1+1+(insert_a ? 1 : 0);
67  tdiff rmend =pos2-(insert_b ? 1 : 0);
68 
69  planck_assert((rmend-rmstart)&1,"cannot happen");
70 
71  if (insert_a && insert_b && (pos1+1>pos2)) // insert
72  {
73  r.insert(r.begin()+pos1+1,2,a);
74  r[pos1+2]=b;
75  }
76  else
77  {
78  if (insert_a) r[pos1+1]=a;
79  if (insert_b) r[pos2]=b;
80  r.erase(r.begin()+rmstart,r.begin()+rmend+1);
81  }
82  }
83 
84  /*! Estimate a good strategy for set operations involving two rangesets. */
85  static int strategy (tsize sza, tsize szb)
86  {
87  const double fct1 = 1.;
88  const double fct2 = 1.;
89  tsize slo = sza<szb ? sza : szb,
90  shi = sza<szb ? szb : sza;
91  double cost1 = fct1 * (sza+szb);
92  double cost2 = fct2 * slo * std::max(1,ilog2(shi));
93  return (cost1<=cost2) ? 1 : (slo==sza) ? 2 : 3;
94  }
95 
96  void generalUnion1 (const rangeset &a, const rangeset &b,
97  bool flip_a, bool flip_b)
98  {
99  bool state_a=flip_a, state_b=flip_b, state_res=state_a||state_b;
100  tsize ia=0, ea=a.r.size(), ib=0, eb=b.r.size();
101  bool runa = ia!=ea, runb = ib!=eb;
102  while(runa||runb)
103  {
104  T va = runa ? a.r[ia] : T(0),
105  vb = runb ? b.r[ib] : T(0);
106  bool adv_a = runa && (!runb || (va<=vb)),
107  adv_b = runb && (!runa || (vb<=va));
108  if (adv_a) { state_a=!state_a; ++ia; runa = ia!=ea; }
109  if (adv_b) { state_b=!state_b; ++ib; runb = ib!=eb; }
110  if ((state_a||state_b)!=state_res)
111  { r.push_back(adv_a ? va : vb); state_res = !state_res; }
112  }
113  }
114  void generalUnion2 (const rangeset &a, const rangeset &b,
115  bool flip_a, bool flip_b)
116  {
117  tdiff iva = flip_a ? 0 : -1;
118  tdiff asz=tdiff(a.r.size()), bsz=tdiff(b.r.size());
119  while (iva<asz)
120  {
121  tdiff ivb = (iva==-1) ? -1 : b.iiv(a.r[iva]);
122  bool state_b = flip_b^((ivb&1)==0);
123  if ((iva>-1) && (!state_b)) r.push_back(a.r[iva]);
124  while((ivb<bsz-1)&&((iva==asz-1)||(b.r[ivb+1]<a.r[iva+1])))
125  { ++ivb; state_b=!state_b; r.push_back(b.r[ivb]); }
126  if ((iva<asz-1)&&(!state_b)) r.push_back(a.r[iva+1]);
127  iva+=2;
128  }
129  }
130  void generalUnion (const rangeset &a, const rangeset &b,
131  bool flip_a, bool flip_b)
132  {
133  planck_assert((this!=&a)&&(this!=&b), "cannot overwrite the rangeset");
134  if (a.r.empty())
135  {
136  if (flip_a) clear(); else *this=b;
137  return;
138  }
139  if (b.r.empty())
140  {
141  if (flip_b) clear(); else *this=a;
142  return;
143  }
144 
145  clear();
146  int strat = strategy (a.nranges(), b.nranges());
147  (strat==1) ? generalUnion1(a,b,flip_a,flip_b) :
148  ((strat==2) ? generalUnion2(a,b,flip_a,flip_b)
149  : generalUnion2(b,a,flip_b,flip_a));
150  }
151  void generalXor (const rangeset &a, const rangeset &b)
152  {
153  clear();
154  bool state_a=false, state_b=false, state_res=state_a||state_b;
155  tsize ia=0, ea=a.r.size(), ib=0, eb=b.r.size();
156  bool runa = ia!=ea, runb = ib!=eb;
157  while(runa||runb)
158  {
159  T va = runa ? a.r[ia] : T(0),
160  vb = runb ? b.r[ib] : T(0);
161  bool adv_a = runa && (!runb || (va<=vb)),
162  adv_b = runb && (!runa || (vb<=va));
163  if (adv_a) { state_a=!state_a; ++ia; runa = ia!=ea; }
164  if (adv_b) { state_b=!state_b; ++ib; runb = ib!=eb; }
165  if ((state_a^state_b)!=state_res)
166  { r.push_back(adv_a ? va : vb); state_res = !state_res; }
167  }
168  }
169 
170  static bool generalAllOrNothing1 (const rangeset &a, const rangeset &b,
171  bool flip_a, bool flip_b)
172  {
173  bool state_a=flip_a, state_b=flip_b, state_res=state_a||state_b;
174  tsize ia=0, ea=a.r.size(), ib=0, eb=b.r.size();
175  bool runa = ia!=ea, runb = ib!=eb;
176  while(runa||runb)
177  {
178  T va = runa ? a.r[ia] : T(0),
179  vb = runb ? b.r[ib] : T(0);
180  bool adv_a = runa && (!runb || (va<=vb)),
181  adv_b = runb && (!runa || (vb<=va));
182  if (adv_a) { state_a=!state_a; ++ia; runa = ia!=ea; }
183  if (adv_b) { state_b=!state_b; ++ib; runb = ib!=eb; }
184  if ((state_a||state_b)!=state_res)
185  return false;
186  }
187  return true;
188  }
189  static bool generalAllOrNothing2 (const rangeset &a, const rangeset &b,
190  bool flip_a, bool flip_b)
191  {
192  tdiff iva = flip_a ? 0 : -1;
193  tdiff asz=tdiff(a.r.size()), bsz=tdiff(b.r.size());
194  while (iva<asz)
195  {
196  if (iva==-1) // implies that flip_a==false
197  { if ((!flip_b)||(b.r[0]<a.r[0])) return false; }
198  else if (iva==asz-1) // implies that flip_a==false
199  { if ((!flip_b)||(b.r[bsz-1]>a.r[asz-1])) return false; }
200  else
201  {
202  tdiff ivb=b.iiv(a.r[iva]);
203  if ((ivb!=bsz-1)&&(b.r[ivb+1]<a.r[iva+1])) return false;
204  if (flip_b==((ivb&1)==0)) return false;
205  }
206  iva+=2;
207  }
208  return true;
209  }
210  static bool generalAllOrNothing (const rangeset &a, const rangeset &b,
211  bool flip_a, bool flip_b)
212  {
213  if (a.r.empty())
214  return flip_a ? true : b.r.empty();
215  if (b.r.empty())
216  return flip_b ? true : a.r.empty();
217  int strat = strategy (a.nranges(), b.nranges());
218  return (strat==1) ? generalAllOrNothing1(a,b,flip_a,flip_b) :
219  ((strat==2) ? generalAllOrNothing2(a,b,flip_a,flip_b)
220  : generalAllOrNothing2(b,a,flip_b,flip_a));
221  }
222 
223  public:
224  /*! Removes all rangeset entries. */
225  void clear() { r.clear(); }
226  /*! Reserves space for \a n ranges. */
227  void reserve(tsize n) { r.reserve(2*n); }
228  /*! Returns the current number of ranges. */
229  tsize nranges() const { return r.size()>>1; }
230  tsize size() const { return nranges(); }
231  bool empty() const { return r.empty(); }
232  /*! Returns the current vector of ranges. */
233  const rtype &data() const { return r; }
234  void checkConsistency() const
235  {
236  planck_assert((r.size()&1)==0,"invalid number of entries");
237  for (tsize i=1; i<r.size(); ++i)
238  planck_assert(r[i]>r[i-1],"inconsistent entries");
239  }
240  void setData (const rtype &inp)
241  {
242  r=inp;
243  checkConsistency();
244  }
245 
246  /*! Returns the first value of range \a i. */
247  const T &ivbegin (tdiff i) const { return r[2*i]; }
248  /*! Returns the one-past-last value of range \a i. */
249  const T &ivend (tdiff i) const { return r[2*i+1]; }
250  /*! Returns the length of range \a i. */
251  T ivlen (tdiff i) const { return r[2*i+1]-r[2*i]; }
252 
253  /*! Appends \a [v1;v2[ to the rangeset. \a v1 must be larger
254  than the minimum of the last range in the rangeset. */
255  void append(const T &v1, const T &v2)
256  {
257  if (v2<=v1) return;
258  if ((!r.empty()) && (v1<=r.back()))
259  {
260  planck_assert (v1>=r[r.size()-2],"bad append operation");
261  if (v2>r.back()) r.back()=v2;
262  }
263  else
264  { r.push_back(v1); r.push_back(v2); }
265  }
266  /*! Appends \a [v;v+1[ to the rangeset. \a v must be larger
267  than the minimum of the last range in the rangeset. */
268  void append(const T &v)
269  { append(v,v+1); }
270 
271  /*! Appends \a other to the rangeset. All values in \a other must be larger
272  than the minimum of the last range in the rangeset. */
273  void append (const rangeset &other)
274  {
275  for (tsize j=0; j<other.nranges(); ++j)
276  append(other.ivbegin(j),other.ivend(j));
277  }
278 
279  /*! After this operation, the rangeset contains the union of itself
280  with \a [v1;v2[. */
281  void add(const T &v1, const T &v2)
282  {
283  if (v2<=v1) return;
284  if (r.empty() || (v1>=r[r.size()-2])) append(v1,v2);
285  addRemove(v1,v2,1);
286  }
287  /*! After this operation, the rangeset contains the union of itself
288  with \a [v;v+1[. */
289  void add(const T &v) { add(v,v+1); }
290 
291  /*! Removes all values within \a [v1;v2[ from the rangeset. */
292  void remove(const T &v1, const T &v2)
293  {
294  if (v2<=v1) return;
295  if (r.empty()) return;
296  if ((v2<=r[0])||(v1>=r.back())) return;
297  if ((v1<=r[0]) && (v2>=r.back())) { r.clear(); return; }
298  addRemove(v1,v2,0);
299  }
300  /*! Removes the value \a v from the rangeset. */
301  void remove(const T &v) { remove(v,v+1); }
302 
303  /*! Removes all values not within \a [a;b[ from the rangeset. */
304  void intersect (const T &a, const T &b)
305  {
306  if (r.empty()) return; // nothing to remove
307  if ((b<=r[0]) || (a>=r.back())) { r.clear(); return; } // no overlap
308  if ((a<=r[0]) && (b>=r.back())) return; // full rangeset in interval
309 
310  tdiff pos2=iiv(b);
311  if ((pos2>=0) && (r[pos2]==b)) --pos2;
312  bool insert_b = (pos2&1)==0;
313  r.erase(r.begin()+pos2+1,r.end());
314  if (insert_b) r.push_back(b);
315 
316  tdiff pos1=iiv(a);
317  bool insert_a = (pos1&1)==0;
318  if (insert_a) r[pos1--]=a;
319  if (pos1>=0)
320  r.erase(r.begin(),r.begin()+pos1+1);
321  }
322 
323  /*! Returns the total number of elements in the rangeset. */
324  T nval() const
325  {
326  T result=T(0);
327  for (tsize i=0; i<r.size(); i+=2)
328  result+=r[i+1]-r[i];
329  return result;
330  }
331 
332  /*! After this operation, \a res contains all elements of the rangeset
333  in ascending order. */
334  void toVector (std::vector<T> &res) const
335  {
336  res.clear();
337  res.reserve(nval());
338  for (tsize i=0; i<r.size(); i+=2)
339  for (T m(r[i]); m<r[i+1]; ++m)
340  res.push_back(m);
341  }
342 
343  /*! Returns a vector containing all elements of the rangeset in ascending
344  order. */
345  std::vector<T> toVector() const
346  {
347  std::vector<T> res;
348  toVector(res);
349  return res;
350  }
351 
352  /*! Returns the union of this rangeset and \a other. */
353  rangeset op_or (const rangeset &other) const
354  {
355  rangeset res;
356  res.generalUnion (*this,other,false,false);
357  return res;
358  }
359  /*! Returns the intersection of this rangeset and \a other. */
360  rangeset op_and (const rangeset &other) const
361  {
362  rangeset res;
363  res.generalUnion (*this,other,true,true);
364  return res;
365  }
366  /*! Returns the part of this rangeset which is not in \a other. */
367  rangeset op_andnot (const rangeset &other) const
368  {
369  rangeset res;
370  res.generalUnion (*this,other,true,false);
371  return res;
372  }
373  /*! Returns the parts of this rangeset and \a other, which are not in
374  both rangesets. */
375  rangeset op_xor (const rangeset &other) const
376  {
377  rangeset res;
378  res.generalXor (*this,other);
379  return res;
380  }
381 
382  /*! Returns the index of the interval containing \a v; if no such interval
383  exists, -1 is returned. */
384  tdiff findInterval (const T &v) const
385  {
386  tdiff res = iiv(v);
387  return (res&1) ? -1 : res>>1;
388  }
389 
390  /*! Returns \a true if the rangeset is identical to \a other, else \a false.
391  */
392  bool operator== (const rangeset &other) const
393  { return r==other.r; }
394 
395  /*! Returns \a true if the rangeset contains all values in the range
396  \a [a;b[, else \a false. */
397  bool contains (T a,T b) const
398  {
399  tdiff res=iiv(a);
400  if (res&1) return false;
401  return (b<=r[res+1]);
402  }
403  /*! Returns \a true if the rangeset contains the value \a v,
404  else \a false. */
405  bool contains (T v) const
406  { return !(iiv(v)&1); }
407  /*! Returns \a true if the rangeset contains all values stored in \a other,
408  else \a false. */
409  bool contains (const rangeset &other) const
410  { return generalAllOrNothing(*this,other,false,true); }
411  /** Returns true if any of the numbers [a;b[ are contained in the set,
412  else false. */
413  bool overlaps (T a,T b) const
414  {
415  tdiff res=iiv(a);
416  if ((res&1)==0) return true;
417  if (res==tdiff(r.size())-1) return false; // beyond the end of the set
418  return (r[res+1]<b);
419  }
420  /** Returns true if there is overlap between the set and "other",
421  else false. */
422  bool overlaps (const rangeset &other) const
423  { return !generalAllOrNothing(*this,other,true,true); }
424  };
425 
426 template<typename T> inline std::ostream &operator<< (std::ostream &os,
427  const rangeset<T> &rs)
428  {
429  os << "{ ";
430  for (tsize i=0; i<rs.nranges(); ++i)
431  os << "["<<rs.ivbegin(i)<<";"<<rs.ivend(i)<<"[ ";
432  return os << "}";
433  }
434 
435 #endif
T nval() const
Definition: rangeset.h:324
bool operator==(const rangeset &other) const
Definition: rangeset.h:392
bool contains(const rangeset &other) const
Definition: rangeset.h:409
void append(const T &v)
Definition: rangeset.h:268
void reserve(tsize n)
Definition: rangeset.h:227
bool contains(T a, T b) const
Definition: rangeset.h:397
void add(const T &v)
Definition: rangeset.h:289
T ivlen(tdiff i) const
Definition: rangeset.h:251
rangeset op_xor(const rangeset &other) const
Definition: rangeset.h:375
const rtype & data() const
Definition: rangeset.h:233
rangeset op_and(const rangeset &other) const
Definition: rangeset.h:360
std::ostream & operator<<(std::ostream &os, const pointing &p)
void toVector(std::vector< T > &res) const
Definition: rangeset.h:334
tsize nranges() const
Definition: rangeset.h:229
bool overlaps(const rangeset &other) const
Definition: rangeset.h:422
void intersect(const T &a, const T &b)
Definition: rangeset.h:304
std::size_t tsize
Definition: datatypes.h:116
int ilog2(I arg)
Definition: math_utils.h:125
std::ptrdiff_t tdiff
Definition: datatypes.h:118
std::vector< T > toVector() const
Definition: rangeset.h:345
bool contains(T v) const
Definition: rangeset.h:405
tdiff findInterval(const T &v) const
Definition: rangeset.h:384
bool overlaps(T a, T b) const
Definition: rangeset.h:413
void append(const T &v1, const T &v2)
Definition: rangeset.h:255
void add(const T &v1, const T &v2)
Definition: rangeset.h:281
rangeset op_or(const rangeset &other) const
Definition: rangeset.h:353
const T & ivbegin(tdiff i) const
Definition: rangeset.h:247
#define planck_assert(testval, msg)
void clear()
Definition: rangeset.h:225
void append(const rangeset &other)
Definition: rangeset.h:273
const T & ivend(tdiff i) const
Definition: rangeset.h:249
rangeset op_andnot(const rangeset &other) const
Definition: rangeset.h:367

Generated on Thu Jul 28 2022 17:32:06 for LevelS C++ support library