compress_utils.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 compress_utils.h
00026  *  Support for compression of integer arrays.
00027  *
00028  *  Copyright (C) 2013-2015 Max-Planck-Society
00029  *  \author Martin Reinecke
00030  */
00031 
00032 #ifndef PLANCK_COMPRESS_UTILS_H
00033 #define PLANCK_COMPRESS_UTILS_H
00034 
00035 #include <limits>
00036 #include <vector>
00037 #include <iterator>
00038 
00039 #include "datatypes.h"
00040 #include "error_handling.h"
00041 #include "math_utils.h"
00042 
00043 class obitstream
00044   {
00045   private:
00046     std::vector<uint8> data;
00047     tsize bitpos;
00048 
00049     template<typename T> void put_internal (const T &val, uint8 bits)
00050       {
00051       int bitsleft = 8-(bitpos&7);
00052       if (bitsleft==8) data.push_back(0);
00053       if (bits<=bitsleft) // wbits==bits
00054         {
00055         data.back() |= ((val&((T(1)<<bits)-1))<<(bitsleft-bits));
00056         bitpos+=bits;
00057         }
00058       else // wbits==bitsleft
00059         {
00060         data.back() |= ((val>>(bits-bitsleft))&((1<<bitsleft)-1));
00061         bitpos+=bitsleft;
00062         put_internal(val,bits-bitsleft);
00063         }
00064       }
00065 
00066   public:
00067     obitstream() : bitpos(0) {}
00068 
00069     template<typename T> void put (const T &val, uint8 bits)
00070       {
00071       if (bits==0) return;
00072       planck_assert(bits<=(sizeof(T)<<3),"too many bits for this data type");
00073 //      planck_assert(val-(val&((T(1)<<bits)-1))==0,"value has too many bits");
00074       put_internal(val,bits);
00075       }
00076 
00077     const std::vector<uint8> &state() const
00078       { return data; }
00079   };
00080 
00081 class ibitstream
00082   {
00083   private:
00084     const std::vector<uint8> data;
00085     tsize bitpos;
00086 
00087     template<typename T> void get_internal (T &val, int bits)
00088       {
00089       int bitsleft = 8-(bitpos&7);
00090       if (bits<=bitsleft)
00091         {
00092         val |= ((data[bitpos>>3]>>(bitsleft-bits))&((1<<bits)-1));
00093         bitpos+=bits;
00094         }
00095       else
00096         {
00097         val |= T((data[bitpos>>3])&((1<<bitsleft)-1))<<(bits-bitsleft);
00098         bitpos+=bitsleft;
00099         get_internal(val,bits-bitsleft);
00100         }
00101       }
00102   public:
00103     ibitstream(const std::vector<uint8> &indata) : data(indata), bitpos(0) {}
00104 
00105     template<typename T> T get (uint8 bits)
00106       {
00107       if (bits==0) return T(0);
00108       planck_assert(bits<=(sizeof(T)<<3),"too many bits for this data type");
00109       planck_assert((bitpos+bits)<=8*data.size(),"reading past end of stream");
00110       T res=T(0);
00111       get_internal(res,bits);
00112       return res;
00113       }
00114   };
00115 
00116 template<typename T,bool> struct notNegativeHelper__
00117   { notNegativeHelper__(const T &) {} };
00118 template<typename T> struct notNegativeHelper__<T,true>
00119   {
00120   notNegativeHelper__(const T &val)
00121     { planck_assert(val>=T(0),"numbers must be nonnegative");}
00122   };
00123 template<typename T> void assertNotNegative(const T &val)
00124   { notNegativeHelper__<T,std::numeric_limits<T>::is_signed> dummy(val); }
00125 
00126 template<typename Iter> void interpol_encode2 (Iter l, Iter r, obitstream &obs,
00127   int shift)
00128   {
00129   if (r-l<=1) return;
00130   typedef std::iterator_traits<Iter> traits;
00131   typedef typename traits::value_type T;
00132 
00133   Iter m=l+(r-l)/2;
00134   T nval = ((*r-*l)>>shift) - (r-l) + 1;
00135   if (nval<=1) return;
00136 
00137   uint8 nb = 1+ilog2(nval-1);
00138   T val = ((*m)>>shift)-(((*l)>>shift)+(m-l));
00139   T nshort=(T(1)<<nb)-nval;
00140 #if 0
00141   // optional rotation
00142   T nrot=nval-(nshort>>1);
00143   if (val>=nrot)
00144     val-=nrot;
00145   else
00146     val+=(nval-nrot);
00147 #endif
00148   if (val<nshort)
00149     obs.put(val,nb-1);
00150   else
00151     obs.put(val+nshort,nb);
00152   interpol_encode2(l,m,obs,shift);
00153   interpol_encode2(m,r,obs,shift);
00154   }
00155 
00156 template<typename Iter> void interpol_encode (Iter l, Iter r, obitstream &obs)
00157   {
00158   typedef std::iterator_traits<Iter> traits;
00159   typedef typename traits::value_type T;
00160 
00161   if (l==r) // empty range
00162     { obs.put(0,8); return; }
00163 
00164   assertNotNegative(*l);
00165 
00166   T combo=*l;
00167   for (Iter i=l+1; i!=r; ++i)
00168     {
00169     planck_assert(*i>*(i-1),"numbers not strictly increasing");
00170     combo|=*i;
00171     }
00172   int shift = trailingZeros(combo);
00173   T maxnum=(*(r-1))>>shift;
00174   if (T(r-l)>maxnum) maxnum=T(r-l);
00175   uint8 maxbits=1+ilog2(maxnum);
00176   obs.put(maxbits,8);
00177   obs.put(shift,8);
00178   obs.put(r-l,maxbits);
00179   obs.put((*l)>>shift,maxbits);
00180   if (r-l==1) return;
00181   obs.put((*(r-1))>>shift,maxbits);
00182   interpol_encode2(l,r-1,obs,shift);
00183   }
00184 
00185 template<typename Iter> void interpol_decode2 (Iter l, Iter r, ibitstream &ibs,
00186   int shift)
00187   {
00188   if (r-l<=1) return;
00189   typedef std::iterator_traits<Iter> traits;
00190   typedef typename traits::value_type T;
00191 
00192   Iter m=l+(r-l)/2;
00193   T nval = ((*r-*l)>>shift) - (r-l) + 1;
00194   T val=0;
00195 
00196   if (nval>1)
00197     {
00198     uint8 nb = 1+ilog2(nval-1);
00199     T nshort=(T(1)<<nb)-nval;
00200     val=ibs.get<T>(nb-1);
00201     if (val>=nshort)
00202       val=(val<<1)+ ibs.get<T>(1) - nshort;
00203 #if 0
00204     // optional rotation
00205     T nrot=nval-(nshort>>1);
00206     if (val<(nval-nrot))
00207       val+=nrot;
00208     else
00209       val-=(nval-nrot);
00210 #endif
00211     }
00212   *m=*l+(((m-l)+val)<<shift);
00213 
00214   interpol_decode2(l,m,ibs,shift);
00215   interpol_decode2(m,r,ibs,shift);
00216   }
00217 
00218 template<typename T> void interpol_decode (std::vector<T> &v, ibitstream &ibs)
00219   {
00220   uint8 maxbits=ibs.get<uint8>(8);
00221   if (maxbits==0) { v.clear(); return; }
00222   int shift = ibs.get<int>(8);
00223   v.resize(ibs.get<tsize>(maxbits));
00224   v[0]=ibs.get<T>(maxbits)<<shift;
00225   if (v.size()==1) return;
00226   v[v.size()-1]=ibs.get<T>(maxbits)<<shift;
00227   interpol_decode2(v.begin(),v.end()-1,ibs,shift);
00228   }
00229 
00230 #endif

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