Warning, /include/Geant4/tools/wroot/buffer is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef tools_wroot_buffer
0005 #define tools_wroot_buffer
0006
0007 // class used for serializing objects.
0008
0009 #include "wbuf"
0010 #include "ibo"
0011
0012 #include "../realloc"
0013 #include "../mnmx"
0014 #include "../forit"
0015
0016 #ifdef TOOLS_MEM
0017 #include "../mem"
0018 #endif
0019
0020 #include <string>
0021 #include <vector>
0022 #include <ostream>
0023 #include <map>
0024
0025 namespace tools {
0026 namespace wroot {
0027
0028 class buffer {
0029 static const std::string& s_class() {
0030 static const std::string s_v("tools::wroot::buffer");
0031 return s_v;
0032 }
0033 public:
0034 buffer(std::ostream& a_out,bool a_byte_swap,uint32 a_size) // we expect a not zero value for a_size.
0035 :m_out(a_out)
0036 ,m_byte_swap(a_byte_swap)
0037 ,m_size(0)
0038 ,m_buffer(0)
0039 ,m_max(0)
0040 ,m_pos(0)
0041 ,m_wb(a_out,a_byte_swap,0,m_pos) //it holds a ref on m_pos.
0042 {
0043 #ifdef TOOLS_MEM
0044 mem::increment(s_class().c_str());
0045 #endif
0046 m_size = a_size;
0047 m_buffer = new char[m_size];
0048 //if(!m_buffer) {}
0049 m_max = m_buffer+m_size;
0050 m_pos = m_buffer;
0051 m_wb.set_eob(m_max);
0052 }
0053
0054 virtual ~buffer(){
0055 m_objs.clear();
0056 m_obj_mapped.clear();
0057
0058 m_clss.clear();
0059 m_cls_mapped.clear();
0060
0061 delete [] m_buffer;
0062 #ifdef TOOLS_MEM
0063 mem::decrement(s_class().c_str());
0064 #endif
0065 }
0066 protected:
0067 buffer(const buffer& a_from)
0068 :m_out(a_from.m_out)
0069 ,m_byte_swap(a_from.m_byte_swap)
0070 ,m_size(0)
0071 ,m_buffer(0)
0072 ,m_max(0)
0073 ,m_pos(0)
0074 ,m_wb(a_from.m_out,a_from.m_byte_swap,0,m_pos)
0075 {
0076 #ifdef TOOLS_MEM
0077 mem::increment(s_class().c_str());
0078 #endif
0079 }
0080 buffer& operator=(const buffer&){return *this;}
0081 public:
0082 bool byte_swap() const {return m_byte_swap;}
0083 std::ostream& out() const {return m_out;}
0084
0085 //void set_offset(unsigned int a_off) {m_pos = m_buffer+a_off;}
0086
0087 char* buf() {return m_buffer;}
0088 const char* buf() const {return m_buffer;}
0089 uint32 length() const {return uint32(m_pos-m_buffer);}
0090 uint32 size() const {return m_size;}
0091
0092 char*& pos() {return m_pos;} //used in basket.
0093 char* max_pos() const {return m_max;} //used in basket.
0094
0095 public:
0096 template <class T>
0097 bool write(T x){
0098 if(m_pos+sizeof(T)>m_max) {
0099 if(!expand2(m_size+sizeof(T))) return false;
0100 }
0101 return m_wb.write(x);
0102 }
0103
0104 bool write(bool x) {return write<unsigned char>(x?1:0);}
0105
0106 bool write(const std::string& x) {
0107 uint32 sz = (uint32)(x.size() + sizeof(int) + 1);
0108 if((m_pos+sz)>m_max) {
0109 if(!expand2(m_size+sz)) return false;
0110 }
0111 return m_wb.write(x);
0112 }
0113
0114 bool write_fast_array(const char* a_a,uint32 a_n) {
0115 if(!a_n) return true;
0116 uint32 l = a_n * sizeof(char);
0117 if((m_pos+l)>m_max) {
0118 if(!expand2(m_size+l)) return false;
0119 }
0120 ::memcpy(m_pos,a_a,l);
0121 m_pos += l;
0122 return true;
0123 }
0124
0125 bool write_cstring(const char* a_s) {return write_fast_array(a_s,(uint32(::strlen(a_s))+1)*sizeof(char));}
0126
0127 template <class T>
0128 bool write_fast_array(const T* a_a,uint32 a_n) {
0129 if(!a_n) return true;
0130 uint32 l = a_n * sizeof(T);
0131 if((m_pos+l)>m_max) {
0132 if(!expand2(m_size+l)) return false;
0133 }
0134 return m_wb.write<T>(a_a,a_n);
0135 }
0136
0137 template <class T>
0138 bool write_fast_array(const std::vector<T>& a_v) {
0139 if(a_v.empty()) return true;
0140 uint32 l = uint32(a_v.size() * sizeof(T));
0141 if((m_pos+l)>m_max) {
0142 if(!expand2(m_size+l)) return false;
0143 }
0144 return m_wb.write<T>(a_v);
0145 }
0146
0147 template <class T>
0148 bool write_array(const T* a_a,uint32 a_n) {
0149 if(!write(a_n)) return false;
0150 return write_fast_array(a_a,a_n);
0151 }
0152
0153 template <class T>
0154 bool write_array(const std::vector<T> a_v) {
0155 if(!write((uint32)a_v.size())) return false;
0156 return write_fast_array(a_v);
0157 }
0158
0159 template <class T>
0160 bool write_array2(const std::vector< std::vector<T> > a_v) {
0161 if(!write((uint32)a_v.size())) return false;
0162 for(unsigned int index=0;index<a_v.size();index++) {
0163 if(!write_array(a_v[index])) return false;
0164 }
0165 return true;
0166 }
0167
0168 public:
0169 bool write_version(short a_version){
0170 if(a_version>kMaxVersion()) {
0171 m_out << "tools::wroot::buffer::write_version :"
0172 << " version number " << a_version
0173 << " cannot be larger than " << kMaxVersion() << "."
0174 << std::endl;
0175 return false;
0176 }
0177 return write(a_version);
0178 }
0179 bool write_version(short a_version,uint32& a_pos){
0180 // reserve space for leading byte count
0181 a_pos = (uint32)(m_pos-m_buffer);
0182
0183 //NOTE : the below test is lacking in CERN-ROOT !
0184 if((m_pos+sizeof(unsigned int))>m_max) {
0185 if(!expand2(m_size+sizeof(unsigned int))) return false;
0186 }
0187 m_pos += sizeof(unsigned int);
0188
0189 if(a_version>kMaxVersion()) {
0190 m_out << "tools::wroot::buffer::write_version :"
0191 << " version number " << a_version
0192 << " cannot be larger than " << kMaxVersion() << "."
0193 << std::endl;
0194 return false;
0195 }
0196 return write(a_version);
0197 }
0198
0199 bool set_byte_count(uint32 a_pos){
0200 uint32 cnt = (uint32)(m_pos-m_buffer) - a_pos - sizeof(unsigned int);
0201 if(cnt>=kMaxMapCount()) {
0202 m_out << "tools::wroot::buffer::set_byte_count :"
0203 << " bytecount too large (more than "
0204 << kMaxMapCount() << ")."
0205 << std::endl;
0206 return false;
0207 }
0208
0209 union {
0210 uint32 cnt;
0211 short vers[2];
0212 } v;
0213 v.cnt = cnt;
0214
0215 char* opos = m_pos;
0216 m_pos = (char*)(m_buffer+a_pos);
0217 if(m_byte_swap) {
0218 if(!m_wb.write(short(v.vers[1]|kByteCountVMask())))
0219 {m_pos = opos;return false;}
0220 if(!m_wb.write(v.vers[0])) {m_pos = opos;return false;}
0221 } else {
0222 if(!m_wb.write(short(v.vers[0]|kByteCountVMask())))
0223 {m_pos = opos;return false;}
0224 if(!m_wb.write(v.vers[1])) {m_pos = opos;return false;}
0225 }
0226 m_pos = opos;
0227
0228 return true;
0229 }
0230
0231 bool write_object(const ibo& a_obj){
0232 //GB : if adding a write map logic, think to have a displace_mapped()
0233 // in basket::write_on_file().
0234
0235 std::map<ibo*,uint32>::const_iterator it = m_objs.find((ibo*)&a_obj);
0236 if(it!=m_objs.end()) {
0237
0238 uint32 objIdx = (*it).second;
0239
0240 unsigned int offset = (unsigned int)(m_pos-m_buffer);
0241
0242 // save index of already stored object
0243 if(!write(objIdx)) return false;
0244
0245 m_obj_mapped.push_back(std::pair<uint32,uint32>(offset,objIdx));
0246
0247 } else {
0248
0249 // reserve space for leading byte count
0250 uint32 cntpos = (unsigned int)(m_pos-m_buffer);
0251
0252 //NOTE : the below test is lacking in CERN-ROOT !
0253 if((m_pos+sizeof(unsigned int))>m_max) {
0254 if(!expand2(m_size+sizeof(unsigned int))) return false;
0255 }
0256 m_pos += sizeof(unsigned int);
0257
0258 // write class of object first
0259 if(!write_class(a_obj.store_cls())) return false;
0260
0261 // add to map before writing rest of object (to handle self reference)
0262 // (+kMapOffset so it's != kNullTag)
0263 m_objs[(ibo*)&a_obj] = cntpos + kMapOffset();
0264
0265 // let the object write itself :
0266 if(!a_obj.stream(*this)) return false;
0267
0268 // write byte count
0269 if(!set_byte_count_obj(cntpos)) return false;
0270 }
0271 return true;
0272 }
0273
0274 bool expand2(uint32 a_new_size) {return expand(mx<uint32>(2*m_size,a_new_size));} //CERN-ROOT logic.
0275
0276 bool expand(uint32 a_new_size) {
0277 diff_pointer_t len = m_pos-m_buffer;
0278 if(!realloc<char>(m_buffer,a_new_size,m_size)) {
0279 m_out << "tools::wroot::buffer::expand :"
0280 << " can't realloc " << a_new_size << " bytes."
0281 << std::endl;
0282 m_size = 0;
0283 m_max = 0;
0284 m_pos = 0;
0285 m_wb.set_eob(m_max);
0286 return false;
0287 }
0288 m_size = a_new_size;
0289 m_max = m_buffer + m_size;
0290 m_pos = m_buffer + len;
0291 m_wb.set_eob(m_max);
0292 return true;
0293 }
0294
0295 size_t to_displace() const {return m_cls_mapped.size()+m_obj_mapped.size();}
0296
0297 bool displace_mapped(unsigned int a_num){
0298 char* opos = m_pos;
0299
0300 //m_out << "tools::wroot::buffer::displace_mapped :"
0301 // << " cls num " << m_cls_mapped.size()
0302 // << std::endl;
0303
0304 typedef std::pair<uint32,uint32> offset_id;
0305
0306 {tools_vforcit(offset_id,m_cls_mapped,it) {
0307 unsigned int offset = (*it).first;
0308 unsigned int id = (*it).second;
0309 //m_out << "displace " << offset << " " << id << std::endl;
0310 m_pos = m_buffer+offset;
0311 unsigned int clIdx = id+a_num;
0312 if(!write(uint32(clIdx|kClassMask()))) {m_pos = opos;return false;}
0313 }}
0314
0315 //m_out << "tools::wroot::buffer::displace_mapped :"
0316 // << " obj num " << m_obj_mapped.size()
0317 // << std::endl;
0318
0319 {tools_vforcit(offset_id,m_obj_mapped,it) {
0320 uint32 offset = (*it).first;
0321 uint32 id = (*it).second;
0322 //m_out << "displace at " << offset
0323 // << " the obj pos " << id
0324 // << " by " << a_num
0325 // << std::endl;
0326 m_pos = m_buffer+offset;
0327 unsigned int objIdx = id+a_num;
0328 if(!write(objIdx)) {m_pos = opos;return false;}
0329 }}
0330
0331 m_pos = opos;
0332 return true;
0333 }
0334
0335 void reset_objs_map() {
0336 m_objs.clear();
0337 //m_clss.clear();
0338 }
0339 protected:
0340 static short kMaxVersion() {return 0x3FFF;}
0341 static uint32 kMaxMapCount() {return 0x3FFFFFFE;}
0342 static short kByteCountVMask() {return 0x4000;}
0343 static uint32 kNewClassTag() {return 0xFFFFFFFF;}
0344
0345 static int kMapOffset() {return 2;}
0346 static unsigned int kClassMask() {return 0x80000000;}
0347 static uint32 kByteCountMask() {return 0x40000000;}
0348
0349 bool write_class(const std::string& a_cls){
0350
0351 std::map<std::string,uint32>::const_iterator it = m_clss.find(a_cls);
0352 if(it!=m_clss.end()) {
0353 uint32 clIdx = (*it).second;
0354
0355 unsigned int offset = (unsigned int)(m_pos-m_buffer);
0356
0357 // save index of already stored class
0358 if(!write(uint32(clIdx|kClassMask()))) return false;
0359
0360 m_cls_mapped.push_back(std::pair<uint32,uint32>(offset,clIdx));
0361
0362 } else {
0363
0364 unsigned int offset = (unsigned int)(m_pos-m_buffer);
0365 if(!write(kNewClassTag())) return false;
0366 if(!write_cstring(a_cls.c_str())) return false;
0367 m_clss[a_cls] = offset + kMapOffset();
0368
0369 }
0370 return true;
0371 }
0372
0373 bool set_byte_count_obj(uint32 a_pos){
0374 uint32 cnt = (uint32)(m_pos-m_buffer) - a_pos - sizeof(unsigned int);
0375 if(cnt>=kMaxMapCount()) {
0376 m_out << "tools::wroot::buffer::set_byte_count_obj :"
0377 << " bytecount too large (more than "
0378 << kMaxMapCount() << ")."
0379 << std::endl;
0380 return false;
0381 }
0382 char* opos = m_pos;
0383 m_pos = (char*)(m_buffer+a_pos);
0384 if(!m_wb.write(uint32(cnt|kByteCountMask()))) {m_pos = opos;return false;}
0385 m_pos = opos;
0386 return true;
0387 }
0388
0389 protected:
0390 std::ostream& m_out;
0391 bool m_byte_swap;
0392 uint32 m_size;
0393 char* m_buffer;
0394 char* m_max;
0395 char* m_pos;
0396 wbuf m_wb;
0397
0398 std::map<ibo*,uint32> m_objs;
0399 std::vector< std::pair<uint32,uint32> > m_obj_mapped;
0400
0401 std::map<std::string,uint32> m_clss;
0402 std::vector< std::pair<uint32,uint32> > m_cls_mapped;
0403 };
0404
0405 }}
0406
0407 #endif