Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion Modules/Core/Common/include/itkMetaDataDictionary.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <vector>
#include <map>
#include <string>
#include <memory>

namespace itk
{
Expand All @@ -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
Expand All @@ -57,8 +67,10 @@ class ITKCommon_EXPORT MetaDataDictionary
MetaDataDictionary();
// Copy Constructor
MetaDataDictionary(const MetaDataDictionary &);
MetaDataDictionary(MetaDataDictionary &&) = default;
// operator =
MetaDataDictionary & operator=(const MetaDataDictionary &);
MetaDataDictionary & operator=(MetaDataDictionary &&) = default;

// Destructor
virtual ~MetaDataDictionary();
Expand All @@ -74,6 +86,9 @@ class ITKCommon_EXPORT MetaDataDictionary
// API. The implementation will be in the DLL.
MetaDataObjectBase::Pointer & operator[](const std::string &);

// \brief Get a constant point to a DataObject
//
// If the key does not exist then nullptr is returned.
const MetaDataObjectBase * operator[](const std::string &) const;

const MetaDataObjectBase * Get(const std::string &) const;
Expand Down Expand Up @@ -112,8 +127,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<MetaDataDictionaryMapType> m_Dictionary;
};

inline void swap(MetaDataDictionary &a, MetaDataDictionary &b )
{
a.Swap(b);
}

}
#endif // itkMetaDataDictionary_h
6 changes: 3 additions & 3 deletions Modules/Core/Common/include/itkMetaDataObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,13 @@ inline void EncapsulateMetaData(MetaDataDictionary & Dictionary, const char *key
template< typename T >
inline bool ExposeMetaData(const MetaDataDictionary & Dictionary, const std::string key, T & outval)
{
if ( !Dictionary.HasKey(key) )
auto keyIter = Dictionary.Find(key);
if ( keyIter == Dictionary.End() )
{
return false;
}

const MetaDataObjectBase::ConstPointer baseObjectSmartPointer = Dictionary[key];
auto const * const TempMetaDataObject = dynamic_cast< MetaDataObject< T > const * >( baseObjectSmartPointer.GetPointer() );
auto const * const TempMetaDataObject = dynamic_cast< MetaDataObject< T > const * >( keyIter->second.GetPointer() );
if ( TempMetaDataObject == nullptr )
{
return false;
Expand Down
1 change: 1 addition & 0 deletions Modules/Core/Common/include/itkObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
56 changes: 47 additions & 9 deletions Modules/Core/Common/src/itkMetaDataDictionary.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,29 @@ namespace itk
{
MetaDataDictionary
::MetaDataDictionary()
: m_Dictionary( std::make_shared<MetaDataDictionaryMapType>() )
{
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
::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;
}
Expand All @@ -53,29 +52,36 @@ 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 )
{
os << ( *it ).first << " ";
( *it ).second->Print(os);
}

}

MetaDataObjectBase::Pointer &
MetaDataDictionary
::operator[](const std::string & key)
{
MakeUnique();
return ( *m_Dictionary )[key];
}

const MetaDataObjectBase *
MetaDataDictionary
::operator[](const std::string & key) const
{
MetaDataObjectBase::Pointer entry = ( *m_Dictionary )[key];
const MetaDataObjectBase * constentry = entry.GetPointer();
auto iter = m_Dictionary->find(key);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@N-Dekker I pondered deprecating this method, but instead I have just made it return a nullptr, and not modify the std::map when not does not exist. This const method does not exist in the std container, and the behavior is different than the non-constant method.

if (iter == m_Dictionary->end())
{
return nullptr;
}

const MetaDataObjectBase * constentry = iter->second.GetPointer();
return constentry;
}

Expand All @@ -96,6 +102,7 @@ void
MetaDataDictionary
::Set(const std::string & key, MetaDataObjectBase * object)
{
MakeUnique();
(*m_Dictionary)[key] = object;
}

Expand Down Expand Up @@ -126,6 +133,7 @@ MetaDataDictionary::Iterator
MetaDataDictionary
::Begin()
{
MakeUnique();
return m_Dictionary->begin();
}

Expand All @@ -140,6 +148,7 @@ MetaDataDictionary::Iterator
MetaDataDictionary
::End()
{
MakeUnique();
return m_Dictionary->end();
}

Expand All @@ -154,6 +163,7 @@ MetaDataDictionary::Iterator
MetaDataDictionary
::Find(const std::string & key)
{
MakeUnique();
return m_Dictionary->find(key);
}

Expand All @@ -168,7 +178,30 @@ void
MetaDataDictionary
::Clear()
{
this->m_Dictionary->clear();
// Construct a new one instead of enforcing uniqueness then clearing
this->m_Dictionary = std::make_shared<MetaDataDictionaryMapType>();
}

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<MetaDataDictionaryMapType>(*m_Dictionary);
return true;
}
return false;
}

bool
Expand All @@ -180,6 +213,11 @@ ::Erase( const std::string& key )

if( it != end )
{
if (MakeUnique())
{
// Need to find the correct iterator, in the new copy
it = m_Dictionary->find( key );
}
m_Dictionary->erase( it );
return true;
}
Expand Down
16 changes: 15 additions & 1 deletion Modules/Core/Common/src/itkObject.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions Modules/Core/Common/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -634,5 +634,6 @@ set(ITKCommonGTests
itkShapedImageNeighborhoodRangeGTest.cxx
itkSmartPointerGTest.cxx
itkCommonTypeTraitsGTest.cxx
itkMetaDataDictionaryGTest.cxx
)
CreateGoogleTestDriver(ITKCommon "${ITKCommon-Test_LIBRARIES}" "${ITKCommonGTests}")
Loading