// ---------------------------------------------------------------------- // // HepNtuple.cc - implementation of some methods of the HepNtuple // class // // Are defined in this file: // block (const char blockName[], char format[], vector addresses); // Will create and add to the Ntuple the block and column // implied by format. // Block* unspecifiedBlock(); // returns the current unspecified block. Create a new // if the current one is block. // The name will be #0000001 for the first unspecified block, // and after it is frozen and fUB() is called again, #0000002, etc. // For row-wise, it will start as the title of the Ntuple, and after it // is frozen forming new blocks will require the special rewind() // action so the same name will be retained. #include "HepTuple/HepNtuple.h" #include "HepTuple/Block.h" #include "HepTuple/TupleNameTag.h" #include "HepTuple/HepFileManager.h" // for sprintf #include #include USING( std::string ) ZM_BEGIN_NAMESPACE( zmht ) /* namespace zmht { */ // type identifier ( is equal to type() for this object ) const char HepNtuple::typeId = 'N'; // ********************************************************************** // Constructors HepNtuple::HepNtuple(HepFileManager* manager, const string& title, int idReq) : HepObj( manager, title.c_str(), idReq), _changedDefinition(false), _storageGeometry(COLUMN), _storageLocation('D'), _sharedMemoryAreaName(0), _nwbuff(1024), _buffLimit(1024), _bufferType(DEMAND), _unspecifiedBlock(0), _unspecifiedBlockNumber(0), _lockNoNewColumns(false), _currentColumn(0), _nrows(0) { HEP_DEBUG( "HepNtuple::constructor( \"" << title << "\", " << id_ << " )" ); type_ = 'N'; manager->signIn( this ); // the default should be: (it can not be called here because each // of this function make a call to a isXXXenable which is virtual! // setColumnWise(); // setDiskResident(); // setNwbuff(defNwbuff); // setDemandBuffers(defDemandNbytes); // setNoNewColumns(false); } HepNtuple::HepNtuple() : HepObj() { HEP_DEBUG( "HepNtuple::constructor()" ); type_ = 'N'; } // ********************************************************************** // Destructor HepNtuple::~HepNtuple() { HEP_DEBUG( "HepNtuple::destructor( " << id_ << " )" ); columnsMap::iterator iterateCol = columns.begin(); while ( ! (iterateCol == columns.end()) ) { delete (*iterateCol).second; iterateCol++; } blocksMap::iterator iterateBlock = blocks.begin(); while ( ! (iterateBlock == blocks.end()) ) { // We Assume that the block do NOT delete its column. delete (*iterateBlock).second; iterateBlock++; } } // ********************************************************************** // Duplicator ZM_COVARIANT_TYPE(HepObj, HepNtuple ) & HepNtuple::makeEmpty(const string& title, int id ) const { HEP_DEBUG( "HepNtuple::makeClone( \"" << title << "\", " << id_ << " )" ); return makeEmpty(manager(), title, id); } ZM_COVARIANT_TYPE(HepObj, HepNtuple ) & HepNtuple::makeEmpty(HepFileManager* mgr, const string& title, int id) const { HepNtuple* copy = & mgr->ntuple(title, id); for ( blocksMap::const_iterator iterateBlock(blocks.begin()); iterateBlock != blocks.end(); iterateBlock++) { Block *bk = (*iterateBlock).second; Block *newBk = bk->duplicate(copy); copy->addBlock(newBk); // newBk already contains the new columns we need to add them to // the HepTuple lists. for ( Block::columnsVec::const_iterator iterateCol( newBk->columns().begin() ); iterateCol != newBk->columns().end(); iterateCol++ ) { Column* col = *iterateCol; copy->addColumn( col ); } } return *copy; } ZM_COVARIANT_TYPE(HepObj, HepNtuple ) & HepNtuple::makeClone(const string& title, int id ) const { HEP_DEBUG( "HepNtuple::makeClone( \"" << title << "\", " << id_ << " )" ); return makeClone(manager(), title, id); } class SmallAttributes { // This small intermediate class is used to save and restore the // status of destination and capture origin of a column void* variable; // . . . . Designated variable genericFunction function;// Designated function void* getMethod; // pointer to use ZMuseMethod for Designated Method void* destination; // . . . . Destination variable genericFunction destFunction; // Destination function void* setMethod; // pointer to use ZMsetMethod for Designated Method public: SmallAttributes() : variable(0), function(0), getMethod(0), destination(0), destFunction(0), setMethod(0) {}; SmallAttributes( const SmallAttributes& oldVersion ) : variable(oldVersion.variable), function(oldVersion.function), getMethod(oldVersion.getMethod), destination(oldVersion.destination), destFunction(oldVersion.destFunction), setMethod(oldVersion.setMethod) {}; SmallAttributes( const ColumnAttribs& oldVersion ) : variable(oldVersion.variable), function(oldVersion.function), getMethod(oldVersion.getMethod), destination(oldVersion.destination), destFunction(oldVersion.destFunction), setMethod(oldVersion.setMethod) {}; // We omit operator=( const SmallAttributes& ) because we are satisfied // with bitwise member copy. void Update ( Column * col ) { // Since here old variable/function are generic, the following calls // are to the generic Column member functions, unlike their ColumnT // type specific equivalent those have NO side effect col->setDesignatedVariable (variable); col->setDesignatedFunction (function); col->setDesignatedMethod (getMethod); col->setDestinationVariable(destination); col->setDestinationFunction(destFunction); col->setDestinationMethod (setMethod); } }; ZM_COVARIANT_TYPE(HepObj, HepNtuple ) & HepNtuple::makeClone(HepFileManager* mgr, const string& title, int id) const { HepNtuple* copy = (HepNtuple*) ( & makeEmpty( mgr, title, id) ); // Establish the destinations Block::columnsVec::const_iterator orig_col, dest_col; SmallAttributes * origAttrib = new SmallAttributes[nColumns()]; SmallAttributes * destAttrib = new SmallAttributes[nColumns()]; SmallAttributes Nothing; // all zeros Int4 index = 0; for ( blocksMap::const_iterator iterateBlock(blocks.begin()); iterateBlock != blocks.end(); iterateBlock++) { Block *bk = (*iterateBlock).second; Block *dest_bk = copy->findBlock( bk->name() ); for(orig_col = bk->columns().begin(),dest_col = dest_bk->columns().begin(); orig_col!= bk->columns().end() && dest_col != dest_bk->columns().end(); orig_col++, dest_col++ ) { Column* orig = *orig_col; Column* dest = *dest_col; // Remember the users designated variables etc ... origAttrib[index] = orig->attributes(); destAttrib[index] = dest->attributes(); index ++; Nothing.Update( orig ); Nothing.Update( dest ); // The destination variable for the column read is set to be the place // holder for the column written. NO designated variable or function is // set for the column written, this way the value written when the // original column is read is kept and used for the storing. orig->setDestinationVariable( dest->getValueAddr() ); } } // Copy the data int row; int end = nrows(); int status = 1; // We need to const cast because so far readRow which 'should' // be a const function is not (due to current or past deficiency // in 'mutable'). HepNtuple * this_p = const_cast (this); for ( row = 1; row <= end ; row++ ) { status &= this_p->readRow( row ) ; status &= copy->captureThenStore(); } // Restore the column settings. index = 0; for ( blocksMap::const_iterator iterateBlock(blocks.begin()); iterateBlock != blocks.end(); iterateBlock++) { Block *bk = (*iterateBlock).second; Block *dest_bk = copy->findBlock( bk->name() ); for( orig_col = bk->columns().begin(), dest_col = dest_bk->columns().begin(); orig_col != bk->columns().end() && dest_col != dest_bk->columns().end(); orig_col++, dest_col++ ) { Column* orig = *orig_col; Column* dest = *dest_col; origAttrib[index].Update( orig); destAttrib[index].Update( dest); index++; } } delete [] destAttrib; delete [] origAttrib; return *copy; } // Append an existing ntuple to the current one. Both nutple needs to // have the same columns in the same orders (column name excepted) HepNtuple & HepNtuple::append ( const HepNtuple& from ) { if ( isCompatible ( from ) ) { // Establish the destinations Block::columnsVec::const_iterator orig_col, from_col; SmallAttributes * origAttrib = new SmallAttributes[nColumns()]; SmallAttributes * destAttrib = new SmallAttributes[nColumns()]; SmallAttributes Nothing; // all zeros Int4 index = 0; for ( blocksMap::const_iterator iterateBlock(blocks.begin()); iterateBlock != blocks.end(); iterateBlock++) { Block *bk = (*iterateBlock).second; Block *from_bk = from.findBlock( bk->name() ); for( orig_col =bk->columns().begin(); orig_col!=bk->columns().end(); orig_col++ ) { Column* orig = *orig_col; Column* from_c = from_bk->findColumn( orig->name() ); // Remember the users designated variables etc ... origAttrib[index] = orig->attributes(); destAttrib[index] = from_c->attributes(); index ++; Nothing.Update( orig ); Nothing.Update( from_c ); // The destination variable for the column read is set to be the place // holder for the column written. NO designated variable or function is // set for the column written, this way the value written when the // original column is read is kept and used for the storing. from_c->setDestinationVariable( orig->getValueAddr() ); } } // Copy the data int row; int end = from.nrows(); int status = 1; // We need to const cast because so far readRow which 'should' // be a const function is not (due to current or past deficiency // in 'mutable'). HepNtuple * from_p = const_cast (&from); for ( row = 1; row <= end ; row++ ) { status &= from_p->readRow( row ) ; status &= captureThenStore(); if ( ! status ) { std::cerr << "Problem" << std::endl; } } // Restore the column settings. index = 0; for ( blocksMap::const_iterator iterateBlock(blocks.begin()); iterateBlock != blocks.end(); iterateBlock++) { Block *bk = (*iterateBlock).second; Block *from_bk = from.findBlock( bk->name() ); for( orig_col =bk->columns().begin(),from_col = from_bk->columns().begin(); orig_col!=bk->columns().end()&& from_col != from_bk->columns().end(); orig_col++, from_col++ ) { Column* orig = *orig_col; Column* from_c = *from_col; // Restore the user's settings origAttrib[index].Update(orig); destAttrib[index].Update(from_c); } } delete[] destAttrib; delete[] origAttrib; } else { ZMthrow( ZMxHepUnsupported("Tried to append 2 uncompatible HepTuple" )); } return *this; } // Return true if the argument HepTuple has a column layout compatible // with the current one. // They are if: // - they have the same number of column // - in increasing order (for each block, each column) each column is // compatible (i.e both of same numeric type or both string) // - for all column arrays, the column in ntuple_1 have LESS elements // than in ntuple_2 // NOTE: this function and the above 'could' be improved to contain // an automatic cast of numeric values ... // NOTE: this function and the above 'could' be improved to allow // for smaller array to be appended bool HepNtuple::isCompatible ( const HepNtuple& hep ) { if ( nColumns() != hep.nColumns() ) return false; Block::columnsVec::const_iterator i_col; blocksMap::const_iterator i_bk; for ( i_bk = blocks.begin(); i_bk != blocks.end(); i_bk++ ) { Block * bk = (*i_bk).second; Block * hep_bk = hep.findBlock( bk->name() ); if ( hep_bk == NULL ) return false; for ( i_col = (*i_bk).second->columns().begin(); i_col != (*i_bk).second->columns().end(); i_col ++ ) { Column * hep_col = bk->findColumn( (*i_col)->name() ); if ( hep_col == NULL ) return false; // Check types ColumnAttribs i_ca = (*i_col)->attributes(); ColumnAttribs i_hep_ca = (hep_col)->attributes(); if ( i_ca.type != i_hep_ca.type ) return false; Int4 i, dim_1 = 1; for( i=0; i < i_ca.ndim; i++ ) { dim_1 *= i_ca.extents[i]; } Int4 dim_2 = 1; for( i=0; i < i_hep_ca.ndim; i++ ) { dim_2 *= i_hep_ca.extents[i]; } if ( dim_1 != dim_2 ) return false; } } return true; } // ************************************************************************ // Access to blocks and columns // // unspecifiedBlock // // return a block that can accept new columns. // It will create a new if needed. The name of the block // will #number_of_unspecified_block_created ( #1 #2 etc ...) // Block* HepNtuple::unspecifiedBlock() { if ( _unspecifiedBlock == NULL || _unspecifiedBlock->isLockedNewColumn() ) { string name; // we loop to insure that the block name does not exist // yet. It could happen if we load back an ntuple that // has an unspecifiedBlock. do { _unspecifiedBlockNumber++; char temporary[128]; sprintf(temporary,"_%d",_unspecifiedBlockNumber); name = temporary; } while ( findBlock(name) != 0 ); _unspecifiedBlock = new Block(this,name,isCaseSensitive()); addBlock(_unspecifiedBlock); } return _unspecifiedBlock; } bool HepNtuple::addBlock(Block *bk) { changedDefinition(); if ( isCaseSensitive() ) { blocks[bk->name()] = bk; } else { string UpperName(bk->name()); for ( std::string::size_type i=0; i < UpperName.size(); i++) { UpperName[i] = toupper( UpperName[i] ); } blocks[UpperName] = bk; } return true; } bool HepNtuple::addColumn(Column *col) { if ( ! isTypeEnabled(col->attributes().type) ) { ZMthrow(ZMxHepTypeMismatch (string("For Column: ")+col->name()+ TypeInformation[col->attributes().type].shortcut)); return false; } changedDefinition(); if ( isCaseSensitive() ) { columns[col->name()] = col; } else { string UpperName(col->name()); for (std::string::size_type i=0; i < UpperName.size(); i++) { UpperName[i] = toupper( UpperName[i] ); } columns[UpperName] = col; } return true; } bool HepNtuple::addColumn(Block *bk,Column *col) { if ( ! isTypeEnabled(col->attributes().type,bk) ) { ZMthrow(ZMxHepTypeMismatch (string("In Block: ")+bk->name()+" the type: "+ TypeInformation[col->attributes().type].shortcut+ " is not supported." ) ); return false; } if ( addColumn(col) ) { bk->addColumn(col); } return true; } // ************************************************************************ // Block creation. bool HepNtuple::block( const string& blockName, const string& format, std::STL_VECTOR(void*) addresses ) { HEP_DEBUG( "HepNtuple::block( \"" << blockName << "\", \"" << format << "\" )" ); if ( ! isValid() ) { return false; } if (format.length() == 0 ) { ZMthrow(ZMxHepBadFormat("Empty format")); return false; } string probe(blockName+TupleNameTag::NameTagDelimiter+"A"); TupleNameTag tag; parseNameTag( tag, probe); if ( !tag.isValid() ) { // Might actually belong in the block constructor ZMthrow(ZMxHepCantMakeBlock(string("The block name: ") +blockName+" is invalid")); return false; } std::STL_VECTOR(ColumnAttribs*) CAs = parseFormat(format); if ( CAs.size() == 0) { ZMthrow(ZMxHepCantMakeBlock(string("Block Format: ") +format+" is invalid")); return false; } if ( CAs.size() != addresses.size() ) { ZMthrow(ZMxHepCantMakeBlock("The number of addresses provided is different from the number columns!")); return false; } Block *bk; if ( blockName.empty() ) { bk = unspecifiedBlock(); } else { bk = new Block(this,blockName,isCaseSensitive()); addBlock(bk); } int i = 0; bool result = true; typedef std::STL_VECTOR(ColumnAttribs*) vecCa; for ( vecCa::const_iterator iterateAttribs(CAs.begin()); iterateAttribs != CAs.end(); iterateAttribs++ ) { ColumnAttribs *ca = * iterateAttribs; Column* newCol = Column::newColumn(bk,*ca); // The ColumnAttribs is now copied we can now delete it. delete ca; if ( newCol == 0 ) return false; result &= newCol->setDesignatedVariable(addresses[i]); result &= addColumn(bk,newCol); i++; } return result; } /**************/ /* */ /* findColumn */ /* */ /**************/ // // Find the column in this HepNtuple which has the supplied column name. // Return a null pointer if no such column exists. Otherwise, return // a Column* pointing to that column. // Column* HepNtuple::findColumn ( const string& nametag ) const { static TupleNameTag tag; parseNameTag(tag, nametag); if (!tag.isValid()) { ZMthrow ( ZMxHepUnknownColumn (string("Improper form for column name tag: ")+nametag) ); return NULL; } Column * col = NULL; columnsMap::const_iterator it; if ( tag.block().length() != 0 ) { Block *bk = findBlock(tag.block()); if ( bk == NULL ) { return NULL; } col = bk->findColumn(tag.column()); } else { if ( columns.empty() ) return col; if ( isCaseSensitive() ) { it = columns.find(tag.column()); } else { string UpperName(tag.column()); for (std::string::size_type i=0; i < UpperName.size(); i++) { UpperName[i] = toupper( UpperName[i] ); } it = columns.find(UpperName); } col = (it == columns.end() ? (Column*)NULL : (*it).second); } return col; } // /*************/ /* */ /* findBlock */ /* */ /*************/ // // Find the block in this HepNtuple which has the supplied name. // Return a null pointer if no such Block exists. // Block* HepNtuple::findBlock ( const string& BlockName ) const { static TupleNameTag tag; parseNameTag( tag, BlockName+TupleNameTag::NameTagDelimiter+"A"); if (!tag.isValid()) { ZMthrow ( ZMxHepUnknownBlock("Block name invalid "+BlockName+".") ); return NULL; } if ( blocks.empty() ) return NULL; blocksMap::const_iterator it; if ( ! isCaseSensitive() ) { string UpperBlockName = BlockName; for (std::string::size_type i=0; i < BlockName.size(); i++) { UpperBlockName[i] = toupper( UpperBlockName[i] ); } it = blocks.find(UpperBlockName); } else { it = blocks.find(BlockName); } return ( it == blocks.end() ? (Block*)NULL : (*it).second ); } // /*******************/ /* */ /* isNameAvailable */ /* */ /*******************/ // // This version verifies that the nameTag AS specified in not already // in use. // For example if A::B exist A::B is not available C::B is available // and B is not availaible. bool HepNtuple::isNameAvailable ( const string& nameTag ) const { Column * col = findColumn(nameTag); if ( col != NULL ) { return false; } else { return true; } } /****************/ /* */ /* parseNametag */ /* */ /****************/ // // Parse the nametag for a column, providing block and column names. // return a TupleNameTag with the method isValid(), block() and column() // returning the proper result const TupleNameTag& HepNtuple::parseNameTag (TupleNameTag& what, const string& nametag, bool withIndices) const { static TupleNameTag tag; tag.init(nametag,withIndices,what); return what; } /* parseNameTag */ // ************************************************************************ // Restore a block from an existing ntuple bool HepNtuple::restoreBlock( const string& blockName, const string& format ) { HEP_DEBUG( "HepNtuple::restoreBlock( \"" << blockName << "\", \"" << format << "\" )" ); if ( ! isValid() ) { return false; } if ( ! blockName.empty() ) { string probe(blockName+TupleNameTag::NameTagDelimiter+"A"); TupleNameTag tag; parseNameTag( tag, probe); if ( !tag.isValid() ) { // Might actually belong in the block constructor ZMthrow(ZMxHepCantMakeBlock("The block name: "+blockName+" is invalid")); return false; } } // Get a copy of the current value of _changedDefinition // and put it back before returning. bool tmpValue = _changedDefinition; std::STL_VECTOR(ColumnAttribs*) CAs = parseFormat(format); if ( CAs.size() == 0) { ZMthrow(ZMxHepCantMakeBlock("Block Format: "+format+" is invalid")); _changedDefinition = tmpValue; return false; } bool result = true; Block * bk; if( blockName.empty() ) { bk = this->unspecifiedBlock(); } else { bk = new Block(this,blockName,isCaseSensitive()); result &= this->addBlock(bk); } if( ! result ) { _changedDefinition = tmpValue; return false; } typedef std::STL_VECTOR(ColumnAttribs*) vecCa; for ( vecCa::const_iterator iterateAttribs(CAs.begin()); iterateAttribs != CAs.end(); iterateAttribs++ ) { ColumnAttribs *ca = * iterateAttribs; Column* newCol = Column::newColumn(bk,*ca); // The ColumnAttribs is now copied we can now delete it. delete ca; if ( newCol == 0 ) result = false; if( result ) result &= addColumn(bk,newCol); } // AFTER creating all the columns, set the lock for each one. JMM 31 Oct. 1997 for ( Block::columnsVec::const_iterator iterateCol( bk->columns().begin() ); iterateCol != bk->columns().end(); iterateCol++ ) { Column* col = *iterateCol; col->setHasBeenStored(); } _changedDefinition = tmpValue; bk->book(); return result; } bool HepNtuple::setNrowsValue( int newNrows ) { _nrows = newNrows; return true; } ZM_END_NAMESPACE( zmht ) /* } // namespace zmht */