inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/wroot/buffer
Go to the documentation of this file.
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
00002 // See the file inlib.license for terms.
00003 
00004 #ifndef inlib_wroot_buffer
00005 #define inlib_wroot_buffer
00006 
00007 // class used for serializing objects.
00008 
00009 #include "wbuf"
00010 #include "ibo"
00011 
00012 #include "../realloc"
00013 #include "../mnmx"
00014 #ifdef INLIB_MEM
00015 #include "../mem"
00016 #endif
00017 
00018 #include <string>
00019 #include <vector>
00020 #include <ostream>
00021 #include <map>
00022 
00023 namespace inlib {
00024 namespace wroot {
00025 
00026 class buffer {
00027   static const std::string& s_class() {
00028     static const std::string s_v("inlib::wroot::buffer");
00029     return s_v;
00030   }
00031 public:
00032   buffer(std::ostream& a_out,
00033                 bool a_byte_swap,
00034                 uint32 a_size) // we expect a not zero value.
00035   :m_out(a_out)
00036   ,m_byte_swap(a_byte_swap)
00037   ,m_size(0)
00038   ,m_buffer(0)
00039   ,m_max(0)
00040   ,m_pos(0)
00041   ,m_wb(a_out,a_byte_swap,0,m_pos) //it holds a ref on m_pos.
00042   {
00043 #ifdef INLIB_MEM
00044     mem::increment(s_class().c_str());
00045 #endif
00046     m_size = a_size;
00047     m_buffer = new char[m_size];
00048     //if(!m_buffer) {}
00049     m_max = m_buffer+m_size;
00050     m_pos = m_buffer;
00051     m_wb.set_eob(m_max);
00052   }
00053 
00054   virtual ~buffer(){
00055     m_objs.clear();
00056     m_obj_mapped.clear();
00057 
00058     m_clss.clear();
00059     m_cls_mapped.clear();
00060 
00061     delete [] m_buffer;
00062 #ifdef INLIB_MEM
00063     mem::decrement(s_class().c_str());
00064 #endif
00065   }
00066 protected:
00067   buffer(const buffer& a_from)
00068   :m_out(a_from.m_out)
00069   ,m_byte_swap(a_from.m_byte_swap)
00070   ,m_size(0)
00071   ,m_buffer(0)
00072   ,m_max(0)
00073   ,m_pos(0)
00074   ,m_wb(a_from.m_out,a_from.m_byte_swap,0,m_pos)
00075   {
00076 #ifdef INLIB_MEM
00077     mem::increment(s_class().c_str());
00078 #endif
00079   }
00080   buffer& operator=(const buffer&){return *this;}
00081 public:
00082   std::ostream& out() const {return m_out;}
00083 
00084   //void set_offset(unsigned int a_off) {m_pos = m_buffer+a_off;}
00085 
00086   char* buf() {return m_buffer;}
00087   const char* buf() const {return m_buffer;}
00088   uint32 length() const {return m_pos-m_buffer;}
00089   uint32 size() const {return m_size;}
00090 
00091   char*& pos() {return m_pos;}          //used in basket.
00092   char* max_pos() const {return m_max;} //used in basket.
00093 
00094 public:
00095   template <class T>
00096   bool write(T x){
00097     if(m_pos+sizeof(T)>m_max) {
00098       if(!expand(m_size+sizeof(T))) return false;
00099     }
00100     return m_wb.write(x);
00101   }
00102 
00103   bool write(bool x){ 
00104     return write<unsigned char>(x?1:0);
00105   }
00106 
00107   bool write(const std::string& x) {
00108     uint32 sz = (uint32)(x.size() + sizeof(int) + 1);
00109     if((m_pos+sz)>m_max) {
00110       if(!expand(m_size+sz)) return false;
00111     }
00112     return m_wb.write(x);
00113   }
00114 
00115   bool write_fast_array(const char* a_a,uint32 a_n) {
00116     if(!a_n) return true;
00117     uint32 l = a_n * sizeof(char);
00118     if((m_pos+l)>m_max) {
00119       if(!expand(m_size+l)) return false;
00120     }
00121     ::memcpy(m_pos,a_a,l);
00122     m_pos += l;
00123     return true;
00124   }
00125 
00126   bool write_cstring(const char* a_s) {
00127     return write_fast_array(a_s,(::strlen(a_s)+1)*sizeof(char));
00128   }
00129 
00130   template <class T>
00131   bool write_fast_array(const T* a_a,uint32 a_n) {
00132     if(!a_n) return true;
00133     uint32 l = a_n * sizeof(T);
00134     if((m_pos+l)>m_max) {
00135       if(!expand(m_size+l)) return false;
00136     }
00137     return m_wb.write<T>(a_a,a_n);
00138   }
00139 
00140   template <class T>
00141   bool write_array(const T* a_a,uint32 a_n) {
00142     if(!write(a_n)) return false;
00143     return write_fast_array(a_a,a_n);
00144   }
00145 
00146 public:
00147   bool write_version(short a_version){
00148     if(a_version>kMaxVersion()) {
00149       m_out << "inlib::wroot::buffer::write_version :"
00150             << " version number " << a_version
00151             << " cannot be larger than " << kMaxVersion() << "."
00152             << std::endl;
00153       return false;
00154     }
00155     return write(a_version);
00156   }
00157   bool write_version(short a_version,uint32& a_pos){
00158     // reserve space for leading byte count
00159     a_pos = (uint32)(m_pos-m_buffer);
00160 
00161     //NOTE : the below test is lacking in CERN-ROOT !
00162     if((m_pos+sizeof(unsigned int))>m_max) {
00163       if(!expand(m_size+sizeof(unsigned int))) return false;
00164     }
00165     m_pos += sizeof(unsigned int);
00166 
00167     if(a_version>kMaxVersion()) {
00168       m_out << "inlib::wroot::buffer::write_version :"
00169             << " version number " << a_version
00170             << " cannot be larger than " << kMaxVersion() << "."
00171             << std::endl;
00172       return false;
00173     }
00174     return write(a_version);
00175   }
00176 
00177   bool set_byte_count(uint32 a_pos){
00178     uint32 cnt = (uint32)(m_pos-m_buffer) - a_pos - sizeof(unsigned int);
00179     if(cnt>=kMaxMapCount()) {
00180       m_out << "inlib::wroot::buffer::set_byte_count :"
00181             << " bytecount too large (more than "
00182             << kMaxMapCount() << ")."
00183             << std::endl;
00184       return false;
00185     }
00186 
00187     union {
00188       uint32 cnt;
00189       short vers[2];
00190     } v;
00191     v.cnt = cnt;
00192 
00193     char* opos = m_pos;
00194     m_pos = (char*)(m_buffer+a_pos);
00195     if(m_byte_swap) {
00196       if(!m_wb.write(short(v.vers[1]|kByteCountVMask()))) 
00197         {m_pos = opos;return false;}
00198       if(!m_wb.write(v.vers[0])) {m_pos = opos;return false;}
00199     } else {
00200       if(!m_wb.write(short(v.vers[0]|kByteCountVMask())))
00201         {m_pos = opos;return false;}
00202       if(!m_wb.write(v.vers[1])) {m_pos = opos;return false;}
00203     }
00204     m_pos = opos;
00205 
00206     return true;
00207   }
00208 
00209   bool write_object(const ibo& a_obj){
00210     //GB : if adding a write map logic, think to have a displace_mapped()
00211     //     in basket::write_on_file().
00212 
00213     std::map<ibo*,uint32>::const_iterator it = m_objs.find((ibo*)&a_obj);
00214     if(it!=m_objs.end()) {
00215       uint32 objIdx = (*it).second;
00216 
00217       unsigned int offset = (unsigned int)(m_pos-m_buffer);
00218 
00219       // save index of already stored object
00220       if(!write(objIdx)) return false;
00221 
00222       m_obj_mapped.push_back(std::pair<uint32,uint32>(offset,objIdx));
00223 
00224     } else {
00225 
00226       // reserve space for leading byte count
00227       uint32 cntpos = (unsigned int)(m_pos-m_buffer);
00228 
00229       //NOTE : the below test is lacking in CERN-ROOT !
00230       if((m_pos+sizeof(unsigned int))>m_max) {
00231         if(!expand(m_size+sizeof(unsigned int))) return false;
00232       }
00233       m_pos += sizeof(unsigned int);
00234     
00235       // write class of object first
00236       if(!write_class(a_obj.store_cls())) return false;
00237     
00238       // add to map before writing rest of object (to handle self reference)
00239       // (+kMapOffset so it's != kNullTag)
00240       m_objs[(ibo*)&a_obj] = cntpos + kMapOffset();
00241     
00242       // let the object write itself :
00243       if(!a_obj.stream(*this)) return false;
00244     
00245       // write byte count
00246       if(!set_byte_count_obj(cntpos)) return false;
00247     }
00248     return true;
00249   }
00250 
00251  
00252   bool expand(uint32 a_new_size) {
00253     unsigned long len = m_pos-m_buffer;
00254     if(!realloc<char>(m_buffer,a_new_size,m_size)) {
00255       m_out << "inlib::wroot::buffer::expand :"
00256             << " can't realloc " << a_new_size << " bytes."
00257             << std::endl;
00258       m_size = 0;
00259       m_max = 0;
00260       m_pos = 0;
00261       m_wb.set_eob(m_max);
00262       return false;
00263     }
00264     m_size = a_new_size;
00265     m_max = m_buffer + m_size;
00266     m_pos = m_buffer + len;
00267     m_wb.set_eob(m_max);
00268     return true;
00269   }
00270 
00271   unsigned int to_displace() const {
00272     return m_cls_mapped.size()+m_obj_mapped.size();
00273   }
00274 
00275   bool displace_mapped(unsigned int a_num){
00276     char* opos = m_pos;
00277 
00278     //m_out << "inlib::wroot::buffer::displace_mapped :"
00279     //      << " cls num " << m_cls_mapped.size()
00280     //      << std::endl;
00281 
00282    {std::vector< std::pair<uint32,uint32> >::const_iterator it;
00283     for(it=m_cls_mapped.begin();it!=m_cls_mapped.end();++it) {
00284       unsigned int offset = (*it).first;
00285       unsigned int id = (*it).second;
00286       //m_out << "displace " << offset << " " << id << std::endl;
00287       m_pos = m_buffer+offset;
00288       unsigned int clIdx = id+a_num;
00289       if(!write(uint32(clIdx|kClassMask()))) {m_pos = opos;return false;}
00290     }}
00291   
00292     //m_out << "inlib::wroot::buffer::displace_mapped :"
00293     //      << " obj num " << m_obj_mapped.size()
00294     //      << std::endl;
00295 
00296    {std::vector< std::pair<uint32,uint32> >::const_iterator it;
00297     for(it=m_obj_mapped.begin();it!=m_obj_mapped.end();++it) {
00298       uint32 offset = (*it).first;
00299       uint32 id = (*it).second;
00300       //m_out << "displace at " << offset
00301       //      << " the obj pos " << id
00302       //      << " by " << a_num
00303       //      << std::endl;
00304       m_pos = m_buffer+offset;
00305       unsigned int objIdx = id+a_num;
00306       if(!write(objIdx)) {m_pos = opos;return false;}
00307     }}
00308   
00309     m_pos = opos;
00310     return true;
00311   }
00312 
00313 protected:
00314   static short kMaxVersion() {return 0x3FFF;}
00315   static uint32 kMaxMapCount() {return 0x3FFFFFFE;}
00316   static short kByteCountVMask() {return 0x4000;}
00317   static uint32 kNewClassTag() {return 0xFFFFFFFF;}
00318 
00319   static int kMapOffset() {return 2;}
00320   static unsigned int kClassMask() {return 0x80000000;}
00321   static uint32 kByteCountMask() {return 0x40000000;}
00322 
00323   bool write_class(const std::string& a_cls){
00324 
00325     std::map<std::string,uint32>::const_iterator it = m_clss.find(a_cls);
00326     if(it!=m_clss.end()) {
00327       uint32 clIdx = (*it).second;
00328 
00329       unsigned int offset = (unsigned int)(m_pos-m_buffer);
00330 
00331       // save index of already stored class
00332       if(!write(uint32(clIdx|kClassMask()))) return false;
00333 
00334       m_cls_mapped.push_back(std::pair<uint32,uint32>(offset,clIdx));
00335 
00336     } else {
00337 
00338       unsigned int offset = (unsigned int)(m_pos-m_buffer);
00339       if(!write(kNewClassTag())) return false;
00340       if(!write_cstring(a_cls.c_str())) return false;
00341       m_clss[a_cls] = offset + kMapOffset();
00342 
00343     }
00344     return true;
00345   }
00346 
00347   bool set_byte_count_obj(uint32 a_pos){
00348     uint32 cnt = (uint32)(m_pos-m_buffer) - a_pos - sizeof(unsigned int);
00349     if(cnt>=kMaxMapCount()) {
00350       m_out << "inlib::wroot::buffer::set_byte_count_obj :"
00351             << " bytecount too large (more than "
00352             << kMaxMapCount() << ")."
00353             << std::endl;
00354       return false;
00355     }
00356     char* opos = m_pos;
00357     m_pos = (char*)(m_buffer+a_pos);
00358     if(!m_wb.write(uint32(cnt|kByteCountMask()))) {m_pos = opos;return false;}
00359     m_pos = opos;
00360     return true;
00361   }
00362 
00363   static std::string sout(const std::string& a_string) {
00364     return std::string("\"")+a_string+"\"";
00365   }
00366 protected:
00367   std::ostream& m_out;
00368   bool m_byte_swap;
00369   uint32 m_size;
00370   char* m_buffer;
00371   char* m_max;
00372   char* m_pos;
00373   wbuf m_wb;
00374 
00375   std::map<ibo*,uint32> m_objs;
00376   std::vector< std::pair<uint32,uint32> > m_obj_mapped;
00377 
00378   std::map<std::string,uint32> m_clss;
00379   std::vector< std::pair<uint32,uint32> > m_cls_mapped;
00380 };
00381 
00382 }}
00383 
00384 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines