Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef tools_wroot_buffer 5 #define tools_wroot_buffer 6 7 // class used for serializing objects. 8 9 #include "wbuf" 10 #include "ibo" 11 12 #include "../realloc" 13 #include "../mnmx" 14 #include "../forit" 15 16 #ifdef TOOLS_MEM 17 #include "../mem" 18 #endif 19 20 #include <string> 21 #include <vector> 22 #include <ostream> 23 #include <map> 24 25 namespace tools { 26 namespace wroot { 27 28 class buffer { 29 static const std::string& s_class() { 30 static const std::string s_v("tools::wroot::buffer"); 31 return s_v; 32 } 33 public: 34 buffer(std::ostream& a_out,bool a_byte_swap,uint32 a_size) // we expect a not zero value for a_size. 35 :m_out(a_out) 36 ,m_byte_swap(a_byte_swap) 37 ,m_size(0) 38 ,m_buffer(0) 39 ,m_max(0) 40 ,m_pos(0) 41 ,m_wb(a_out,a_byte_swap,0,m_pos) //it holds a ref on m_pos. 42 { 43 #ifdef TOOLS_MEM 44 mem::increment(s_class().c_str()); 45 #endif 46 m_size = a_size; 47 m_buffer = new char[m_size]; 48 //if(!m_buffer) {} 49 m_max = m_buffer+m_size; 50 m_pos = m_buffer; 51 m_wb.set_eob(m_max); 52 } 53 54 virtual ~buffer(){ 55 m_objs.clear(); 56 m_obj_mapped.clear(); 57 58 m_clss.clear(); 59 m_cls_mapped.clear(); 60 61 delete [] m_buffer; 62 #ifdef TOOLS_MEM 63 mem::decrement(s_class().c_str()); 64 #endif 65 } 66 protected: 67 buffer(const buffer& a_from) 68 :m_out(a_from.m_out) 69 ,m_byte_swap(a_from.m_byte_swap) 70 ,m_size(0) 71 ,m_buffer(0) 72 ,m_max(0) 73 ,m_pos(0) 74 ,m_wb(a_from.m_out,a_from.m_byte_swap,0,m_pos) 75 { 76 #ifdef TOOLS_MEM 77 mem::increment(s_class().c_str()); 78 #endif 79 } 80 buffer& operator=(const buffer&){return *this;} 81 public: 82 bool byte_swap() const {return m_byte_swap;} 83 std::ostream& out() const {return m_out;} 84 85 //void set_offset(unsigned int a_off) {m_pos = m_buffer+a_off;} 86 87 char* buf() {return m_buffer;} 88 const char* buf() const {return m_buffer;} 89 uint32 length() const {return uint32(m_pos-m_buffer);} 90 uint32 size() const {return m_size;} 91 92 char*& pos() {return m_pos;} //used in basket. 93 char* max_pos() const {return m_max;} //used in basket. 94 95 public: 96 template <class T> 97 bool write(T x){ 98 if(m_pos+sizeof(T)>m_max) { 99 if(!expand2(m_size+sizeof(T))) return false; 100 } 101 return m_wb.write(x); 102 } 103 104 bool write(bool x) {return write<unsigned char>(x?1:0);} 105 106 bool write(const std::string& x) { 107 uint32 sz = (uint32)(x.size() + sizeof(int) + 1); 108 if((m_pos+sz)>m_max) { 109 if(!expand2(m_size+sz)) return false; 110 } 111 return m_wb.write(x); 112 } 113 114 bool write_fast_array(const char* a_a,uint32 a_n) { 115 if(!a_n) return true; 116 uint32 l = a_n * sizeof(char); 117 if((m_pos+l)>m_max) { 118 if(!expand2(m_size+l)) return false; 119 } 120 ::memcpy(m_pos,a_a,l); 121 m_pos += l; 122 return true; 123 } 124 125 bool write_cstring(const char* a_s) {return write_fast_array(a_s,(uint32(::strlen(a_s))+1)*sizeof(char));} 126 127 template <class T> 128 bool write_fast_array(const T* a_a,uint32 a_n) { 129 if(!a_n) return true; 130 uint32 l = a_n * sizeof(T); 131 if((m_pos+l)>m_max) { 132 if(!expand2(m_size+l)) return false; 133 } 134 return m_wb.write<T>(a_a,a_n); 135 } 136 137 template <class T> 138 bool write_fast_array(const std::vector<T>& a_v) { 139 if(a_v.empty()) return true; 140 uint32 l = uint32(a_v.size() * sizeof(T)); 141 if((m_pos+l)>m_max) { 142 if(!expand2(m_size+l)) return false; 143 } 144 return m_wb.write<T>(a_v); 145 } 146 147 template <class T> 148 bool write_array(const T* a_a,uint32 a_n) { 149 if(!write(a_n)) return false; 150 return write_fast_array(a_a,a_n); 151 } 152 153 template <class T> 154 bool write_array(const std::vector<T>& a_v) { 155 if(!write((uint32)a_v.size())) return false; 156 return write_fast_array(a_v); 157 } 158 159 template <class T> 160 bool write_array2(const std::vector< std::vector<T> >& a_v) { 161 if(!write((uint32)a_v.size())) return false; 162 for(unsigned int index=0;index<a_v.size();index++) { 163 if(!write_array(a_v[index])) return false; 164 } 165 return true; 166 } 167 168 public: 169 bool write_version(short a_version){ 170 if(a_version>kMaxVersion()) { 171 m_out << "tools::wroot::buffer::write_version :" 172 << " version number " << a_version 173 << " cannot be larger than " << kMaxVersion() << "." 174 << std::endl; 175 return false; 176 } 177 return write(a_version); 178 } 179 bool write_version(short a_version,uint32& a_pos){ 180 // reserve space for leading byte count 181 a_pos = (uint32)(m_pos-m_buffer); 182 183 //NOTE : the below test is lacking in CERN-ROOT ! 184 if((m_pos+sizeof(unsigned int))>m_max) { 185 if(!expand2(m_size+sizeof(unsigned int))) return false; 186 } 187 m_pos += sizeof(unsigned int); 188 189 if(a_version>kMaxVersion()) { 190 m_out << "tools::wroot::buffer::write_version :" 191 << " version number " << a_version 192 << " cannot be larger than " << kMaxVersion() << "." 193 << std::endl; 194 return false; 195 } 196 return write(a_version); 197 } 198 199 bool set_byte_count(uint32 a_pos){ 200 uint32 cnt = (uint32)(m_pos-m_buffer) - a_pos - sizeof(unsigned int); 201 if(cnt>=kMaxMapCount()) { 202 m_out << "tools::wroot::buffer::set_byte_count :" 203 << " bytecount too large (more than " 204 << kMaxMapCount() << ")." 205 << std::endl; 206 return false; 207 } 208 209 union { 210 uint32 cnt; 211 short vers[2]; 212 } v; 213 v.cnt = cnt; 214 215 char* opos = m_pos; 216 m_pos = (char*)(m_buffer+a_pos); 217 if(m_byte_swap) { 218 if(!m_wb.write(short(v.vers[1]|kByteCountVMask()))) 219 {m_pos = opos;return false;} 220 if(!m_wb.write(v.vers[0])) {m_pos = opos;return false;} 221 } else { 222 if(!m_wb.write(short(v.vers[0]|kByteCountVMask()))) 223 {m_pos = opos;return false;} 224 if(!m_wb.write(v.vers[1])) {m_pos = opos;return false;} 225 } 226 m_pos = opos; 227 228 return true; 229 } 230 231 bool write_object(const ibo& a_obj){ 232 //GB : if adding a write map logic, think to have a displace_mapped() 233 // in basket::write_on_file(). 234 235 std::map<ibo*,uint32>::const_iterator it = m_objs.find((ibo*)&a_obj); 236 if(it!=m_objs.end()) { 237 238 uint32 objIdx = (*it).second; 239 240 unsigned int offset = (unsigned int)(m_pos-m_buffer); 241 242 // save index of already stored object 243 if(!write(objIdx)) return false; 244 245 m_obj_mapped.push_back(std::pair<uint32,uint32>(offset,objIdx)); 246 247 } else { 248 249 // reserve space for leading byte count 250 uint32 cntpos = (unsigned int)(m_pos-m_buffer); 251 252 //NOTE : the below test is lacking in CERN-ROOT ! 253 if((m_pos+sizeof(unsigned int))>m_max) { 254 if(!expand2(m_size+sizeof(unsigned int))) return false; 255 } 256 m_pos += sizeof(unsigned int); 257 258 // write class of object first 259 if(!write_class(a_obj.store_cls())) return false; 260 261 // add to map before writing rest of object (to handle self reference) 262 // (+kMapOffset so it's != kNullTag) 263 m_objs[(ibo*)&a_obj] = cntpos + kMapOffset(); 264 265 // let the object write itself : 266 if(!a_obj.stream(*this)) return false; 267 268 // write byte count 269 if(!set_byte_count_obj(cntpos)) return false; 270 } 271 return true; 272 } 273 274 bool expand2(uint32 a_new_size) {return expand(mx<uint32>(2*m_size,a_new_size));} //CERN-ROOT logic. 275 276 bool expand(uint32 a_new_size) { 277 diff_pointer_t len = m_pos-m_buffer; 278 if(!realloc<char>(m_buffer,a_new_size,m_size)) { 279 m_out << "tools::wroot::buffer::expand :" 280 << " can't realloc " << a_new_size << " bytes." 281 << std::endl; 282 m_size = 0; 283 m_max = 0; 284 m_pos = 0; 285 m_wb.set_eob(m_max); 286 return false; 287 } 288 m_size = a_new_size; 289 m_max = m_buffer + m_size; 290 m_pos = m_buffer + len; 291 m_wb.set_eob(m_max); 292 return true; 293 } 294 295 size_t to_displace() const {return m_cls_mapped.size()+m_obj_mapped.size();} 296 297 bool displace_mapped(unsigned int a_num){ 298 char* opos = m_pos; 299 300 //m_out << "tools::wroot::buffer::displace_mapped :" 301 // << " cls num " << m_cls_mapped.size() 302 // << std::endl; 303 304 typedef std::pair<uint32,uint32> offset_id; 305 306 {tools_vforcit(offset_id,m_cls_mapped,it) { 307 unsigned int offset = (*it).first; 308 unsigned int id = (*it).second; 309 //m_out << "displace " << offset << " " << id << std::endl; 310 m_pos = m_buffer+offset; 311 unsigned int clIdx = id+a_num; 312 if(!write(uint32(clIdx|kClassMask()))) {m_pos = opos;return false;} 313 }} 314 315 //m_out << "tools::wroot::buffer::displace_mapped :" 316 // << " obj num " << m_obj_mapped.size() 317 // << std::endl; 318 319 {tools_vforcit(offset_id,m_obj_mapped,it) { 320 uint32 offset = (*it).first; 321 uint32 id = (*it).second; 322 //m_out << "displace at " << offset 323 // << " the obj pos " << id 324 // << " by " << a_num 325 // << std::endl; 326 m_pos = m_buffer+offset; 327 unsigned int objIdx = id+a_num; 328 if(!write(objIdx)) {m_pos = opos;return false;} 329 }} 330 331 m_pos = opos; 332 return true; 333 } 334 335 void reset_objs_map() { 336 m_objs.clear(); 337 //m_clss.clear(); 338 } 339 protected: 340 static short kMaxVersion() {return 0x3FFF;} 341 static uint32 kMaxMapCount() {return 0x3FFFFFFE;} 342 static short kByteCountVMask() {return 0x4000;} 343 static uint32 kNewClassTag() {return 0xFFFFFFFF;} 344 345 static int kMapOffset() {return 2;} 346 static unsigned int kClassMask() {return 0x80000000;} 347 static uint32 kByteCountMask() {return 0x40000000;} 348 349 bool write_class(const std::string& a_cls){ 350 351 std::map<std::string,uint32>::const_iterator it = m_clss.find(a_cls); 352 if(it!=m_clss.end()) { 353 uint32 clIdx = (*it).second; 354 355 unsigned int offset = (unsigned int)(m_pos-m_buffer); 356 357 // save index of already stored class 358 if(!write(uint32(clIdx|kClassMask()))) return false; 359 360 m_cls_mapped.push_back(std::pair<uint32,uint32>(offset,clIdx)); 361 362 } else { 363 364 unsigned int offset = (unsigned int)(m_pos-m_buffer); 365 if(!write(kNewClassTag())) return false; 366 if(!write_cstring(a_cls.c_str())) return false; 367 m_clss[a_cls] = offset + kMapOffset(); 368 369 } 370 return true; 371 } 372 373 bool set_byte_count_obj(uint32 a_pos){ 374 uint32 cnt = (uint32)(m_pos-m_buffer) - a_pos - sizeof(unsigned int); 375 if(cnt>=kMaxMapCount()) { 376 m_out << "tools::wroot::buffer::set_byte_count_obj :" 377 << " bytecount too large (more than " 378 << kMaxMapCount() << ")." 379 << std::endl; 380 return false; 381 } 382 char* opos = m_pos; 383 m_pos = (char*)(m_buffer+a_pos); 384 if(!m_wb.write(uint32(cnt|kByteCountMask()))) {m_pos = opos;return false;} 385 m_pos = opos; 386 return true; 387 } 388 389 protected: 390 std::ostream& m_out; 391 bool m_byte_swap; 392 uint32 m_size; 393 char* m_buffer; 394 char* m_max; 395 char* m_pos; 396 wbuf m_wb; 397 398 std::map<ibo*,uint32> m_objs; 399 std::vector< std::pair<uint32,uint32> > m_obj_mapped; 400 401 std::map<std::string,uint32> m_clss; 402 std::vector< std::pair<uint32,uint32> > m_cls_mapped; 403 }; 404 405 }} 406 407 #endif