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, 2012 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     tdiff iiv (const T &val) const
00052       { return tdiff(std::upper_bound(r.begin(),r.end(),val)-r.begin())-1; }
00053 
00054     void addRemove (T a, T b, tdiff v)
00055       {
00056       tdiff pos1=iiv(a), pos2=iiv(b);
00057       if ((pos1>=0) && (r[pos1]==a)) --pos1;
00058       // first to delete is at pos1+1; last is at pos2
00059       bool insert_a = (pos1&1)==v;
00060       bool insert_b = (pos2&1)==v;
00061       int rmstart=pos1+1+(insert_a ? 1 : 0);
00062       int rmend  =pos2-(insert_b?1:0);
00063 
00064       planck_assert((rmend-rmstart)&1,"cannot happen");
00065 
00066       if (insert_a && insert_b && (pos1+1>pos2)) // insert
00067         {
00068         r.insert(r.begin()+pos1+1,2,a);
00069         r[pos1+2]=b;
00070         }
00071       else
00072         {
00073         if (insert_a) r[pos1+1]=a;
00074         if (insert_b) r[pos2]=b;
00075         r.erase(r.begin()+rmstart,r.begin()+rmend+1);
00076         }
00077       }
00078 
00079     static void generalUnion (const rtype &a, const rtype &b,
00080       bool flip_a, bool flip_b, rtype &c)
00081       {
00082       planck_assert((&c!=&a)&&(&c!=&b), "cannot overwrite the rangeset");
00083       c.clear();
00084       bool state_a=flip_a, state_b=flip_b, state_res=state_a||state_b;
00085       tsize ia=0, ea=a.size(), ib=0, eb=b.size();
00086       bool runa = ia!=ea, runb = ib!=eb;
00087       while(runa||runb)
00088         {
00089         bool adv_a=false, adv_b=false;
00090         T val,va=T(),vb=T();
00091         if (runa) va = a[ia];
00092         if (runb) vb = b[ib];
00093         if (runa && (!runb || (va<=vb))) { adv_a=true; val=va; }
00094         if (runb && (!runa || (vb<=va))) { adv_b=true; val=vb; }
00095         if (adv_a) { state_a=!state_a; ++ia; runa = ia!=ea; }
00096         if (adv_b) { state_b=!state_b; ++ib; runb = ib!=eb; }
00097         if ((state_a||state_b)!=state_res)
00098           { c.push_back(val); state_res = !state_res; }
00099         }
00100       }
00101 
00102   public:
00103     /*! Removes all rangeset entries. */
00104     void clear() { r.clear(); }
00105     /*! Reserves space for \a n ranges. */
00106     void reserve(tsize n) { r.reserve(2*n); }
00107     /*! Returns the current number of ranges. */
00108     tsize size() const { return r.size()>>1; }
00109     /*! Returns the current vector of ranges. */
00110     const rtype &data() const { return r; }
00111 
00112     /*! Returns the first value of range \a i. */
00113     const T &ivbegin (tdiff i) const { return r[2*i]; }
00114     /*! Returns the one-past-last value of range \a i. */
00115     const T &ivend (tdiff i) const { return r[2*i+1]; }
00116     /*! Returns the length of range \a i. */
00117     T ivlen (tdiff i) const { return r[2*i+1]-r[2*i]; }
00118 
00119     /*! Appends \a [v1;v2[ to the rangeset. \a v1 must be larger
00120         than the minimum of the last range in the rangeset. */
00121     void append(const T &v1, const T &v2)
00122       {
00123       if (v2<=v1) return;
00124       if ((!r.empty()) && (v1<=r.back()))
00125         {
00126         planck_assert (v1>=r[r.size()-2],"bad append operation");
00127         if (v2>r.back()) r.back()=v2;
00128         }
00129       else
00130         { r.push_back(v1); r.push_back(v2); }
00131       }
00132     /*! Appends \a [v;v+1[ to the rangeset. \a v must be larger
00133         than the minimum of the last range in the rangeset. */
00134     void append(const T &v)
00135       { append(v,v+1); }
00136 
00137     /*! Appends \a other to the rangeset. All values in \a other must be larger
00138         than the minimum of the last range in the rangeset. */
00139     void append (const rangeset &other)
00140       {
00141       for (tsize j=0; j<other.size(); ++j)
00142         append(other.ivbegin(j),other.ivend(j));
00143       }
00144 
00145     /*! After this operation, the rangeset contains the union of itself
00146         with \a [v1;v2[. */
00147     void add(const T &v1, const T &v2) { addRemove(v1,v2,1); }
00148     /*! After this operation, the rangeset contains the union of itself
00149         with \a [v;v+1[. */
00150     void add(const T &v) { addRemove(v,v+1,1); }
00151 
00152     /*! Removes all values within \a [v1;v2[ from the rangeset. */
00153     void remove(const T &v1, const T &v2) { addRemove(v1,v2,0); }
00154     /*! Removes the value \a v from the rangeset. */
00155     void remove(const T &v) { addRemove(v,v+1,0); }
00156 
00157     /*! Removes all values not within \a [v1;v2[ from the rangeset. */
00158     void intersect (const T &a, const T &b)
00159       {
00160       tdiff pos1=iiv(a), pos2=iiv(b);
00161       if ((pos2>=0) && (r[pos2]==b)) --pos2;
00162       // delete all up to pos1 (inclusive); and starting from pos2+1
00163       bool insert_a = (pos1&1)==0;
00164       bool insert_b = (pos2&1)==0;
00165 
00166       // cut off end
00167       r.erase(r.begin()+pos2+1,r.end());
00168       if (insert_b) r.push_back(b);
00169 
00170       // erase start
00171       if (insert_a) r[pos1--]=a;
00172       if (pos1>=0)
00173         r.erase(r.begin(),r.begin()+pos1+1);
00174       }
00175 
00176     /*! Returns the total number of elements in the rangeset. */
00177     T nval() const
00178       {
00179       T result=T(0);
00180       for (tsize i=0; i<r.size(); i+=2)
00181         result+=r[i+1]-r[i];
00182       return result;
00183       }
00184 
00185     /*! After this opration, \a res contains all elements of the rangeset
00186         in ascending order. */
00187     void toVector (std::vector<T> &res) const
00188       {
00189       res.clear();
00190       res.reserve(nval());
00191       for (tsize i=0; i<r.size(); i+=2)
00192         for (T m(r[i]); m<r[i+1]; ++m)
00193           res.push_back(m);
00194       }
00195 
00196     /*! After this operation, the rangeset contains the union of itself
00197         and \a other. */
00198     void unite (const rangeset &other)
00199       {
00200       rtype tmp;
00201       generalUnion (r,other.r,false,false,tmp);
00202       std::swap(r,tmp);
00203       }
00204     /*! After this operation, the rangeset contains the intersection of itself
00205         and \a other. */
00206     void intersect (const rangeset &other)
00207       {
00208       rtype tmp;
00209       generalUnion (r,other.r,true,true,tmp);
00210       std::swap(r,tmp);
00211       }
00212     /*! After this operation, the rangeset contains the union of itself
00213         with the inverse of \a other. */
00214     void subtract (const rangeset &other)
00215       {
00216       rtype tmp;
00217       generalUnion (r,other.r,true,false,tmp);
00218       std::swap(r,tmp);
00219       }
00220     /*! After this operation, the rangeset contains the union of \a a
00221         and \a b. */
00222     void setToUnion (const rangeset &a, const rangeset &b)
00223       { generalUnion (a.r,b.r,false,false,r); }
00224     /*! After this operation, the rangeset contains the intersection of \a a
00225         and \a b. */
00226     void setToIntersection (const rangeset &a, const rangeset &b)
00227       { generalUnion (a.r,b.r,true,true,r); }
00228     /*! After this operation, the rangeset contains the union of \a a
00229         with the inverse of \a b. */
00230     void setToDifference (const rangeset &a, const rangeset &b)
00231       { generalUnion (a.r,b.r,true,false,r); }
00232 
00233     /*! Returns the index of the interval containing \a v; if no such interval
00234         exists, -1 is returned. */
00235     tdiff findInterval (const T &v) const
00236       {
00237       tdiff res = iiv(v);
00238       return (res&1) ? -1 : res>>1;
00239       }
00240 
00241     /*! Returns \a true if the rangeset is identical to \a other, else \a false.
00242         */
00243     bool equals (const rangeset &other) const
00244       { return r==other.data(); }
00245 
00246     /*! Returns \a true if the rangeset contains all values in the range
00247         \a [a;b[, else \a false. */
00248     bool containsAll (T a,T b) const
00249       {
00250       tdiff res=iiv(a);
00251       if (res&1) return false;
00252       return (b<=r[res+1]);
00253       }
00254     /*! Returns \a true if the rangeset contains the value \a v,
00255         else \a false. */
00256     bool contains (T v) const
00257       { return !(iiv(v)&1); }
00258     /*! Returns \a true if the rangeset contains all values stored in \a other,
00259         else \a false. */
00260     bool contains (const rangeset &other) const
00261       {
00262       tsize im=0, em=r.size();
00263       for (tsize i=0; i<other.r.size(); i+=2)
00264         {
00265         T a=other.r[i], b=other.r[i+1];
00266         while ((im!=em) && (r[im+1] < a)) im+=2;
00267         if (im==em) return false;
00268         if ((r[im]>a) || (r[im+1]<b)) return false;
00269         }
00270       return true;
00271       }
00272   };
00273 
00274 template<typename T> inline std::ostream &operator<< (std::ostream &os,
00275   const rangeset<T> &rs)
00276   {
00277   os << "{ ";
00278   for (tsize i=0; i<rs.size(); ++i)
00279     os << "["<<rs.ivbegin(i)<<";"<<rs.ivend(i)<<"[ ";
00280   return os << "}";
00281   }
00282 
00283 #endif

Generated on Wed Apr 24 11:31:17 2013 for LevelS C++ support library