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