Warning, /include/Geant4/toolx/hdf5/ntuple 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 toolx_hdf5_ntuple
0005 #define toolx_hdf5_ntuple
0006
0007 #include "store"
0008
0009 #include <tools/vfind>
0010 #include <tools/vmanip>
0011 #include <tools/ntuple_binding>
0012 #include <tools/ntuple_booking>
0013 #include <tools/sout>
0014 #include <tools/scast>
0015 #include <tools/forit>
0016 #include <tools/stype>
0017 #include <tools/mnmx>
0018 #include <tools/vdata>
0019
0020 #ifdef TOOLS_MEM
0021 #include <tools/mem>
0022 #include <tools/stype>
0023 #endif
0024
0025 namespace toolx {
0026 namespace hdf5 {
0027
0028 class ntuple : public store {
0029 public:
0030 class icol {
0031 public:
0032 virtual ~icol(){}
0033 public:
0034 virtual void* cast(tools::cid) const = 0;
0035 virtual tools::cid id_cls() const = 0;
0036 public:
0037 virtual bool set_basket_size(size_t a_size) = 0;
0038 virtual bool add() = 0;
0039 virtual bool fetch_entry() = 0;
0040 virtual const std::string& name() const = 0;
0041 virtual void reset() = 0;
0042 };
0043 public:
0044
0045
0046 template <class T>
0047 class column_ref : public virtual icol {
0048 #ifdef TOOLS_MEM
0049 static const std::string& s_class() {
0050 static const std::string s_v("toolx::hdf5::ntuple::column_ref<"+tools::stype(T())+">");
0051 return s_v;
0052 }
0053 #endif
0054 public:
0055 static tools::cid id_class() {
0056 static const T s_v = T(); //do that for T = std::string.
0057 return tools::_cid(s_v)+10000;
0058 }
0059 virtual void* cast(tools::cid a_class) const {
0060 if(void* p = tools::cmp_cast<column_ref>(this,a_class)) {return p;}
0061 else return 0;
0062 }
0063 virtual tools::cid id_cls() const {return id_class();}
0064 public: //icol
0065 virtual bool add() { //write.
0066 if(!m_write) return false;
0067 if(m_basket_pos>=m_basket_size) {
0068 if(!m_branch.write_page<T>(m_basket_size,m_basket)) {
0069 m_store.out() << "toolx::hdf5::ntuple::column_ref::add : write_page() failed." << std::endl;
0070 m_basket_pos = 0;
0071 return false;
0072 }
0073 m_basket_pos = 0;
0074 if(m_want_new_basket_size) {
0075 delete [] m_basket;
0076 m_basket = new T[m_want_new_basket_size];
0077 m_basket_pos = 0;
0078 m_basket_size = m_want_new_basket_size;
0079 m_want_new_basket_size = 0;
0080 }
0081 }
0082 m_basket[m_basket_pos] = m_ref;
0083 m_basket_pos++;
0084 return true;
0085 }
0086 virtual bool fetch_entry() { //read.
0087 if(m_write) return false;
0088 if(m_basket_pos>=m_basket_end) { //we need more data.
0089 if(m_branch.pos()>=m_branch.entries()) {
0090 m_store.out() << "toolx::hdf5::ntuple::column_ref:fetch_entry : no more data." << std::endl;
0091 m_basket_pos = 0;
0092 m_basket_end = 0;
0093 return false;
0094 }
0095 if(m_want_new_basket_size) {
0096 delete [] m_basket;
0097 m_basket = new T[m_want_new_basket_size];
0098 m_basket_pos = 0;
0099 m_basket_size = m_want_new_basket_size;
0100 m_want_new_basket_size = 0;
0101 }
0102 tools::uint64 remain = m_branch.entries()-m_branch.pos();
0103 size_t n = tools::mn<size_t>((size_t)remain,m_basket_size);
0104 if(!m_branch.read_page<T>(n,m_basket)) {
0105 m_store.out() << "toolx::hdf5::ntuple::column_ref:fetch_entry : read_page() failed." << std::endl;
0106 m_basket_pos = 0;
0107 m_basket_end = 0;
0108 return false;
0109 }
0110 m_basket_pos = 0;
0111 m_basket_end = n;
0112 }
0113 m_ref = m_basket[m_basket_pos];
0114 m_basket_pos++;
0115 return true;
0116 }
0117 virtual void reset() {m_branch.reset_pos();}
0118 virtual const std::string& name() const {return m_name;}
0119 virtual bool set_basket_size(size_t a_size) {
0120 if(!a_size) return false;
0121 m_want_new_basket_size = a_size;
0122 return true;
0123 }
0124 public:
0125 column_ref(store& a_store,pages& a_pages,bool a_write,const std::string& a_name,size_t a_basket_size,T& a_ref)
0126 :m_store(a_store)
0127 ,m_branch(a_pages)
0128 ,m_write(a_write)
0129 ,m_name(a_name)
0130 ,m_ref(a_ref)
0131 ,m_basket_size(a_basket_size?a_basket_size:32000)
0132 ,m_basket_pos(0)
0133 ,m_basket_end(0) //read.
0134 ,m_basket(0)
0135 ,m_want_new_basket_size(0)
0136 {
0137 #ifdef TOOLS_MEM
0138 tools::mem::increment(s_class().c_str());
0139 #endif
0140 m_basket = new T[m_basket_size];
0141 if(m_write) {
0142 } else { //read.
0143 tools::uint64 _entries = m_branch.entries();
0144 size_t n = tools::mn<size_t>((size_t)_entries,m_basket_size);
0145 if(_entries) {
0146 if(!m_branch.read_page<T>(n,m_basket)) {
0147 m_store.out() << "toolx::hdf5::ntuple::column_ref:column_ref : read_page() failed." << std::endl;
0148 m_basket_pos = 0;
0149 m_basket_end = 0;
0150 return;
0151 }
0152 }
0153 m_basket_pos = 0;
0154 m_basket_end = n;
0155 }
0156 }
0157 virtual ~column_ref(){
0158 if(m_write && m_basket_pos) {
0159 if(!m_branch.write_page<T>(m_basket_pos,m_basket)) {
0160 m_store.out() << "toolx::hdf5::ntuple::column_ref::~column_ref : write_page() failed." << std::endl;
0161 }
0162 }
0163 delete [] m_basket;
0164 #ifdef TOOLS_MEM
0165 tools::mem::decrement(s_class().c_str());
0166 #endif
0167 }
0168 protected:
0169 column_ref(const column_ref& a_from)
0170 :icol(a_from)
0171 ,m_store(a_from.m_store)
0172 ,m_branch(a_from.m_branch)
0173 ,m_write(a_from.m_write)
0174 ,m_name(a_from.m_name)
0175 ,m_ref(a_from.m_ref)
0176 ,m_basket_size(a_from.m_basket_size)
0177 ,m_basket_pos(0)
0178 ,m_basket_end(0)
0179 ,m_basket(0)
0180 ,m_want_new_basket_size(0)
0181 {}
0182 column_ref& operator=(const column_ref& a_from){
0183 if(&a_from==this) return *this;
0184 m_name = a_from.m_name;
0185 m_basket_size = a_from.m_basket_size;
0186 m_basket_pos = 0;
0187 m_basket_end = 0;
0188 m_want_new_basket_size = 0;
0189 return *this;
0190 }
0191 protected:
0192 store& m_store;
0193 pages& m_branch;
0194 bool m_write;
0195 std::string m_name;
0196 T& m_ref;
0197 size_t m_basket_size;
0198 size_t m_basket_pos;
0199 size_t m_basket_end;
0200 T* m_basket;
0201 size_t m_want_new_basket_size;
0202 };
0203
0204 template <class T>
0205 class column : public column_ref<T> {
0206 typedef column_ref<T> parent;
0207 #ifdef TOOLS_MEM
0208 static const std::string& s_class() {
0209 static const std::string s_v("toolx::hdf5::ntuple::column<"+tools::stype(T())+">");
0210 return s_v;
0211 }
0212 #endif
0213 public:
0214 static tools::cid id_class() {
0215 static const T s_v = T(); //do that for T = std::string.
0216 return tools::_cid(s_v);
0217 }
0218 virtual void* cast(tools::cid a_class) const {
0219 if(void* p = tools::cmp_cast<column>(this,a_class)) {return p;}
0220 else return 0;
0221 }
0222 virtual tools::cid id_cls() const {return id_class();}
0223 public:
0224 column(store& a_store,pages& a_pages,bool a_write,const std::string& a_name,size_t a_basket_size)
0225 :parent(a_store,a_pages,a_write,a_name,a_basket_size,m_tmp)
0226 ,m_tmp(T())
0227 {
0228 #ifdef TOOLS_MEM
0229 tools::mem::increment(s_class().c_str());
0230 #endif
0231 }
0232 virtual ~column(){
0233 #ifdef TOOLS_MEM
0234 tools::mem::decrement(s_class().c_str());
0235 #endif
0236 }
0237 protected:
0238 column(const column& a_from)
0239 :icol(a_from)
0240 ,parent(a_from)
0241 ,m_tmp(a_from.m_tmp)
0242 {}
0243 column& operator=(const column& a_from){
0244 if(&a_from==this) return *this;
0245 parent::operator=(a_from);
0246 m_tmp = a_from.m_tmp;
0247 return *this;
0248 }
0249 public:
0250 bool fill(const T& a_value) {m_tmp = a_value;return true;} //write.
0251 bool get_entry(T& a_v) const {a_v = m_tmp;return true;} //read.
0252 protected:
0253 T m_tmp;
0254 };
0255
0256 TOOLS_CLASS_STRING_VALUE(vector_char,vector<char>)
0257 TOOLS_CLASS_STRING_VALUE(vector_short,vector<short>)
0258 TOOLS_CLASS_STRING_VALUE(vector_int,vector<int>)
0259 TOOLS_CLASS_STRING_VALUE(vector_float,vector<float>)
0260 TOOLS_CLASS_STRING_VALUE(vector_double,vector<double>)
0261
0262 TOOLS_CLASS_STRING_VALUE(string,string)
0263
0264 TOOLS_CLASS_STRING_VALUE(vector_int64,vector<tools::int64>)
0265 TOOLS_CLASS_STRING_VALUE(vector_uchar,vector<tools::uchar>)
0266 TOOLS_CLASS_STRING_VALUE(vector_ushort,vector<tools::ushort>)
0267 TOOLS_CLASS_STRING_VALUE(vector_uint32,vector<tools::uint32>)
0268 TOOLS_CLASS_STRING_VALUE(vector_uint64,vector<tools::uint64>)
0269
0270 TOOLS_CLASS_STRING_VALUE(vector_string,vector<std::string>)
0271
0272 template <class T>
0273 class std_vector_column_ref : public virtual icol {
0274 #ifdef TOOLS_MEM
0275 static const std::string& s_class() {
0276 static const std::string s_v("toolx::hdf5::ntuple::std_vector_column_ref<"+tools::stype(T())+">");
0277 return s_v;
0278 }
0279 #endif
0280 public:
0281 static tools::cid id_class() {return tools::_cid_std_vector<T>()+10000;}
0282 virtual void* cast(tools::cid a_class) const {
0283 if(void* p = tools::cmp_cast<std_vector_column_ref>(this,a_class)) {return p;}
0284 else return 0;
0285 }
0286 virtual tools::cid id_cls() const {return id_class();}
0287 public: //icol
0288 virtual bool add() { //write.
0289 if(!m_write) return false;
0290 const T* _data = tools::vec_data(m_ref);
0291 return m_branch.write_vlen<T>(m_ref.size(),_data);
0292 }
0293 virtual bool fetch_entry() { //read.
0294 if(m_write) return false;
0295 size_t n;
0296 T* _data;
0297 if(!m_branch.read_vlen<T>(n,_data)) {
0298 m_store.out() << "toolx::hdf5::ntuple::std_vector_column_ref:fetch_entry : read_page() failed." << std::endl;
0299 return false;
0300 }
0301 m_ref.resize(n);
0302 T* dpos = _data;
0303 T* pos = tools::vec_data(m_ref);
0304 for(size_t index=0;index<n;index++,pos++,dpos++) *pos = *dpos;
0305 delete [] _data;
0306 return true;
0307 }
0308 virtual void reset() {m_branch.reset_pos();}
0309 virtual const std::string& name() const {return m_name;}
0310 virtual bool set_basket_size(size_t) {return true;}
0311 public:
0312 std_vector_column_ref(store& a_store,pages& a_pages,bool a_write,const std::string& a_name,
0313 size_t /*a_basket_size*/,
0314 std::vector<T>& a_ref)
0315 :m_store(a_store)
0316 ,m_branch(a_pages)
0317 ,m_write(a_write)
0318 ,m_name(a_name)
0319 ,m_ref(a_ref)
0320 {
0321 #ifdef TOOLS_MEM
0322 tools::mem::increment(s_class().c_str());
0323 #endif
0324 }
0325 virtual ~std_vector_column_ref(){
0326 #ifdef TOOLS_MEM
0327 tools::mem::decrement(s_class().c_str());
0328 #endif
0329 }
0330 protected:
0331 std_vector_column_ref(const std_vector_column_ref& a_from)
0332 :icol(a_from)
0333 ,m_store(a_from.m_store)
0334 ,m_branch(a_from.m_branch)
0335 ,m_write(a_from.m_write)
0336 ,m_name(a_from.m_name)
0337 ,m_ref(a_from.m_ref)
0338 {}
0339 std_vector_column_ref& operator=(const std_vector_column_ref& a_from){
0340 if(&a_from==this) return *this;
0341 m_name = a_from.m_name;
0342 return *this;
0343 }
0344 protected:
0345 store& m_store;
0346 pages& m_branch;
0347 bool m_write;
0348 std::string m_name;
0349 std::vector<T>& m_ref;
0350 };
0351
0352 template <class T>
0353 class std_vector_column : public std_vector_column_ref<T> {
0354 typedef std_vector_column_ref<T> parent;
0355 #ifdef TOOLS_MEM
0356 static const std::string& s_class() {
0357 static const std::string s_v("toolx::hdf5::ntuple::std_vector_column<"+tools::stype(T())+">");
0358 return s_v;
0359 }
0360 #endif
0361 public:
0362 static tools::cid id_class() {return tools::_cid_std_vector<T>();}
0363 virtual void* cast(tools::cid a_class) const {
0364 if(void* p = tools::cmp_cast<std_vector_column>(this,a_class)) {return p;}
0365 else return 0;
0366 }
0367 virtual tools::cid id_cls() const {return id_class();}
0368 public:
0369 std_vector_column(store& a_store,pages& a_pages,bool a_write,const std::string& a_name,size_t a_basket_size)
0370 :parent(a_store,a_pages,a_write,a_name,a_basket_size,m_tmp)
0371 {}
0372 virtual ~std_vector_column(){}
0373 protected:
0374 std_vector_column(const std_vector_column& a_from)
0375 :icol(a_from)
0376 ,parent(a_from)
0377 {}
0378 std_vector_column& operator=(const std_vector_column& a_from){
0379 parent::operator=(a_from);
0380 return *this;
0381 }
0382 public:
0383 const std::vector<T>& data() const {return m_tmp;}
0384 protected:
0385 std::vector<T> m_tmp;
0386 };
0387
0388 class column_string_ref : public virtual icol {
0389 #ifdef TOOLS_MEM
0390 TOOLS_SCLASS(toolx::hdf5::ntuple::column_string_ref)
0391 #endif
0392 public:
0393 static tools::cid id_class() {
0394 static const std::string s_v;
0395 return tools::_cid(s_v)+10000;
0396 }
0397 virtual void* cast(tools::cid a_class) const {
0398 if(void* p = tools::cmp_cast<column_string_ref>(this,a_class)) {return p;}
0399 else return 0;
0400 }
0401 virtual tools::cid id_cls() const {return id_class();}
0402 public: //icol
0403 virtual bool add() { //write.
0404 if(!m_write) return false;
0405 return m_branch.write_string(m_ref);
0406 }
0407 virtual bool fetch_entry() { //read.
0408 if(m_write) return false;
0409 if(!m_branch.read_string(m_ref)) {
0410 m_store.out() << "toolx::hdf5::ntuple::column_string_ref:fetch_entry : read_page() failed." << std::endl;
0411 return false;
0412 }
0413 return true;
0414 }
0415 virtual void reset() {m_branch.reset_pos();}
0416 virtual const std::string& name() const {return m_name;}
0417 virtual bool set_basket_size(size_t) {return true;}
0418 public:
0419 column_string_ref(store& a_store,pages& a_pages,bool a_write,const std::string& a_name,
0420 size_t /*a_basket_size*/,
0421 std::string& a_ref)
0422 :m_store(a_store)
0423 ,m_branch(a_pages)
0424 ,m_write(a_write)
0425 ,m_name(a_name)
0426 ,m_ref(a_ref)
0427 {
0428 #ifdef TOOLS_MEM
0429 tools::mem::increment(s_class().c_str());
0430 #endif
0431 }
0432 virtual ~column_string_ref(){
0433 #ifdef TOOLS_MEM
0434 tools::mem::decrement(s_class().c_str());
0435 #endif
0436 }
0437 protected:
0438 column_string_ref(const column_string_ref& a_from)
0439 :icol(a_from)
0440 ,m_store(a_from.m_store)
0441 ,m_branch(a_from.m_branch)
0442 ,m_write(a_from.m_write)
0443 ,m_name(a_from.m_name)
0444 ,m_ref(a_from.m_ref)
0445 {}
0446 column_string_ref& operator=(const column_string_ref& a_from){
0447 if(&a_from==this) return *this;
0448 m_name = a_from.m_name;
0449 return *this;
0450 }
0451 protected:
0452 store& m_store;
0453 pages& m_branch;
0454 bool m_write;
0455 std::string m_name;
0456 std::string& m_ref;
0457 };
0458
0459 class column_string : public column_string_ref {
0460 typedef column_string_ref parent;
0461 #ifdef TOOLS_MEM
0462 TOOLS_SCLASS(toolx::hdf5::ntuple::column_string)
0463 #endif
0464 public:
0465 static tools::cid id_class() {
0466 static const std::string s_v;
0467 return tools::_cid(s_v);
0468 }
0469 virtual void* cast(tools::cid a_class) const {
0470 if(void* p = tools::cmp_cast<column_string>(this,a_class)) {return p;}
0471 else return 0;
0472 }
0473 virtual tools::cid id_cls() const {return id_class();}
0474 public:
0475 column_string(store& a_store,pages& a_pages,bool a_write,const std::string& a_name,tools::uint32 a_basket_size)
0476 :parent(a_store,a_pages,a_write,a_name,a_basket_size,m_tmp)
0477 {
0478 #ifdef TOOLS_MEM
0479 tools::mem::increment(s_class().c_str());
0480 #endif
0481 }
0482 virtual ~column_string(){
0483 #ifdef TOOLS_MEM
0484 tools::mem::decrement(s_class().c_str());
0485 #endif
0486 }
0487 protected:
0488 column_string(const column_string& a_from)
0489 :icol(a_from)
0490 ,parent(a_from)
0491 {}
0492 column_string& operator=(const column_string& a_from){
0493 if(&a_from==this) return *this;
0494 parent::operator=(a_from);
0495 return *this;
0496 }
0497 public:
0498 bool fill(const std::string& a_value) {m_tmp = a_value;return true;}
0499 bool get_entry(std::string& a_value) const {a_value = m_tmp;return true;}
0500 protected:
0501 std::string m_tmp;
0502 };
0503
0504
0505
0506 class std_vector_column_string_ref : public virtual icol {
0507 #ifdef TOOLS_MEM
0508 static const std::string& s_class() {
0509 static const std::string s_v("toolx::hdf5::ntuple::std_vector_column_string_ref");
0510 return s_v;
0511 }
0512 #endif
0513 public:
0514 static tools::cid id_class() {return tools::_cid_std_vector<std::string>()+10000;}
0515 virtual void* cast(tools::cid a_class) const {
0516 if(void* p = tools::cmp_cast<std_vector_column_string_ref>(this,a_class)) {return p;}
0517 else return 0;
0518 }
0519 virtual tools::cid id_cls() const {return id_class();}
0520 public: //icol
0521 virtual bool add() { //write.
0522 if(!m_write) return false;
0523 size_t _size = 0;
0524 {tools_vforcit(std::string,m_ref,it) {
0525 _size += (*it).size();
0526 _size++;
0527 }}
0528 char* _data = _size?new char[_size]:0;
0529 {char* pos = _data;
0530 tools_vforcit(std::string,m_ref,it) {
0531 ::memcpy(pos,(*it).c_str(),(*it).size());
0532 pos += (*it).size();
0533 *pos = 0;
0534 pos++;
0535 }}
0536 return m_branch.write_vlen<char>(_size,_data);
0537 }
0538 virtual bool fetch_entry() { //read.
0539 if(m_write) return false;
0540 size_t n;
0541 char* _data;
0542 if(!m_branch.read_vlen<char>(n,_data)) {
0543 m_store.out() << "toolx::hdf5::ntuple::std_vector_column_string_ref:fetch_entry : read_page() failed." << std::endl;
0544 return false;
0545 }
0546 m_ref.clear();
0547 {char* pos = _data;
0548 char* begin = _data;
0549 for(size_t ichar=0;ichar<n;ichar++,pos++) {
0550 if(*pos==0) {
0551 m_ref.push_back(begin);
0552 begin = pos+1;
0553 }
0554 }}
0555 delete [] _data;
0556 return true;
0557 }
0558 virtual void reset() {m_branch.reset_pos();}
0559 virtual const std::string& name() const {return m_name;}
0560 virtual bool set_basket_size(size_t) {return true;}
0561 public:
0562 std_vector_column_string_ref(store& a_store,pages& a_pages,bool a_write,const std::string& a_name,
0563 size_t /*a_basket_size*/,
0564 std::vector<std::string>& a_ref)
0565 :m_store(a_store)
0566 ,m_branch(a_pages)
0567 ,m_write(a_write)
0568 ,m_name(a_name)
0569 ,m_ref(a_ref)
0570 {
0571 #ifdef TOOLS_MEM
0572 tools::mem::increment(s_class().c_str());
0573 #endif
0574 }
0575 virtual ~std_vector_column_string_ref(){
0576 #ifdef TOOLS_MEM
0577 tools::mem::decrement(s_class().c_str());
0578 #endif
0579 }
0580 protected:
0581 std_vector_column_string_ref(const std_vector_column_string_ref& a_from)
0582 :icol(a_from)
0583 ,m_store(a_from.m_store)
0584 ,m_branch(a_from.m_branch)
0585 ,m_write(a_from.m_write)
0586 ,m_name(a_from.m_name)
0587 ,m_ref(a_from.m_ref)
0588 {}
0589 std_vector_column_string_ref& operator=(const std_vector_column_string_ref& a_from){
0590 if(&a_from==this) return *this;
0591 m_name = a_from.m_name;
0592 return *this;
0593 }
0594 protected:
0595 store& m_store;
0596 pages& m_branch;
0597 bool m_write;
0598 std::string m_name;
0599 std::vector<std::string>& m_ref;
0600 };
0601
0602 class std_vector_column_string : public std_vector_column_string_ref {
0603 typedef std_vector_column_string_ref parent;
0604 #ifdef TOOLS_MEM
0605 static const std::string& s_class() {
0606 static const std::string s_v("toolx::hdf5::ntuple::std_vector_column_string");
0607 return s_v;
0608 }
0609 #endif
0610 public:
0611 static tools::cid id_class() {return tools::_cid_std_vector<std::string>();}
0612 virtual void* cast(tools::cid a_class) const {
0613 if(void* p = tools::cmp_cast<std_vector_column_string>(this,a_class)) {return p;}
0614 else return 0;
0615 }
0616 virtual tools::cid id_cls() const {return id_class();}
0617 public:
0618 std_vector_column_string(store& a_store,pages& a_pages,bool a_write,const std::string& a_name,size_t a_basket_size)
0619 :parent(a_store,a_pages,a_write,a_name,a_basket_size,m_tmp)
0620 {}
0621 virtual ~std_vector_column_string(){}
0622 protected:
0623 std_vector_column_string(const std_vector_column_string& a_from)
0624 :icol(a_from)
0625 ,parent(a_from)
0626 {}
0627 std_vector_column_string& operator=(const std_vector_column_string& a_from){
0628 parent::operator=(a_from);
0629 return *this;
0630 }
0631 public:
0632 //bool get_entry(std::vector<T>& a_v) const {
0633 // a_v = m_tmp;
0634 // return true;
0635 //}
0636 const std::vector<std::string>& data() const {return m_tmp;}
0637 protected:
0638 std::vector<std::string> m_tmp;
0639 };
0640
0641 public:
0642 ntuple(std::ostream& a_out,hid_t a_group,const std::string& a_name,
0643 unsigned int a_compress,size_t /*a_basket_size*//* = 32000*/)
0644 :store(a_out,a_group,a_name,true,a_compress) //true=write
0645 {}
0646
0647 ntuple(std::ostream& a_out,hid_t a_group,const std::string& a_name)
0648 :store(a_out,a_group,a_name,false,0) //false=read
0649 {
0650 tools_vforcit(pages*,m_pagess,it){
0651
0652 #define TOOLX_HDF5_NTUPLE_READ_CREATE_COL(a__type) \
0653 if((*it)->form()==tools::stype(a__type())) {\
0654 column<a__type>* col = new column<a__type>(*this,*(*it),false,(*it)->name(),0);\
0655 if(!col) {tools::safe_clear<icol>(m_cols);return;}\
0656 m_cols.push_back(col);\
0657 }
0658
0659 #define TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(a__vec_type,a__type) \
0660 if((*it)->form()==s_vector_##a__vec_type()) {\
0661 std_vector_column<a__type>* col = new std_vector_column<a__type>(*this,*(*it),false,(*it)->name(),0);\
0662 if(!col) {tools::safe_clear<icol>(m_cols);return;}\
0663 m_cols.push_back(col);\
0664 }
0665
0666 #define TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL_STRING \
0667 if((*it)->form()==s_vector_string()) {\
0668 std_vector_column_string* col = new std_vector_column_string(*this,*(*it),false,(*it)->name(),0);\
0669 if(!col) {tools::safe_clear<icol>(m_cols);return;}\
0670 m_cols.push_back(col);\
0671 }
0672
0673 TOOLX_HDF5_NTUPLE_READ_CREATE_COL(char)
0674 else TOOLX_HDF5_NTUPLE_READ_CREATE_COL(short)
0675 else TOOLX_HDF5_NTUPLE_READ_CREATE_COL(int)
0676 else TOOLX_HDF5_NTUPLE_READ_CREATE_COL(tools::int64)
0677
0678 else TOOLX_HDF5_NTUPLE_READ_CREATE_COL(float)
0679 else TOOLX_HDF5_NTUPLE_READ_CREATE_COL(double)
0680
0681 else TOOLX_HDF5_NTUPLE_READ_CREATE_COL(tools::byte)
0682 else TOOLX_HDF5_NTUPLE_READ_CREATE_COL(tools::ushort)
0683 else TOOLX_HDF5_NTUPLE_READ_CREATE_COL(tools::uint32)
0684 else TOOLX_HDF5_NTUPLE_READ_CREATE_COL(tools::uint64)
0685
0686 //else TOOLX_HDF5_NTUPLE_READ_CREATE_COL(bool) //use byte=uchar.
0687
0688 else
0689 if((*it)->form()==s_string()) {
0690 column_string* col = new column_string(*this,*(*it),false,(*it)->name(),0);
0691 if(!col) {tools::safe_clear<icol>(m_cols);return;}
0692 m_cols.push_back(col);
0693 }
0694
0695 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(char,char)
0696 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(short,short)
0697 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(int,int)
0698 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(int64,tools::int64)
0699
0700 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(float,float)
0701 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(double,double)
0702
0703 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(uchar,tools::uchar)
0704 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(ushort,tools::ushort)
0705 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(uint32,tools::uint32)
0706 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(uint64,tools::uint64)
0707
0708 else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL_STRING
0709 // else TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL(bool) //use byte=uchar.
0710
0711 else {
0712 m_out << "toolx::hdf5::ntuple::ntuple(read) :"
0713 << " for column " << tools::sout((*it)->name())
0714 << ", type " << tools::sout((*it)->form()) << " not yet handled."
0715 << std::endl;
0716 //throw
0717 tools::safe_clear<icol>(m_cols);
0718 return;
0719 }
0720 }
0721 #undef TOOLX_HDF5_NTUPLE_READ_CREATE_VEC_COL
0722 #undef TOOLX_HDF5_NTUPLE_READ_CREATE_COL
0723 }
0724
0725 ntuple(std::ostream& a_out,hid_t a_group,const std::string& a_name,const tools::ntuple_binding& a_bd)
0726 :store(a_out,a_group,a_name,false,0) //false=read
0727 {
0728 if(!initialize(a_out,a_bd)) {}
0729 }
0730
0731 ntuple(std::ostream& a_out,hid_t a_group,const tools::ntuple_booking& a_bkg,
0732 unsigned int a_compress,size_t a_basket_size/* = 32000*/)
0733 :store(a_out,a_group,a_bkg.name(),true,a_compress) //true=write
0734 ,m_title(a_bkg.title())
0735 {
0736 const std::vector<tools::column_booking>& cols = a_bkg.columns();
0737 tools_vforcit(tools::column_booking,cols,it){
0738
0739 #define TOOLX_HDF5_NTUPLE_CREATE_COL(a__type) \
0740 if((*it).cls_id()==tools::_cid(a__type())) {\
0741 a__type* user = (a__type*)(*it).user_obj();\
0742 if(user) {\
0743 if(!create_column_ref<a__type>((*it).name(),a_basket_size,*user)) {\
0744 m_out << "toolx::hdf5::ntuple :"\
0745 << " can't create column_ref " << tools::sout((*it).name()) << "."\
0746 << std::endl;\
0747 tools::safe_clear<icol>(m_cols);\
0748 return;\
0749 }\
0750 } else {\
0751 if(!create_column<a__type>((*it).name(),a_basket_size)) {\
0752 m_out << "toolx::hdf5::ntuple :"\
0753 << " can't create column " << tools::sout((*it).name()) << "."\
0754 << std::endl;\
0755 tools::safe_clear<icol>(m_cols);\
0756 return;\
0757 }\
0758 }\
0759 }
0760
0761 #define TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(a__type) \
0762 if((*it).cls_id()==tools::_cid_std_vector<a__type>()) {\
0763 std::vector<a__type>* vec = (std::vector<a__type>*)(*it).user_obj();\
0764 if(!vec) {\
0765 m_out << "toolx::hdf5::ntuple :"\
0766 << " for std::vector column " << tools::sout((*it).name())\
0767 << ", the user vector pointer is null."\
0768 << std::endl;\
0769 tools::safe_clear<icol>(m_cols);\
0770 return;\
0771 }\
0772 if(!create_std_column_ref<a__type>((*it).name(),a_basket_size,*vec)) {\
0773 m_out << "toolx::hdf5::ntuple :"\
0774 << " can't create std::vector column " << tools::sout((*it).name()) << "."\
0775 << std::endl;\
0776 tools::safe_clear<icol>(m_cols);\
0777 return;\
0778 }\
0779 }
0780
0781 #define TOOLX_HDF5_NTUPLE_CREATE_VEC_COL_STRING \
0782 if((*it).cls_id()==tools::_cid_std_vector<std::string>()) {\
0783 std::vector<std::string>* vec = (std::vector<std::string>*)(*it).user_obj();\
0784 if(!vec) {\
0785 m_out << "toolx::hdf5::ntuple :"\
0786 << " for std::vector column " << tools::sout((*it).name())\
0787 << ", the user vector pointer is null."\
0788 << std::endl;\
0789 tools::safe_clear<icol>(m_cols);\
0790 return;\
0791 }\
0792 if(!create_std_column_string_ref((*it).name(),a_basket_size,*vec)) {\
0793 m_out << "toolx::hdf5::ntuple :"\
0794 << " can't create std::vector column " << tools::sout((*it).name()) << "."\
0795 << std::endl;\
0796 tools::safe_clear<icol>(m_cols);\
0797 return;\
0798 }\
0799 }
0800
0801 TOOLX_HDF5_NTUPLE_CREATE_COL(char)
0802 else TOOLX_HDF5_NTUPLE_CREATE_COL(short)
0803 else TOOLX_HDF5_NTUPLE_CREATE_COL(int)
0804 else TOOLX_HDF5_NTUPLE_CREATE_COL(tools::int64)
0805
0806 else TOOLX_HDF5_NTUPLE_CREATE_COL(float)
0807 else TOOLX_HDF5_NTUPLE_CREATE_COL(double)
0808
0809 else TOOLX_HDF5_NTUPLE_CREATE_COL(tools::byte)
0810 else TOOLX_HDF5_NTUPLE_CREATE_COL(tools::ushort)
0811 else TOOLX_HDF5_NTUPLE_CREATE_COL(tools::uint32)
0812 else TOOLX_HDF5_NTUPLE_CREATE_COL(tools::uint64)
0813
0814 //else TOOLX_HDF5_NTUPLE_CREATE_COL(bool) //use byte=uchar.
0815
0816 else if((*it).cls_id()==tools::_cid(std::string())) {
0817 if(!create_column_string((*it).name(),a_basket_size)) {
0818 m_out << "toolx::hdf5::ntuple :"
0819 << " can't create string column " << tools::sout((*it).name()) << "."
0820 << std::endl;
0821 tools::safe_clear<icol>(m_cols);
0822 return;
0823 }
0824
0825 } else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(char)
0826 else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(short)
0827 else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(int)
0828 else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(tools::int64)
0829
0830 else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(float)
0831 else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(double)
0832
0833 else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(tools::uchar)
0834 else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(tools::ushort)
0835 else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(tools::uint32)
0836 else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(tools::uint64)
0837
0838 else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL_STRING
0839 // else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(std::string)
0840 // else TOOLX_HDF5_NTUPLE_CREATE_VEC_COL(bool) //use byte=uchar.
0841
0842 else {
0843 m_out << "toolx::hdf5::ntuple :"
0844 << " for column " << tools::sout((*it).name())
0845 << ", type with cid " << (*it).cls_id() << " not yet handled."
0846 << std::endl;
0847 tools::safe_clear<icol>(m_cols);
0848 return;
0849 }
0850 }
0851 #undef TOOLX_HDF5_NTUPLE_CREATE_COL
0852 #undef TOOLX_HDF5_NTUPLE_CREATE_VEC_COL
0853
0854 }
0855
0856 virtual ~ntuple() {
0857 tools::safe_clear<icol>(m_cols);
0858 }
0859 protected:
0860 ntuple(const ntuple& a_from):store(a_from),m_title(a_from.m_title){}
0861 ntuple& operator=(const ntuple&){return *this;}
0862 public:
0863 bool initialize(std::ostream& a_out,const tools::ntuple_binding& a_bd = tools::ntuple_binding()) {
0864 tools::safe_clear<icol>(m_cols);
0865 {tools_vforcit(pages*,m_pagess,it) (*it)->reset_pos();}
0866
0867 tools_vforcit(pages*,m_pagess,it) {
0868
0869 #define TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(a__type) \
0870 if((*it)->form()==tools::stype(a__type())) {\
0871 a__type* user_var = a_bd.find_variable<a__type>((*it)->name());\
0872 if(user_var) {\
0873 column_ref<a__type>* col = new column_ref<a__type>(*this,*(*it),false,(*it)->name(),0,*user_var);\
0874 if(!col) {tools::safe_clear<icol>(m_cols);return false;}\
0875 m_cols.push_back(col);\
0876 } else {\
0877 column<a__type>* col = new column<a__type>(*this,*(*it),false,(*it)->name(),0);\
0878 if(!col) {tools::safe_clear<icol>(m_cols);return false;}\
0879 m_cols.push_back(col);\
0880 }\
0881 }
0882
0883 #define TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(a__vec_type,a__type) \
0884 if((*it)->form()==s_vector_##a__vec_type()) {\
0885 std::vector<a__type>* user_var = a_bd.find_variable< std::vector<a__type> >((*it)->name());\
0886 if(user_var) {\
0887 std_vector_column_ref<a__type>* col = \
0888 new std_vector_column_ref<a__type>(*this,*(*it),false,(*it)->name(),0,*user_var);\
0889 if(!col) {tools::safe_clear<icol>(m_cols);return false;}\
0890 m_cols.push_back(col);\
0891 } else {\
0892 std_vector_column<a__type>* col = new std_vector_column<a__type>(*this,*(*it),false,(*it)->name(),0);\
0893 if(!col) {tools::safe_clear<icol>(m_cols);return false;}\
0894 m_cols.push_back(col);\
0895 }\
0896 }
0897
0898 #define TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL_STRING \
0899 if((*it)->form()==s_vector_string()) {\
0900 std::vector<std::string>* user_var = a_bd.find_variable< std::vector<std::string> >((*it)->name());\
0901 if(user_var) {\
0902 std_vector_column_string_ref* col = \
0903 new std_vector_column_string_ref(*this,*(*it),false,(*it)->name(),0,*user_var);\
0904 if(!col) {tools::safe_clear<icol>(m_cols);return false;}\
0905 m_cols.push_back(col);\
0906 } else {\
0907 std_vector_column_string* col = new std_vector_column_string(*this,*(*it),false,(*it)->name(),0);\
0908 if(!col) {tools::safe_clear<icol>(m_cols);return false;}\
0909 m_cols.push_back(col);\
0910 }\
0911 }
0912
0913 TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(char)
0914 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(short)
0915 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(int)
0916 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(tools::int64)
0917
0918 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(float)
0919 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(double)
0920
0921 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(tools::byte)
0922 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(tools::ushort)
0923 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(tools::uint32)
0924 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(tools::uint64)
0925
0926 //else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL(bool) //use byte=uchar.
0927
0928 else
0929 if((*it)->form()==s_string()) {
0930 std::string* user_var = a_bd.find_variable<std::string>((*it)->name());
0931 if(user_var) {
0932 column_string_ref* col = new column_string_ref(*this,*(*it),false,(*it)->name(),0,*user_var);
0933 if(!col) {tools::safe_clear<icol>(m_cols);return false;}
0934 m_cols.push_back(col);
0935 } else {
0936 column_string* col = new column_string(*this,*(*it),false,(*it)->name(),0);
0937 if(!col) {tools::safe_clear<icol>(m_cols);return false;}
0938 m_cols.push_back(col);
0939 }
0940 }
0941
0942 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(char,char)
0943 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(short,short)
0944 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(int,int)
0945 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(int64,tools::int64)
0946
0947 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(float,float)
0948 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(double,double)
0949
0950 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(uchar,tools::uchar)
0951 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(ushort,tools::ushort)
0952 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(uint32,tools::uint32)
0953 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(uint64,tools::uint64)
0954
0955 else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL_STRING
0956
0957 // else TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL(bool) //use byte=uchar.
0958
0959 else {
0960 a_out << "toolx::hdf5::ntuple::ntuple(read with binding) :"
0961 << " for column " << tools::sout((*it)->name())
0962 << ", type " << tools::sout((*it)->form()) << " not yet handled."
0963 << std::endl;
0964 tools::safe_clear<icol>(m_cols);
0965 return false;
0966 }
0967 }
0968 #undef TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_COL
0969 #undef TOOLX_HDF5_NTUPLE_READ_BINDING_CREATE_VEC_COL
0970 return true;
0971 }
0972
0973 const std::string& title() const {return m_title;}
0974
0975 const std::vector<icol*>& columns() const {return m_cols;}
0976 std::vector<icol*>& columns() {return m_cols;}
0977
0978 template <class T>
0979 column_ref<T>* create_column_ref(const std::string& a_name,size_t a_basket_size,T& a_ref) {
0980 if(tools::find_named<icol>(m_cols,a_name)) return 0;
0981 pages* _pages = create_pages(a_name,tools::stype(T()));
0982 if(!_pages) return 0;
0983 column_ref<T>* col = new column_ref<T>(*this,*_pages,true,a_name,a_basket_size,a_ref);
0984 if(!col) return 0;
0985 m_cols.push_back(col);
0986 return col;
0987 }
0988
0989 template <class T>
0990 column<T>* create_column(const std::string& a_name,size_t a_basket_size) {
0991 if(tools::find_named<icol>(m_cols,a_name)) return 0;
0992 pages* _pages = create_pages(a_name,tools::stype(T()));
0993 if(!_pages) return 0;
0994 column<T>* col = new column<T>(*this,*_pages,true,a_name,a_basket_size);
0995 if(!col) return 0;
0996 m_cols.push_back(col);
0997 return col;
0998 }
0999
1000 column_string* create_column_string(const std::string& a_name,size_t a_basket_size) {
1001 if(tools::find_named<icol>(m_cols,a_name)) return 0;
1002 pages* _pages = create_pages(a_name,s_string());
1003 if(!_pages) return 0;
1004 column_string* col = new column_string(*this,*_pages,true,a_name,a_basket_size);
1005 if(!col) return 0;
1006 m_cols.push_back(col);
1007 return col;
1008 }
1009
1010 template <class T>
1011 std_vector_column_ref<T>* create_std_column_ref(const std::string& a_name,size_t a_basket_size,std::vector<T>& a_ref) {
1012 //NOTE : to optimize, we do not handle a default std::vector value logic.
1013 if(tools::find_named<icol>(m_cols,a_name)) return 0;
1014 pages* _pages = create_pages(a_name,"vector<"+tools::stype(T())+">");
1015 if(!_pages) return 0;
1016 std_vector_column_ref<T>* col = new std_vector_column_ref<T>(*this,*_pages,true,a_name,a_basket_size,a_ref);
1017 if(!col) return 0;
1018 m_cols.push_back(col);
1019 return col;
1020 }
1021
1022 std_vector_column_string_ref* create_std_column_string_ref(const std::string& a_name,size_t a_basket_size,std::vector<std::string>& a_ref) {
1023 //NOTE : to optimize, we do not handle a default std::vector value logic.
1024 if(tools::find_named<icol>(m_cols,a_name)) return 0;
1025 pages* _pages = create_pages(a_name,"vector<std::string>");
1026 if(!_pages) return 0;
1027 std_vector_column_string_ref* col = new std_vector_column_string_ref(*this,*_pages,true,a_name,a_basket_size,a_ref);
1028 if(!col) return 0;
1029 m_cols.push_back(col);
1030 return col;
1031 }
1032
1033 template <class T>
1034 column_ref<T>* find_column_ref(const std::string& a_name) {
1035 icol* col = tools::find_named<icol>(m_cols,a_name);
1036 if(!col) return 0;
1037 return tools::id_cast<icol, column_ref<T> >(*col);
1038 }
1039 template <class T>
1040 column<T>* find_column(const std::string& a_name) {
1041 icol* col = tools::find_named<icol>(m_cols,a_name);
1042 if(!col) return 0;
1043 return tools::id_cast<icol, column<T> >(*col);
1044 }
1045
1046 template <class T>
1047 std_vector_column_ref<T>* find_std_vector_column_ref(const std::string& a_name) {
1048 icol* col = tools::find_named<icol>(m_cols,a_name);
1049 if(!col) return 0;
1050 return tools::id_cast<icol, std_vector_column_ref<T> >(*col);
1051 }
1052 template <class T>
1053 std_vector_column<T>* find_std_vector_column(const std::string& a_name) {
1054 icol* col = tools::find_named<icol>(m_cols,a_name);
1055 if(!col) return 0;
1056 return tools::id_cast<icol, std_vector_column<T> >(*col);
1057 }
1058
1059 std_vector_column_string_ref* find_std_vector_column_string_ref(const std::string& a_name) {
1060 icol* col = tools::find_named<icol>(m_cols,a_name);
1061 if(!col) return 0;
1062 return tools::id_cast<icol, std_vector_column_string_ref >(*col);
1063 }
1064 std_vector_column_string* find_std_vector_column_string(const std::string& a_name) {
1065 icol* col = tools::find_named<icol>(m_cols,a_name);
1066 if(!col) return 0;
1067 return tools::id_cast<icol, std_vector_column_string >(*col);
1068 }
1069
1070 column_string* find_column_string(const std::string& a_name) {
1071 icol* col = tools::find_named<icol>(m_cols,a_name);
1072 if(!col) return 0;
1073 return tools::id_cast<icol, column_string >(*col);
1074 }
1075
1076 bool add_row() { //write.
1077 if(m_cols.empty()) return false;
1078 bool status = true;
1079 tools_vforit(icol*,m_cols,it) {if(!(*it)->add()) status = false;}
1080 //tools::uint32 n;
1081 //bool status = store::fill(n);
1082 //tools_vforit(icol*,m_cols,it) (*it)->set_def();
1083 return status;
1084 }
1085
1086 bool get_row() { //read.
1087 bool status = true;
1088 tools_vforcit(icol*,m_cols,it) {
1089 if(!(*it)->fetch_entry()) status = false;
1090 }
1091 return status;
1092 }
1093
1094 bool set_basket_size(size_t a_size) {
1095 tools_vforit(icol*,m_cols,it) {if(!(*it)->set_basket_size(a_size)) return false;}
1096 return true;
1097 }
1098
1099 void reset() { //read.
1100 tools_vforit(icol*,m_cols,it) (*it)->reset();
1101 }
1102
1103 protected:
1104 std::string m_title;
1105 std::vector<icol*> m_cols;
1106 };
1107
1108 }}
1109
1110
1111 #endif