// ContentBlock.cxx #include "dataset_base/ContentBlock.h" #include #include "dataset_util/Environment.h" #include "dataset_util/memsize.h" #include "dataset_util/XmlElement.h" #include "dataset_util/DtdRegistry.h" using std::string; using std::ostream; using std::endl; using dset::ContentBlock; typedef ContentBlock::Name Name; //********************************************************************** // Local definitions. //********************************************************************** namespace { // Register the DTD. const DtdRegistry::Status stat_content_dtd = DtdRegistry::register_dtd("dataset"); // Maximum number of event ranges to write to XML. EventIdList::size_type& max_xml_ranges() { static EventIdList::size_type val = 10000; return val; } } //********************************************************************** // Static member functions. //********************************************************************** // DTD. const Text& ContentBlock::dtd() { static Text txt; if ( txt.size() == 0 ) { txt.append(""); txt.append(""); } return txt; } //********************************************************************** // Set the maximum number of XML ranges. void ContentBlock::set_maximum_xml_ranges(EventIdList::size_type thr) { max_xml_ranges() = thr; } //********************************************************************** // Return the maximum number of XML ranges. EventIdList::size_type ContentBlock::maximum_xml_ranges() { return max_xml_ranges(); } //********************************************************************** // Member functions. //********************************************************************** // Default constructor. ContentBlock::ContentBlock() : m_error(0) { } //********************************************************************** // Constructor without event ID's. ContentBlock:: ContentBlock(Name type, Name name, const ContentIdList& cids) : m_error(0), m_type(type), m_name(name), m_cids(cids), m_has_evids(false), m_has_explicit_evids(false), m_event_count(0) { } //********************************************************************** // Constructor with event ID's. ContentBlock:: ContentBlock(Name type, Name name, const ContentIdList& cids, const EventIdList& eids) : m_error(0), m_type(type), m_name(name), m_cids(cids), m_has_evids(true), m_eids(eids), m_has_explicit_evids(true), m_event_count(eids.size()) { } //********************************************************************** // XML constructor. ContentBlock:: ContentBlock(const XmlElement& ele) : m_error(0), m_event_count(0) { if ( ele.name() != xml_name() ) return; m_type = ele.attribute("type"); m_name = ele.attribute("name"); m_has_evids = ele.attribute_as_bool("has_events"); if ( m_has_evids ) { m_event_count = ele.attribute_as_unsigned_int("event_count"); } // Extract content ID's. const XmlElement* pele_cids = ele.single_child(ContentIdList::xml_name()); assert( pele_cids != 0 ); if ( pele_cids == 0 ) return; m_cids = ContentIdList(*pele_cids); // Extract event ID's if present. const XmlElement* pele_eids = ele.single_child(EventIdList::xml_name()); if ( pele_eids == 0 ) { m_has_explicit_evids = false; } else { assert( m_has_evids ); m_has_explicit_evids = true; m_eids = EventIdList(*pele_eids); } } //********************************************************************** // Const methods. //********************************************************************** // Validity. bool ContentBlock::is_valid() const { return m_error == 0; } //********************************************************************** // Error. int ContentBlock::error() const { return m_error; } //********************************************************************** // Return the type. Name ContentBlock::dataset_type() const { return m_type; } //********************************************************************** // Return the name. Name ContentBlock::name() const { return m_name; } //********************************************************************** // Return the content ID's. const ContentIdList& ContentBlock::content_ids() const { return m_cids; } //********************************************************************** // Return if the block holds event data. bool ContentBlock::has_events() const { return m_has_evids; } //********************************************************************** // Return if event ID's are explicit. bool ContentBlock::has_explicit_events() const { return m_has_explicit_evids; } //********************************************************************** // Return the # events. EventIdList::size_type ContentBlock::event_count() const { return m_event_count; } //********************************************************************** // Return the event ID's. const EventIdList& ContentBlock::event_ids() const { return m_eids; } //********************************************************************** // Emptiness. bool ContentBlock::is_empty() const { return m_cids.size()==0 || (has_events() && event_count()==0); } //********************************************************************** // Can merge. int ContentBlock::check_merge(const ContentBlock& rhs) const { string sallow = Environment::current().value("DIAL_ALLOW_INCONSISTENT_CONTENT"); bool allow = sallow.size(); const ContentBlock& lhs = *this; if ( ! lhs.is_valid() ) return 1; if ( ! rhs.is_valid() ) return 2; ContentBlock::Name ltype = lhs.dataset_type(); ContentBlock::Name rtype = rhs.dataset_type(); ContentBlock::Name lname = lhs.name(); ContentBlock::Name rname = rhs.name(); if ( ltype != rtype ) return 3; if ( lname != rname ) return 4; bool check_ids = false; bool check_evts = false; if ( lhs.has_events() ) { if ( ! rhs.has_events() ) return 5; if ( ! lhs.has_explicit_events() ) return 11; if ( ! rhs.has_explicit_events() ) return 12; if ( lhs.event_ids() == rhs.event_ids() ) { check_ids = true; } else if ( lhs.content_ids() == rhs.content_ids() || allow ) { check_evts = true; } else { return 6; } } else { if ( rhs.has_events() ) return 7; check_ids = true; } if ( check_ids ) { for ( ContentIdList::const_iterator ilco=lhs.content_ids().begin(); ilco!=lhs.content_ids().end(); ++ilco ) { for ( ContentIdList::const_iterator irco=rhs.content_ids().begin(); irco!=rhs.content_ids().end(); ++irco ) { if ( *ilco == *irco ) return 8; } } } if ( check_evts ) { if ( lhs.event_ids().overlaps(rhs.event_ids()) ) return 9; } return 0; } //********************************************************************** // Memory size. size_t ContentBlock::memsize() const { size_t mem = 0; mem += sizeof(m_error); mem += memsize_string(m_type); mem += memsize_string(m_name); mem += memsize_set(m_cids); mem += sizeof(m_has_evids); mem += m_eids.memsize(); mem += sizeof(m_has_explicit_evids); mem += sizeof(m_event_count); return mem; } //********************************************************************** // Write to XML. const XmlElement* ContentBlock::xml() const { if ( ! is_valid() ) return 0; XmlElement* pele = new XmlElement(xml_name()); pele->add_attribute("type", dataset_type()); pele->add_attribute("name", name()); pele->add_attribute_as_bool("has_events", has_events()); if ( has_events() ) { pele->add_attribute_as_unsigned_int("name", event_count()); } pele->add_child(content_ids().xml()); if ( has_events() ) { pele->add_attribute_as_unsigned_int("event_count", event_count() ); } if ( has_explicit_events() && event_ids().ranges().size() <= max_xml_ranges() ) { pele->add_child(event_ids().xml()); } return pele; } //********************************************************************** // Output stream. ostream& ContentBlock::ostr(ostream& lhs, string indent) const { Name stype = dataset_type(); if ( ! stype.size() ) stype = ""; Name sname = name(); if ( ! sname.size() ) sname = ""; string indent2 = indent + " "; lhs << indent << "Dataset content block:" << endl; lhs << indent2 << "Dataset type: " << stype << endl; lhs << indent2 << "Content label: " << sname; lhs << endl; content_ids().ostr(lhs, indent2); if ( has_explicit_events() ) { lhs << endl; event_ids().ostr(lhs, indent2); } else if ( has_events() ) { lhs << endl << indent2 << "Event count is " << event_count(); } return lhs; } //********************************************************************** // Non-const members. //********************************************************************** // Merge. int ContentBlock::merge(const ContentBlock& rhs) { string sallow = Environment::current().value("DIAL_ALLOW_INCONSISTENT_CONTENT"); bool allow = sallow.size(); ContentBlock& lhs = *this; if ( ! lhs.is_valid() ) { return 1; } if ( ! rhs.is_valid() ) { return 2; } ContentBlock::Name ltype = lhs.dataset_type(); ContentBlock::Name rtype = rhs.dataset_type(); ContentBlock::Name lname = lhs.name(); ContentBlock::Name rname = rhs.name(); if ( ltype != rtype ) { return 3; } if ( lname != rname ) { return 4; } bool check_ids = false; bool check_evts = false; if ( lhs.has_events() ) { if ( ! rhs.has_events() ) { return 5; } if ( ! lhs.has_explicit_events() ) return 11; if ( ! rhs.has_explicit_events() ) return 12; if ( lhs.event_ids() == rhs.event_ids() ) { check_ids = true; } else if ( lhs.content_ids() == rhs.content_ids() || allow ) { check_evts = true; } else { return 6; } } else { if ( rhs.has_events() ) { return 7; } check_ids = true; } if ( check_ids ) { for ( ContentIdList::const_iterator irco=rhs.content_ids().begin(); irco!=rhs.content_ids().end(); ++irco ) { for ( ContentIdList::const_iterator ilco=lhs.content_ids().begin(); ilco!=lhs.content_ids().end(); ++ilco ) { if ( *ilco == *irco ) return m_error = 8; } m_cids.insert(*irco); } return 0; } if ( check_evts ) { EventIdList::size_type count = m_eids.merge(rhs.event_ids()); if ( count ) { m_event_count = count; // Also merge content if inconsistent. if ( lhs.content_ids() != rhs.content_ids() ) { assert( allow ); for ( ContentIdList::const_iterator irco=rhs.content_ids().begin(); irco!=rhs.content_ids().end(); ++irco ) { m_cids.insert(*irco); } } return 0; } } return m_error = 9; } //********************************************************************** // Free functions. //********************************************************************** // Output stream. ostream& operator<<(ostream& lhs, const ContentBlock& rhs) { return rhs.ostr(lhs, ""); } //********************************************************************** // Equality. bool dset::operator==(const ContentBlock& lhs, const ContentBlock& rhs) { if ( lhs.dataset_type() != rhs.dataset_type() ) return false; if ( lhs.name() != rhs.name() ) return false; if ( lhs.content_ids() != rhs.content_ids() ) return false; if ( lhs.has_events() ) { if ( ! rhs.has_events() ) return false; return lhs.event_ids() == rhs.event_ids(); } return ! rhs.has_events(); } //********************************************************************** // Inequality. bool dset::operator!=(const ContentBlock& lhs, const ContentBlock& rhs) { return ! operator==(lhs, rhs); } //**********************************************************************