rangeset.h

Go to the documentation of this file.
00001 /*
00002  *  This file is part of libcxxsupport.
00003  *
00004  *  libcxxsupport is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  libcxxsupport is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with libcxxsupport; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00017  */
00018 
00019 /*
00020  *  libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik
00021  *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
00022  *  (DLR).
00023  */
00024 
00025 /*! \file rangeset.h
00026  *  Class for storing sets of ranges of integer numbers
00027  *
00028  *  Copyright (C) 2011-2014 Max-Planck-Society
00029  *  \author Martin Reinecke
00030  */
00031 
00032 #ifndef PLANCK_RANGESET_H
00033 #define PLANCK_RANGESET_H
00034 
00035 #include <algorithm>
00036 #include <vector>
00037 #include <utility>
00038 #include <iostream>
00039 #include "datatypes.h"
00040 #include "error_handling.h"
00041 
00042 /*! Class for storing sets of ranges of integer numbers */
00043 template<typename T> class rangeset
00044   {
00045   private:
00046     typedef std::vector<T> rtype;
00047     typedef typename rtype::iterator iterator;
00048     typedef typename rtype::const_iterator c_iterator;
00049     rtype r;
00050 
00051     /*! Returns the index of the last number in \c r which is <= \a val.
00052         If \a val is smaller than all numbers in \c r, returns -1. */
00053     tdiff iiv (const T &val) const
00054       { return tdiff(std::upper_bound(r.begin(),r.end(),val)-r.begin())-1; }
00055 
00056     void addRemove (T a, T b, tdiff v)
00057       {
00058       tdiff pos1=iiv(a), pos2=iiv(b);
00059       if ((pos1>=0) && (r[pos1]==a)) --pos1;
00060       // first to delete is at pos1+1; last is at pos2
00061       bool insert_a = (pos1&1)==v;
00062       bool insert_b = (pos2&1)==v;
00063       tdiff rmstart=pos1+1+(insert_a ? 1 : 0);
00064       tdiff rmend  =pos2-(insert_b ? 1 : 0);
00065 
00066       planck_assert((rmend-rmstart)&1,"cannot happen");
00067 
00068       if (insert_a && insert_b && (pos1+1>pos2)) // insert
00069         {
00070         r.insert(r.begin()+pos1+1,2,a);
00071         r[pos1+2]=b;
00072         }
00073       else
00074         {
00075         if (insert_a) r[pos1+1]=a;
00076         if (insert_b) r[pos2]=b;
00077         r.erase(r.begin()+rmstart,r.begin()+rmend+1);
00078         }
00079       }
00080 
00081     /*! Estimate a good strategy for set operations involving two rangesets. */
00082     static int strategy (tsize sza, tsize szb)
00083       {
00084       const double fct1 = 1.;
00085       const double fct2 = 1.;
00086       tsize slo = sza<szb ? sza : szb,
00087             shi = sza<szb ? szb : sza;
00088       double cost1 = fct1 * (sza+szb);
00089       double cost2 = fct2 * slo * std::max(1,ilog2(shi));
00090       return (cost1<=cost2) ? 1 : (slo==sza) ? 2 : 3;
00091       }
00092 
00093     void generalUnion1 (const rangeset &a, const rangeset &b,
00094       bool flip_a, bool flip_b)
00095       {
00096       bool state_a=flip_a, state_b=flip_b, state_res=state_a||state_b;
00097       tsize ia=0, ea=a.r.size(), ib=0, eb=b.r.size();
00098       bool runa = ia!=ea, runb = ib!=eb;
00099       while(runa||runb)
00100         {
00101         T va = runa ? a.r[ia] : T(0),
00102           vb = runb ? b.r[ib] : T(0);
00103         bool adv_a = runa && (!runb || (va<=vb)),
00104              adv_b = runb && (!runa || (vb<=va));
00105         if (adv_a) { state_a=!state_a; ++ia; runa = ia!=ea; }
00106         if (adv_b) { state_b=!state_b; ++ib; runb = ib!=eb; }
00107         if ((state_a||state_b)!=state_res)
00108           { r.push_back(adv_a ? va : vb); state_res = !state_res; }
00109         }
00110       }
00111     void generalUnion2 (const rangeset &a, const rangeset &b,
00112       bool flip_a, bool flip_b)
00113       {
00114       tdiff iva = flip_a ? 0 : -1;
00115       tdiff asz=tdiff(a.r.size()), bsz=tdiff(b.r.size());
00116       while (iva<asz)
00117         {
00118         tdiff ivb = (iva==-1) ? -1 : b.iiv(a.r[iva]);
00119         bool state_b = flip_b^((ivb&1)==0);
00120         if ((iva>-1) && (!state_b)) r.push_back(a.r[iva]);
00121         while((ivb<bsz-1)&&((iva==asz-1)||(b.r[ivb+1]<a.r[iva+1])))
00122           { ++ivb; state_b=!state_b; r.push_back(b.r[ivb]); }
00123         if ((iva<asz-1)&&(!state_b)) r.push_back(a.r[iva+1]);
00124         iva+=2;
00125         }
00126       }
00127     void generalUnion (const rangeset &a, const rangeset &b,
00128       bool flip_a, bool flip_b)
00129       {
00130       planck_assert((this!=&a)&&(this!=&b), "cannot overwrite the rangeset");
00131       if (a.r.empty())
00132         {
00133         if (flip_a) clear(); else *this=b;
00134         return;
00135         }
00136       if (b.r.empty())
00137         {
00138         if (flip_b) clear(); else *this=a;
00139         return;
00140         }
00141 
00142       clear();
00143       int strat = strategy (a.nranges(), b.nranges());
00144       (strat==1) ? generalUnion1(a,b,flip_a,flip_b) :
00145         ((strat==2) ? generalUnion2(a,b,flip_a,flip_b)
00146                     : generalUnion2(b,a,flip_b,flip_a));
00147       }
00148     void generalXor (const rangeset &a, const rangeset &b)
00149       {
00150       clear();
00151       bool state_a=false, state_b=false, state_res=state_a||state_b;
00152       tsize ia=0, ea=a.r.size(), ib=0, eb=b.r.size();
00153       bool runa = ia!=ea, runb = ib!=eb;
00154       while(runa||runb)
00155         {
00156         T va = runa ? a.r[ia] : T(0),
00157           vb = runb ? b.r[ib] : T(0);
00158         bool adv_a = runa && (!runb || (va<=vb)),
00159              adv_b = runb && (!runa || (vb<=va));
00160         if (adv_a) { state_a=!state_a; ++ia; runa = ia!=ea; }
00161         if (adv_b) { state_b=!state_b; ++ib; runb = ib!=eb; }
00162         if ((state_a^state_b)!=state_res)
00163           { r.push_back(adv_a ? va : vb); state_res = !state_res; }
00164         }
00165       }
00166 
00167     static bool generalAllOrNothing1 (const rangeset &a, const rangeset &b,
00168       bool flip_a, bool flip_b)
00169       {
00170       bool state_a=flip_a, state_b=flip_b, state_res=state_a||state_b;
00171       tsize ia=0, ea=a.r.size(), ib=0, eb=b.r.size();
00172       bool runa = ia!=ea, runb = ib!=eb;
00173       while(runa||runb)
00174         {
00175         T va = runa ? a.r[ia] : T(0),
00176           vb = runb ? b.r[ib] : T(0);
00177         bool adv_a = runa && (!runb || (va<=vb)),
00178              adv_b = runb && (!runa || (vb<=va));
00179         if (adv_a) { state_a=!state_a; ++ia; runa = ia!=ea; }
00180         if (adv_b) { state_b=!state_b; ++ib; runb = ib!=eb; }
00181         if ((state_a||state_b)!=state_res)
00182           return false;
00183         }
00184       return true;
00185       }
00186     static bool generalAllOrNothing2 (const rangeset &a, const rangeset &b,
00187       bool flip_a, bool flip_b)
00188       {
00189       tdiff iva = flip_a ? 0 : -1;
00190       tdiff asz=tdiff(a.r.size()), bsz=tdiff(b.r.size());
00191       while (iva<asz)
00192         {
00193         if (iva==-1) // implies that flip_a==false
00194           { if ((!flip_b)||(b.r[0]<a.r[0])) return false; }
00195         else if (iva==asz-1) // implies that flip_a==false
00196           { if ((!flip_b)||(b.r[bsz-1]>a.r[asz-1])) return false; }
00197         else
00198           {
00199           tdiff ivb=b.iiv(a.r[iva]);
00200           if ((ivb!=bsz-1)&&(b.r[ivb+1]<a.r[iva+1])) return false;
00201           if (flip_b==((ivb&1)==0)) return false;
00202           }
00203         iva+=2;
00204         }
00205       return true;
00206       }
00207     static bool generalAllOrNothing (const rangeset &a, const rangeset &b,
00208       bool flip_a, bool flip_b)
00209       {
00210       if (a.r.empty())
00211         return flip_a ? true : b.r.empty();
00212       if (b.r.empty())
00213         return flip_b ? true : a.r.empty();
00214       int strat = strategy (a.nranges(), b.nranges());
00215       return (strat==1) ? generalAllOrNothing1(a,b,flip_a,flip_b) :
00216                ((strat==2) ? generalAllOrNothing2(a,b,flip_a,flip_b)
00217                            : generalAllOrNothing2(b,a,flip_b,flip_a));
00218       }
00219 
00220   public:
00221     /*! Removes all rangeset entries. */
00222     void clear() { r.clear(); }
00223     /*! Reserves space for \a n ranges. */
00224     void reserve(tsize n) { r.reserve(2*n); }
00225     /*! Returns the current number of ranges. */
00226     tsize nranges() const { return r.size()>>1; }
00227     tsize size() const { return nranges(); }
00228     bool empty() const { return r.empty(); }
00229     /*! Returns the current vector of ranges. */
00230     const rtype &data() const { return r; }
00231     void checkConsistency() const
00232       {
00233       planck_assert((r.size()&1)==0,"invalid number of entries");
00234       for (tsize i=1; i<r.size(); ++i)
00235         planck_assert(r[i]>r[i-1],"inconsistent entries");
00236       }
00237     void setData (const rtype &inp)
00238       {
00239       r=inp;
00240       checkConsistency();
00241       }
00242 
00243     /*! Returns the first value of range \a i. */
00244     const T &ivbegin (tdiff i) const { return r[2*i]; }
00245     /*! Returns the one-past-last value of range \a i. */
00246     const T &ivend (tdiff i) const { return r[2*i+1]; }
00247     /*! Returns the length of range \a i. */
00248     T ivlen (tdiff i) const { return r[2*i+1]-r[2*i]; }
00249 
00250     /*! Appends \a [v1;v2[ to the rangeset. \a v1 must be larger
00251         than the minimum of the last range in the rangeset. */
00252     void append(const T &v1, const T &v2)
00253       {
00254       if (v2<=v1) return;
00255       if ((!r.empty()) && (v1<=r.back()))
00256         {
00257         planck_assert (v1>=r[r.size()-2],"bad append operation");
00258         if (v2>r.back()) r.back()=v2;
00259         }
00260       else
00261         { r.push_back(v1); r.push_back(v2); }
00262       }
00263     /*! Appends \a [v;v+1[ to the rangeset. \a v must be larger
00264         than the minimum of the last range in the rangeset. */
00265     void append(const T &v)
00266       { append(v,v+1); }
00267 
00268     /*! Appends \a other to the rangeset. All values in \a other must be larger
00269         than the minimum of the last range in the rangeset. */
00270     void append (const rangeset &other)
00271       {
00272       for (tsize j=0; j<other.nranges(); ++j)
00273         append(other.ivbegin(j),other.ivend(j));
00274       }
00275 
00276     /*! After this operation, the rangeset contains the union of itself
00277         with \a [v1;v2[. */
00278     void add(const T &v1, const T &v2)
00279       {
00280       if (v2<=v1) return;
00281       if (r.empty() || (v1>=r[r.size()-2])) append(v1,v2);
00282       addRemove(v1,v2,1);
00283       }
00284     /*! After this operation, the rangeset contains the union of itself
00285         with \a [v;v+1[. */
00286     void add(const T &v) { add(v,v+1); }
00287 
00288     /*! Removes all values within \a [v1;v2[ from the rangeset. */
00289     void remove(const T &v1, const T &v2)
00290       {
00291       if (v2<=v1) return;
00292       if (r.empty()) return;
00293       if ((v2<=r[0])||(v1>=r.back())) return;
00294       if ((v1<=r[0]) && (v2>=r.back())) { r.clear(); return; }
00295       addRemove(v1,v2,0);
00296       }
00297     /*! Removes the value \a v from the rangeset. */
00298     void remove(const T &v) { remove(v,v+1); }
00299 
00300     /*! Removes all values not within \a [a;b[ from the rangeset. */
00301     void intersect (const T &a, const T &b)
00302       {
00303       if (r.empty()) return; // nothing to remove
00304       if ((b<=r[0]) || (a>=r.back())) { r.clear(); return; } // no overlap
00305       if ((a<=r[0]) && (b>=r.back())) return; // full rangeset in interval
00306 
00307       tdiff pos2=iiv(b);
00308       if ((pos2>=0) && (r[pos2]==b)) --pos2;
00309       bool insert_b = (pos2&1)==0;
00310       r.erase(r.begin()+pos2+1,r.end());
00311       if (insert_b) r.push_back(b);
00312 
00313       tdiff pos1=iiv(a);
00314       bool insert_a = (pos1&1)==0;
00315       if (insert_a) r[pos1--]=a;
00316       if (pos1>=0)
00317         r.erase(r.begin(),r.begin()+pos1+1);
00318       }
00319 
00320     /*! Returns the total number of elements in the rangeset. */
00321     T nval() const
00322       {
00323       T result=T(0);
00324       for (tsize i=0; i<r.size(); i+=2)
00325         result+=r[i+1]-r[i];
00326       return result;
00327       }
00328 
00329     /*! After this operation, \a res contains all elements of the rangeset
00330         in ascending order. */
00331     void toVector (std::vector<T> &res) const
00332       {
00333       res.clear();
00334       res.reserve(nval());
00335       for (tsize i=0; i<r.size(); i+=2)
00336         for (T m(r[i]); m<r[i+1]; ++m)
00337           res.push_back(m);
00338       }
00339 
00340     /*! Returns a vector containing all elements of the rangeset in ascending
00341         order. */
00342     std::vector<T> toVector() const
00343       {
00344       std::vector<T> res;
00345       toVector(res);
00346       return res;
00347       }
00348 
00349     /*! Returns the union of this rangeset and \a other. */
00350     rangeset op_or (const rangeset &other) const
00351       {
00352       rangeset res;
00353       res.generalUnion (*this,other,false,false);
00354       return res;
00355       }
00356     /*! Returns the intersection of this rangeset and \a other. */
00357     rangeset op_and (const rangeset &other) const
00358       {
00359       rangeset res;
00360       res.generalUnion (*this,other,true,true);
00361       return res;
00362       }
00363     /*! Returns the part of this rangeset which is not in \a other. */
00364     rangeset op_andnot (const rangeset &other) const
00365       {
00366       rangeset res;
00367       res.generalUnion (*this,other,true,false);
00368       return res;
00369       }
00370     /*! Returns the parts of this rangeset and \a other, which are not in
00371         both rangesets. */
00372     rangeset op_xor (const rangeset &other) const
00373       {
00374       rangeset res;
00375       res.generalXor (*this,other);
00376       return res;
00377       }
00378 
00379     /*! Returns the index of the interval containing \a v; if no such interval
00380         exists, -1 is returned. */
00381     tdiff findInterval (const T &v) const
00382       {
00383       tdiff res = iiv(v);
00384       return (res&1) ? -1 : res>>1;
00385       }
00386 
00387     /*! Returns \a true if the rangeset is identical to \a other, else \a false.
00388         */
00389     bool operator== (const rangeset &other) const
00390       { return r==other.r; }
00391 
00392     /*! Returns \a true if the rangeset contains all values in the range
00393         \a [a;b[, else \a false. */
00394     bool contains (T a,T b) const
00395       {
00396       tdiff res=iiv(a);
00397       if (res&1) return false;
00398       return (b<=r[res+1]);
00399       }
00400     /*! Returns \a true if the rangeset contains the value \a v,
00401         else \a false. */
00402     bool contains (T v) const
00403       { return !(iiv(v)&1); }
00404     /*! Returns \a true if the rangeset contains all values stored in \a other,
00405         else \a false. */
00406     bool contains (const rangeset &other) const
00407       { return generalAllOrNothing(*this,other,false,true); }
00408     /** Returns true if any of the numbers [a;b[ are contained in the set,
00409         else false. */
00410     bool overlaps (T a,T b) const
00411       {
00412       tdiff res=iiv(a);
00413       if ((res&1)==0) return true;
00414       if (res==tdiff(r.size())-1) return false; // beyond the end of the set
00415       return (r[res+1]<b);
00416       }
00417     /** Returns true if there is overlap between the set and "other",
00418         else false. */
00419     bool overlaps (const rangeset &other) const
00420       { return !generalAllOrNothing(*this,other,true,true); }
00421   };
00422 
00423 template<typename T> inline std::ostream &operator<< (std::ostream &os,
00424   const rangeset<T> &rs)
00425   {
00426   os << "{ ";
00427   for (tsize i=0; i<rs.nranges(); ++i)
00428     os << "["<<rs.ivbegin(i)<<";"<<rs.ivend(i)<<"[ ";
00429   return os << "}";
00430   }
00431 
00432 #endif

Generated on Thu Oct 8 14:48:51 2015 for LevelS C++ support library