// -*- c-basic-offset: 4 -*- /* Rosegarden A sequencer and musical notation editor. This program is Copyright 2000-2008 Guillaume Laurent , Chris Cannam , Richard Bown The moral right of the authors to claim authorship of this work has been asserted. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #include #include #include #include "Event.h" #include "XmlExportable.h" #if (__GNUC__ < 3) #include #define stringstream strstream #else #include #endif namespace Rosegarden { using std::string; using std::ostream; PropertyName Event::EventData::NotationTime = "!notationtime"; PropertyName Event::EventData::NotationDuration = "!notationduration"; Event::EventData::EventData(const std::string &type, timeT absoluteTime, timeT duration, short subOrdering) : m_refCount(1), m_type(type), m_absoluteTime(absoluteTime), m_duration(duration), m_subOrdering(subOrdering), m_properties(0) { // empty } Event::EventData::EventData(const std::string &type, timeT absoluteTime, timeT duration, short subOrdering, const PropertyMap *properties) : m_refCount(1), m_type(type), m_absoluteTime(absoluteTime), m_duration(duration), m_subOrdering(subOrdering), m_properties(properties ? new PropertyMap(*properties) : 0) { // empty } Event::EventData *Event::EventData::unshare() { --m_refCount; EventData *newData = new EventData (m_type, m_absoluteTime, m_duration, m_subOrdering, m_properties); return newData; } Event::EventData::~EventData() { if (m_properties) delete m_properties; } timeT Event::EventData::getNotationTime() const { if (!m_properties) return m_absoluteTime; PropertyMap::const_iterator i = m_properties->find(NotationTime); if (i == m_properties->end()) return m_absoluteTime; else return static_cast *>(i->second)->getData(); } timeT Event::EventData::getNotationDuration() const { if (!m_properties) return m_duration; PropertyMap::const_iterator i = m_properties->find(NotationDuration); if (i == m_properties->end()) return m_duration; else return static_cast *>(i->second)->getData(); } void Event::EventData::setTime(const PropertyName &name, timeT t, timeT deft) { if (!m_properties) m_properties = new PropertyMap(); PropertyMap::iterator i = m_properties->find(name); if (t != deft) { if (i == m_properties->end()) { m_properties->insert(PropertyPair(name, new PropertyStore(t))); } else { static_cast *>(i->second)->setData(t); } } else if (i != m_properties->end()) { delete i->second; m_properties->erase(i); } } PropertyMap * Event::find(const PropertyName &name, PropertyMap::iterator &i) { PropertyMap *map = m_data->m_properties; if (!map || ((i = map->find(name)) == map->end())) { map = m_nonPersistentProperties; if (!map) return 0; i = map->find(name); if (i == map->end()) return 0; } return map; } bool Event::has(const PropertyName &name) const { #ifndef NDEBUG ++m_hasCount; #endif PropertyMap::const_iterator i; const PropertyMap *map = find(name, i); if (map) return true; else return false; } void Event::unset(const PropertyName &name) { #ifndef NDEBUG ++m_unsetCount; #endif unshare(); PropertyMap::iterator i; PropertyMap *map = find(name, i); if (map) { delete i->second; map->erase(i); } } PropertyType Event::getPropertyType(const PropertyName &name) const // throw (NoData) { PropertyMap::const_iterator i; const PropertyMap *map = find(name, i); if (map) { return i->second->getType(); } else { throw NoData(name.getName(), __FILE__, __LINE__); } } string Event::getPropertyTypeAsString(const PropertyName &name) const // throw (NoData) { PropertyMap::const_iterator i; const PropertyMap *map = find(name, i); if (map) { return i->second->getTypeName(); } else { throw NoData(name.getName(), __FILE__, __LINE__); } } string Event::getAsString(const PropertyName &name) const // throw (NoData) { PropertyMap::const_iterator i; const PropertyMap *map = find(name, i); if (map) { return i->second->unparse(); } else { throw NoData(name.getName(), __FILE__, __LINE__); } } // We could derive from XmlExportable and make this a virtual method // overriding XmlExportable's pure virtual. We don't, because this // class has no other virtual methods and for such a core class we // could do without the overhead (given that it wouldn't really gain // us anything anyway). string Event::toXmlString() { return toXmlString(0); } string Event::toXmlString(timeT expectedTime) { std::stringstream out; out << ""; // Save all persistent properties as elements PropertyNames propertyNames(getPersistentPropertyNames()); for (PropertyNames::const_iterator i = propertyNames.begin(); i != propertyNames.end(); ++i) { out << "getName()) << "\" "; string type = getPropertyTypeAsString(*i); for (unsigned int j = 0; j < type.size(); ++j) { type[j] = (isupper(type[j]) ? tolower(type[j]) : type[j]); } out << type << "=\"" << XmlExportable::encode(getAsString(*i)) << "\"/>"; } // Save non-persistent properties (the persistence applies to // copying events, not load/save) as elements // unless they're view-local. View-local properties are // assumed to have "::" in their name somewhere. propertyNames = getNonPersistentPropertyNames(); for (PropertyNames::const_iterator i = propertyNames.begin(); i != propertyNames.end(); ++i) { std::string s(i->getName()); if (s.find("::") != std::string::npos) continue; out << ""; } out << ""; #if (__GNUC__ < 3) out << std::ends; #endif return out.str(); } #ifndef NDEBUG void Event::dump(ostream& out) const { out << "Event type : " << m_data->m_type.c_str() << '\n'; out << "\tAbsolute Time : " << m_data->m_absoluteTime << "\n\tDuration : " << m_data->m_duration << "\n\tSub-ordering : " << m_data->m_subOrdering << "\n\tPersistent properties : \n"; if (m_data->m_properties) { for (PropertyMap::const_iterator i = m_data->m_properties->begin(); i != m_data->m_properties->end(); ++i) { out << "\t\t" << i->first.getName() << " [" << i->first.getValue() << "] \t" << *(i->second) << "\n"; } } if (m_nonPersistentProperties) { out << "\n\tNon-persistent properties : \n"; for (PropertyMap::const_iterator i = m_nonPersistentProperties->begin(); i != m_nonPersistentProperties->end(); ++i) { out << "\t\t" << i->first.getName() << " [" << i->first.getValue() << "] \t" << *(i->second) << '\n'; } } out << "Event storage size : " << getStorageSize() << '\n'; } int Event::m_getCount = 0; int Event::m_setCount = 0; int Event::m_setMaybeCount = 0; int Event::m_hasCount = 0; int Event::m_unsetCount = 0; clock_t Event::m_lastStats = clock(); void Event::dumpStats(ostream& out) { clock_t now = clock(); int ms = (now - m_lastStats) * 1000 / CLOCKS_PER_SEC; out << "\nEvent stats, since start of run or last report (" << ms << "ms ago):" << std::endl; out << "Calls to get<>: " << m_getCount << std::endl; out << "Calls to set<>: " << m_setCount << std::endl; out << "Calls to setMaybe<>: " << m_setMaybeCount << std::endl; out << "Calls to has: " << m_hasCount << std::endl; out << "Calls to unset: " << m_unsetCount << std::endl; m_getCount = m_setCount = m_setMaybeCount = m_hasCount = m_unsetCount = 0; m_lastStats = clock(); } #else void Event::dumpStats(ostream&) { // nothing } #endif Event::PropertyNames Event::getPropertyNames() const { PropertyNames v; if (m_data->m_properties) { for (PropertyMap::const_iterator i = m_data->m_properties->begin(); i != m_data->m_properties->end(); ++i) { v.push_back(i->first); } } if (m_nonPersistentProperties) { for (PropertyMap::const_iterator i = m_nonPersistentProperties->begin(); i != m_nonPersistentProperties->end(); ++i) { v.push_back(i->first); } } return v; } Event::PropertyNames Event::getPersistentPropertyNames() const { PropertyNames v; if (m_data->m_properties) { for (PropertyMap::const_iterator i = m_data->m_properties->begin(); i != m_data->m_properties->end(); ++i) { v.push_back(i->first); } } return v; } Event::PropertyNames Event::getNonPersistentPropertyNames() const { PropertyNames v; if (m_nonPersistentProperties) { for (PropertyMap::const_iterator i = m_nonPersistentProperties->begin(); i != m_nonPersistentProperties->end(); ++i) { v.push_back(i->first); } } return v; } void Event::clearNonPersistentProperties() { if (m_nonPersistentProperties) m_nonPersistentProperties->clear(); } size_t Event::getStorageSize() const { size_t s = sizeof(Event) + sizeof(EventData) + m_data->m_type.size(); if (m_data->m_properties) { for (PropertyMap::const_iterator i = m_data->m_properties->begin(); i != m_data->m_properties->end(); ++i) { s += sizeof(i->first); s += i->second->getStorageSize(); } } if (m_nonPersistentProperties) { for (PropertyMap::const_iterator i = m_nonPersistentProperties->begin(); i != m_nonPersistentProperties->end(); ++i) { s += sizeof(i->first); s += i->second->getStorageSize(); } } return s; } bool operator<(const Event &a, const Event &b) { timeT at = a.getAbsoluteTime(); timeT bt = b.getAbsoluteTime(); if (at != bt) return at < bt; else return a.getSubOrdering() < b.getSubOrdering(); } }