// Content.cxx #include "dataset_base/Content.h" #include #include #include "dataset_util/XmlElement.h" #include "dataset_util/DtdRegistry.h" using std::string; using std::ostream; using std::endl; using dset::ContentBlock; using dset::Content; typedef Content::BlockList BlockList; typedef std::list CBList; //********************************************************************** // Local definitions. //********************************************************************** namespace { //********************************************************************** // Register the DTD. const DtdRegistry::Status stat_content_dtd = DtdRegistry::register_dtd("dataset"); } //********************************************************************** // Iteratively merge a block from a list of blocks into the other // blocks on that list. If the merge succeeds then the block is removed // from the list and the new block is merged in the same way. void list_merge(CBList& blks, const CBList::iterator& blkiter) { // Loop over iterations. CBList::iterator iblk = blkiter; while ( iblk != blks.end() ) { // Loop over the list. bool merged = false; for ( CBList::iterator jblk=blks.begin(); jblk!=blks.end(); ++jblk ) { if ( jblk == iblk ) continue; ContentBlock& lhs = **jblk; ContentBlock& rhs = **iblk; if ( lhs.check_merge(rhs) == 0 ) { // Merge. int stat = lhs.merge(rhs); assert( stat == 0 ); merged = true; // Delete the mergee and set iblk to point at the merger. blks.erase(iblk); iblk = jblk; break; } } if ( ! merged ) break; } } //********************************************************************** //} //********************************************************************** // Static member functions. //********************************************************************** // DTD. const Text& Content::dtd() { static Text txt; if ( txt.size() == 0 ) { txt.append(""); txt.append(""); } return txt; } //********************************************************************** // Constructors and destructor. //********************************************************************** // Empty or invalid constructor. Content::Content(int error) : m_error(error), m_compact(true) { } //********************************************************************** // Single block constructor w/o events. Content::Content(Name type, Name name, const ContentIdList& cids) : m_error(0), m_compact(true) { push_back(ContentBlock(type, name, cids)); m_compact = true; } //********************************************************************** // Single block constructor w/ events. Content::Content(Name type, Name name, const ContentIdList& cids, const EventIdList& eids) : m_error(0), m_compact(true) { push_back(ContentBlock(type, name, cids, eids)); m_compact = true; } //********************************************************************** // XML constructor. Content::Content(const XmlElement& ele) : m_error(0) { if ( ele.name() != xml_name() ) return; m_compact = ele.attribute_as_bool("compact"); for ( XmlElement::ElementList::const_iterator iele=ele.children().begin(); iele!=ele.children().end(); ++iele ) { m_blks.push_back(ContentBlock(**iele)); } } //********************************************************************** // Non-const methods. //********************************************************************** // Append a block. int Content::push_back(const ContentBlock& blk) { if ( ! is_valid() ) return 1; if ( ! blk.is_valid() ) return 2; m_blks.push_back(blk); m_compact = false; return 0; } //********************************************************************** // Append content. int Content::push_back(const Content& con) { if ( ! is_valid() ) return 1; if ( ! con.is_valid() ) return 2; const BlockList& blks = con.blocks(); for ( BlockList::const_iterator iblk = blks.begin(); iblk!=blks.end(); ++iblk ) { int stat = push_back(*iblk); if ( stat != 0 ) { return m_error = 11; } } return 0; } //********************************************************************** // Compact. int Content::compact() { if ( ! is_valid() ) return 1; if ( is_compact() ) return 0; if ( m_blks.size() < 2 ) return 0; BlockList::iterator iblk = m_blks.begin(); // Create list used for merging. CBList cblist; cblist.push_back(&*iblk); // Loop over blocks and try to merge each into the preceding blocks. while ( ++iblk != m_blks.end() ) { cblist.push_back(&*iblk); CBList::iterator icb = cblist.end(); --icb; list_merge(cblist, icb); } // If any merges took place, copy the new list. iblk = m_blks.begin(); if ( cblist.size() < m_blks.size() ) { for ( CBList::const_iterator ilcb=cblist.begin(); ilcb!=cblist.end(); ++ilcb ) { *iblk = **ilcb; ++iblk; } } m_blks.erase(iblk, m_blks.end()); m_compact = true; return 0; } //********************************************************************** // Merge a block. int Content::merge(const ContentBlock& blk) { if ( ! is_valid() ) return 1; m_blks.push_back(blk); if ( m_blks.size() == 1 ) return 0; // Create temporary list with m_blks and new block. CBList cblist; for ( BlockList::iterator iblk=m_blks.begin(); iblk!=m_blks.end(); ++iblk ) { cblist.push_back(&*iblk); CBList::iterator icb = cblist.end(); --icb; list_merge(cblist, icb); } // If any merges took place, copy the new list. if ( cblist.size() < m_blks.size() ) { BlockList::iterator iblk = m_blks.begin(); for ( CBList::const_iterator ilcb=cblist.begin(); ilcb!=cblist.end(); ++ilcb ) { *iblk = **ilcb; ++iblk; } m_blks.erase(iblk, m_blks.end()); } return 0; } //********************************************************************** // Merge content. int Content::merge(const Content& con) { if ( ! is_valid() ) return 1; if ( ! con.is_valid() ) return 2; const BlockList& blks = con.blocks(); for ( BlockList::const_iterator iblk = blks.begin(); iblk!=blks.end(); ++iblk ) { int stat = merge(*iblk); if ( stat != 0 ) { return m_error = 12; } } return 0; } //********************************************************************** // Const methods. //********************************************************************** // Validity. bool Content::is_valid() const { return m_error == 0; } //********************************************************************** // Error. int Content::error() const { return m_error; } //********************************************************************** // Is compact. bool Content::is_compact() const { return m_compact; } //********************************************************************** // Return the blocks. const BlockList& Content::blocks() const { return m_blks; } //********************************************************************** // Return the number of blocks. BlockList::size_type Content::size() const { return m_blks.size(); } //********************************************************************** // Return the first block. const ContentBlock& Content::front() const { if ( m_blks.size() == 0 ) { static ContentBlock empty; return empty; } return m_blks.front(); } //********************************************************************** // Has non-event content. bool Content::has_nonevent_content() const { if ( ! is_valid() ) return false; for ( BlockList::const_iterator iblk=blocks().begin(); iblk!=blocks().end(); ++iblk ) { if ( ! iblk->has_events() ) return true; } return false; } //********************************************************************** // Has event content. bool Content::has_event_content() const { if ( ! is_valid() ) return false; for ( BlockList::const_iterator iblk=blocks().begin(); iblk!=blocks().end(); ++iblk ) { if ( iblk->has_events() ) return true; } return false; } //********************************************************************** // Return the event content. Content Content::event_content() const { if ( ! is_valid() ) return *this; Content tmpcon; for ( BlockList::const_iterator iblk=blocks().begin(); iblk!=blocks().end(); ++iblk ) { if ( iblk->has_events() ) tmpcon.push_back(*iblk); } return tmpcon; } //********************************************************************** // Return the nonevent content. Content Content::nonevent_content() const { if ( ! is_valid() ) return *this; Content tmpcon; for ( BlockList::const_iterator iblk=blocks().begin(); iblk!=blocks().end(); ++iblk ) { if ( ! iblk->has_events() ) tmpcon.push_back(*iblk); } return tmpcon; } //********************************************************************** // Is empty. bool Content::is_empty() const { if ( ! is_valid() ) return false; for ( BlockList::const_iterator iblk=blocks().begin(); iblk!=blocks().end(); ++iblk ) { if ( ! iblk->is_empty() ) return false; } return true; } //********************************************************************** // Memory size. size_t Content::memsize() const { size_t mem = 0; mem += sizeof(m_blks); for ( BlockList::const_iterator iblk=m_blks.begin(); iblk!=m_blks.end(); ++iblk ) { mem += iblk->memsize(); } mem += sizeof(m_error); mem += sizeof(m_compact); return mem; } //********************************************************************** // Write to XML. const XmlElement* Content::xml() const { if ( ! is_valid() ) return 0; XmlElement* pele = new XmlElement(xml_name()); pele->add_attribute_as_bool("compact", is_compact()); for ( BlockList::const_iterator iblk=blocks().begin(); iblk!=blocks().end(); ++iblk ) { pele->add_child(iblk->xml()); } return pele; } //********************************************************************** // Output stream. ostream& Content::ostr(ostream& lhs, string indent) const { if ( ! is_valid() ) { lhs << indent << "Invalid content; error " << error(); return lhs; } BlockList::size_type nblk = blocks().size(); lhs << indent << "Content includes " << nblk << " block"; if ( nblk != 1 ) lhs << "s"; if ( nblk ) { lhs << ":"; for ( BlockList::const_iterator iblk=blocks().begin(); iblk!=blocks().end(); ++iblk ) { lhs << '\n'; iblk->ostr(lhs, indent + " "); } } return lhs; } //********************************************************************** // Free functions. //********************************************************************** // Output stream. ostream& operator<<(ostream& lhs, const Content& rhs) { return rhs.ostr(lhs, ""); } //********************************************************************** // Equality. bool dset::operator==(const Content& lhs, const Content& rhs) { return lhs.blocks() == rhs.blocks(); } //********************************************************************** // Inequality. bool dset::operator!=(const Content& lhs, const Content& rhs) { return ! operator==(lhs, rhs); } //**********************************************************************