inlib
1.2.0
|
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