diff --git a/Modules/Core/Common/include/itkMetaDataDictionary.h b/Modules/Core/Common/include/itkMetaDataDictionary.h index b909ca7fd5a..1db5b6bd7a5 100644 --- a/Modules/Core/Common/include/itkMetaDataDictionary.h +++ b/Modules/Core/Common/include/itkMetaDataDictionary.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace itk { @@ -35,6 +36,15 @@ namespace itk * classes, is designed to provide a mechanism for storing a collection of * arbitrary data types. The main motivation for such a collection is to * associate arbitrary data elements with itk DataObjects. + * + * The MetaDataDictionary implements shallow copying with copy on + * write behavior. When a copy of this class is created, the new copy + * will be shared with the old copy via C++11 shared pointers. When a + * non-constant operation is done, if the dictionary is not unique to + * this object, then a deep copy is performed. This make is very cheap + * to create multiple copies of the same dictionary if they are never + * modified. + * * \ingroup ITKCommon */ class ITKCommon_EXPORT MetaDataDictionary @@ -57,8 +67,10 @@ class ITKCommon_EXPORT MetaDataDictionary MetaDataDictionary(); // Copy Constructor MetaDataDictionary(const MetaDataDictionary &); + MetaDataDictionary(MetaDataDictionary &&); // operator = MetaDataDictionary & operator=(const MetaDataDictionary &); + MetaDataDictionary & operator=(MetaDataDictionary &&); // Destructor virtual ~MetaDataDictionary(); @@ -112,8 +124,18 @@ class ITKCommon_EXPORT MetaDataDictionary /** remove all MetaObjects from dictionary */ void Clear(); + void Swap( MetaDataDictionary &other ); + private: - MetaDataDictionaryMapType *m_Dictionary; + bool MakeUnique(void); + + std::shared_ptr m_Dictionary; }; + +inline void swap(MetaDataDictionary &a, MetaDataDictionary &b ) +{ + a.Swap(b); +} + } #endif // itkMetaDataDictionary_h diff --git a/Modules/Core/Common/include/itkObject.h b/Modules/Core/Common/include/itkObject.h index 3691c272013..9861fadcd74 100644 --- a/Modules/Core/Common/include/itkObject.h +++ b/Modules/Core/Common/include/itkObject.h @@ -172,6 +172,7 @@ class ITKCommon_EXPORT Object:public LightObject * Set the MetaDataDictionary */ void SetMetaDataDictionary(const MetaDataDictionary & rhs); + void SetMetaDataDictionary( MetaDataDictionary && rrhs); /** * A facility to help application programmers set a diff --git a/Modules/Core/Common/src/itkMetaDataDictionary.cxx b/Modules/Core/Common/src/itkMetaDataDictionary.cxx index 997d61d949a..e5b80ae790c 100644 --- a/Modules/Core/Common/src/itkMetaDataDictionary.cxx +++ b/Modules/Core/Common/src/itkMetaDataDictionary.cxx @@ -21,30 +21,46 @@ namespace itk { MetaDataDictionary ::MetaDataDictionary() + : m_Dictionary( std::make_shared() ) { - m_Dictionary = new MetaDataDictionaryMapType; } MetaDataDictionary ::~MetaDataDictionary() { - delete m_Dictionary; - m_Dictionary = nullptr; } MetaDataDictionary ::MetaDataDictionary(const MetaDataDictionary & old) + // perform shallow copy, so m_Dictionary is shared + : m_Dictionary( old.m_Dictionary ) { - m_Dictionary = new MetaDataDictionaryMapType; - *m_Dictionary = *( old.m_Dictionary ); } +MetaDataDictionary +::MetaDataDictionary( MetaDataDictionary && rr) + : m_Dictionary( std::move(rr.m_Dictionary) ) +{ +} + + MetaDataDictionary & MetaDataDictionary ::operator=(const MetaDataDictionary & old) { if(this != &old) { - *m_Dictionary = *( old.m_Dictionary ); + // perform shallow copy, so m_Dictionary is shared + m_Dictionary = old.m_Dictionary; + } + return *this; +} + +MetaDataDictionary & MetaDataDictionary +::operator=(MetaDataDictionary && rr) +{ + if(this != &rr) + { + m_Dictionary = std::move( rr.m_Dictionary ); } return *this; } @@ -53,6 +69,7 @@ void MetaDataDictionary ::Print(std::ostream & os) const { + os << "Dictionary use_count: " << m_Dictionary.use_count() << std::endl; for ( MetaDataDictionaryMapType::const_iterator it = m_Dictionary->begin(); it != m_Dictionary->end(); ++it ) @@ -60,12 +77,14 @@ ::Print(std::ostream & os) const os << ( *it ).first << " "; ( *it ).second->Print(os); } + } MetaDataObjectBase::Pointer & MetaDataDictionary ::operator[](const std::string & key) { + MakeUnique(); return ( *m_Dictionary )[key]; } @@ -96,6 +115,7 @@ void MetaDataDictionary ::Set(const std::string & key, MetaDataObjectBase * object) { + MakeUnique(); (*m_Dictionary)[key] = object; } @@ -126,6 +146,7 @@ MetaDataDictionary::Iterator MetaDataDictionary ::Begin() { + MakeUnique(); return m_Dictionary->begin(); } @@ -140,6 +161,7 @@ MetaDataDictionary::Iterator MetaDataDictionary ::End() { + MakeUnique(); return m_Dictionary->end(); } @@ -154,6 +176,7 @@ MetaDataDictionary::Iterator MetaDataDictionary ::Find(const std::string & key) { + MakeUnique(); return m_Dictionary->find(key); } @@ -168,9 +191,32 @@ void MetaDataDictionary ::Clear() { + MakeUnique(); this->m_Dictionary->clear(); } +void +MetaDataDictionary +::Swap( MetaDataDictionary &other ) +{ + using std::swap; + swap(m_Dictionary, other.m_Dictionary); +} + + +bool +MetaDataDictionary +::MakeUnique() +{ + if (m_Dictionary.use_count() > 1) + { + // copy the shared dictionary. + m_Dictionary = std::make_shared(*m_Dictionary); + return true; + } + return false; +} + bool MetaDataDictionary ::Erase( const std::string& key ) @@ -180,6 +226,7 @@ ::Erase( const std::string& key ) if( it != end ) { + MakeUnique(); m_Dictionary->erase( it ); return true; } diff --git a/Modules/Core/Common/src/itkObject.cxx b/Modules/Core/Common/src/itkObject.cxx index c7ccc0a6513..262dafaefb0 100644 --- a/Modules/Core/Common/src/itkObject.cxx +++ b/Modules/Core/Common/src/itkObject.cxx @@ -654,8 +654,22 @@ ::SetMetaDataDictionary(const MetaDataDictionary & rhs) { if ( m_MetaDataDictionary == nullptr ) { - m_MetaDataDictionary = new MetaDataDictionary; + m_MetaDataDictionary = new MetaDataDictionary(rhs); + return; } *m_MetaDataDictionary = rhs; } + +void +Object +::SetMetaDataDictionary( MetaDataDictionary && rrhs) +{ + if ( m_MetaDataDictionary == nullptr ) + { + m_MetaDataDictionary = new MetaDataDictionary(std::move(rrhs)); + return; + } + *m_MetaDataDictionary = std::move(rrhs); +} + } // end namespace itk