From 327de92e76d7f228fbca6aaf6c8e679f6638d6ce Mon Sep 17 00:00:00 2001 From: Bradley Lowekamp Date: Mon, 5 Mar 2018 11:44:08 -0500 Subject: [PATCH 1/5] ENH: Add move support to the MetaDataDictionary object --- .../Common/include/itkMetaDataDictionary.h | 17 ++++++++++++- Modules/Core/Common/include/itkObject.h | 1 + .../Core/Common/src/itkMetaDataDictionary.cxx | 24 +++++++++++++++---- Modules/Core/Common/src/itkObject.cxx | 16 ++++++++++++- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/Modules/Core/Common/include/itkMetaDataDictionary.h b/Modules/Core/Common/include/itkMetaDataDictionary.h index b909ca7fd5a..7a1d471bb1d 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 { @@ -57,8 +58,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 +115,20 @@ class ITKCommon_EXPORT MetaDataDictionary /** remove all MetaObjects from dictionary */ void Clear(); + void Swap( MetaDataDictionary &other ) + { + using std::swap; + swap(m_Dictionary, other.m_Dictionary); + } + private: - MetaDataDictionaryMapType *m_Dictionary; + std::unique_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..335d3865ffc 100644 --- a/Modules/Core/Common/src/itkMetaDataDictionary.cxx +++ b/Modules/Core/Common/src/itkMetaDataDictionary.cxx @@ -21,24 +21,28 @@ namespace itk { MetaDataDictionary ::MetaDataDictionary() + : m_Dictionary( new MetaDataDictionaryMapType() ) { - m_Dictionary = new MetaDataDictionaryMapType; } MetaDataDictionary ::~MetaDataDictionary() { - delete m_Dictionary; - m_Dictionary = nullptr; } MetaDataDictionary ::MetaDataDictionary(const MetaDataDictionary & old) + : m_Dictionary( new MetaDataDictionaryMapType(*old.m_Dictionary)) { - m_Dictionary = new MetaDataDictionaryMapType; - *m_Dictionary = *( old.m_Dictionary ); } +MetaDataDictionary +::MetaDataDictionary( MetaDataDictionary && rr) + : m_Dictionary( new MetaDataDictionaryMapType(std::move(*rr.m_Dictionary))) +{ +} + + MetaDataDictionary & MetaDataDictionary ::operator=(const MetaDataDictionary & old) { @@ -49,6 +53,16 @@ ::operator=(const MetaDataDictionary & old) return *this; } +MetaDataDictionary & MetaDataDictionary +::operator=(MetaDataDictionary && rr) +{ + if(this != &rr) + { + *m_Dictionary = std::move(*( rr.m_Dictionary )); + } + return *this; +} + void MetaDataDictionary ::Print(std::ostream & os) const 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 From 9b073eb9fd7f102faff1fb026e9d683083dad07e Mon Sep 17 00:00:00 2001 From: Bradley Lowekamp Date: Mon, 5 Mar 2018 15:43:17 -0500 Subject: [PATCH 2/5] PERF: Implement copy on write for MetaDataDictionary The default behavior when reading a Image in ITK is to create 3 copies of the MetaDataDictionary for the ImageIO, ImageFileReader, and Image object. These are usually not modified, not shared and created by a deep copy. The internal std::map is shared via a std::share_ptr with a reference count. If the dictionaries are modified a deep copy is performed. --- .../Common/include/itkMetaDataDictionary.h | 23 ++++--- .../Core/Common/src/itkMetaDataDictionary.cxx | 62 ++++++++++++------- 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/Modules/Core/Common/include/itkMetaDataDictionary.h b/Modules/Core/Common/include/itkMetaDataDictionary.h index 7a1d471bb1d..6071609e17a 100644 --- a/Modules/Core/Common/include/itkMetaDataDictionary.h +++ b/Modules/Core/Common/include/itkMetaDataDictionary.h @@ -36,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 @@ -58,10 +67,10 @@ class ITKCommon_EXPORT MetaDataDictionary MetaDataDictionary(); // Copy Constructor MetaDataDictionary(const MetaDataDictionary &); - MetaDataDictionary(MetaDataDictionary &&); + MetaDataDictionary(MetaDataDictionary &&) = default; // operator = MetaDataDictionary & operator=(const MetaDataDictionary &); - MetaDataDictionary & operator=(MetaDataDictionary &&); + MetaDataDictionary & operator=(MetaDataDictionary &&) = default; // Destructor virtual ~MetaDataDictionary(); @@ -115,14 +124,12 @@ class ITKCommon_EXPORT MetaDataDictionary /** remove all MetaObjects from dictionary */ void Clear(); - void Swap( MetaDataDictionary &other ) - { - using std::swap; - swap(m_Dictionary, other.m_Dictionary); - } + void Swap( MetaDataDictionary &other ); private: - std::unique_ptr m_Dictionary; + bool MakeUnique(void); + + std::shared_ptr m_Dictionary; }; inline void swap(MetaDataDictionary &a, MetaDataDictionary &b ) diff --git a/Modules/Core/Common/src/itkMetaDataDictionary.cxx b/Modules/Core/Common/src/itkMetaDataDictionary.cxx index 335d3865ffc..a10646a2bab 100644 --- a/Modules/Core/Common/src/itkMetaDataDictionary.cxx +++ b/Modules/Core/Common/src/itkMetaDataDictionary.cxx @@ -21,7 +21,7 @@ namespace itk { MetaDataDictionary ::MetaDataDictionary() - : m_Dictionary( new MetaDataDictionaryMapType() ) + : m_Dictionary( std::make_shared() ) { } @@ -32,33 +32,18 @@ MetaDataDictionary MetaDataDictionary ::MetaDataDictionary(const MetaDataDictionary & old) - : m_Dictionary( new MetaDataDictionaryMapType(*old.m_Dictionary)) + // perform shallow copy, so m_Dictionary is shared + : m_Dictionary( old.m_Dictionary ) { } -MetaDataDictionary -::MetaDataDictionary( MetaDataDictionary && rr) - : m_Dictionary( new MetaDataDictionaryMapType(std::move(*rr.m_Dictionary))) -{ -} - - MetaDataDictionary & MetaDataDictionary ::operator=(const MetaDataDictionary & old) { if(this != &old) { - *m_Dictionary = *( old.m_Dictionary ); - } - return *this; -} - -MetaDataDictionary & MetaDataDictionary -::operator=(MetaDataDictionary && rr) -{ - if(this != &rr) - { - *m_Dictionary = std::move(*( rr.m_Dictionary )); + // perform shallow copy, so m_Dictionary is shared + m_Dictionary = old.m_Dictionary; } return *this; } @@ -67,6 +52,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 ) @@ -74,12 +60,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]; } @@ -110,6 +98,7 @@ void MetaDataDictionary ::Set(const std::string & key, MetaDataObjectBase * object) { + MakeUnique(); (*m_Dictionary)[key] = object; } @@ -140,6 +129,7 @@ MetaDataDictionary::Iterator MetaDataDictionary ::Begin() { + MakeUnique(); return m_Dictionary->begin(); } @@ -154,6 +144,7 @@ MetaDataDictionary::Iterator MetaDataDictionary ::End() { + MakeUnique(); return m_Dictionary->end(); } @@ -168,6 +159,7 @@ MetaDataDictionary::Iterator MetaDataDictionary ::Find(const std::string & key) { + MakeUnique(); return m_Dictionary->find(key); } @@ -182,7 +174,30 @@ void MetaDataDictionary ::Clear() { - this->m_Dictionary->clear(); + // Construct a new one instead of enforcing uniqueness then clearing + this->m_Dictionary = std::make_shared(); +} + +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 @@ -194,6 +209,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; } From 2b72bcf13bddd4b5067caacd8f39ba2f62d0fd0c Mon Sep 17 00:00:00 2001 From: Bradley Lowekamp Date: Wed, 30 Jan 2019 10:52:24 -0500 Subject: [PATCH 3/5] ENH: adding MetaDataDictionary GTests Cover basic usage of the interface along with checking that a copy-on-write occurs at the proper time. --- Modules/Core/Common/test/CMakeLists.txt | 1 + .../test/itkMetaDataDictionaryGTest.cxx | 259 ++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 Modules/Core/Common/test/itkMetaDataDictionaryGTest.cxx diff --git a/Modules/Core/Common/test/CMakeLists.txt b/Modules/Core/Common/test/CMakeLists.txt index e55cd7fe245..684c5c1ab8e 100644 --- a/Modules/Core/Common/test/CMakeLists.txt +++ b/Modules/Core/Common/test/CMakeLists.txt @@ -634,5 +634,6 @@ set(ITKCommonGTests itkShapedImageNeighborhoodRangeGTest.cxx itkSmartPointerGTest.cxx itkCommonTypeTraitsGTest.cxx + itkMetaDataDictionaryGTest.cxx ) CreateGoogleTestDriver(ITKCommon "${ITKCommon-Test_LIBRARIES}" "${ITKCommonGTests}") diff --git a/Modules/Core/Common/test/itkMetaDataDictionaryGTest.cxx b/Modules/Core/Common/test/itkMetaDataDictionaryGTest.cxx new file mode 100644 index 00000000000..2974c087d26 --- /dev/null +++ b/Modules/Core/Common/test/itkMetaDataDictionaryGTest.cxx @@ -0,0 +1,259 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#include "itkGTest.h" + +#include "itkMetaDataDictionary.h" +#include "itkMetaDataObject.h" + +#include + +namespace +{ + +itk::MetaDataDictionary createMetaDataDictionary( void ) +{ + itk::MetaDataDictionary metaDataDictionary; + + itk::EncapsulateMetaData( metaDataDictionary, "one", static_cast(1)); + itk::EncapsulateMetaData( metaDataDictionary, "two", static_cast(2)); + + using ObjectType = itk::LightObject; + using PointerType = typename ObjectType::Pointer; + PointerType obj = ObjectType::New(); + itk::EncapsulateMetaData( metaDataDictionary, "object", obj); + + return metaDataDictionary; +} + +template +itk::MetaDataObjectBase::Pointer createMetaDataObject(const T &invalue) +{ + typename itk::MetaDataObject< T >::Pointer temp = itk::MetaDataObject< T >::New(); + temp->SetMetaDataObjectValue(invalue); + return temp; +} +} + +TEST(MetaDataDictionary, Basic) +{ + // This test exercises and checks the non-constant interface + itk::MetaDataDictionary dic = createMetaDataDictionary(); + + EXPECT_TRUE(dic.HasKey("one")); + EXPECT_TRUE(dic.HasKey("two")); + EXPECT_TRUE(dic.HasKey("object")); + + EXPECT_FALSE(dic.HasKey("three")); + EXPECT_FALSE(dic.HasKey("")); + EXPECT_FALSE(dic.HasKey("ONE")); + EXPECT_FALSE(dic.HasKey("SomethingElseThatDoesNotExist")); + + EXPECT_EQ(dic.GetKeys().size(), 3u); + + + EXPECT_NE(dic.Get("one"), nullptr); + EXPECT_NE(dic.Get("two"), nullptr); + EXPECT_NE(dic.Get("object"), nullptr); + EXPECT_THROW(dic.Get("three"), itk::ExceptionObject); + EXPECT_THROW(dic.Get(""), itk::ExceptionObject); + EXPECT_THROW(dic.Get("ONE"), itk::ExceptionObject); + + EXPECT_EQ( dic.GetKeys().size(), 3u); + + EXPECT_EQ( std::distance(dic.Begin(), dic.End()), 3u); + + + auto iter = dic.Find("object"); + + EXPECT_NE(iter, dic.End()); + EXPECT_EQ(iter->first, "object"); + + iter = dic.Find("nothing"); + EXPECT_EQ(iter, dic.End()); + + EXPECT_FALSE(dic.Erase("One")); + EXPECT_EQ(std::distance(dic.Begin(), dic.End()), 3u); + EXPECT_EQ(dic.GetKeys().size(), 3u); + EXPECT_TRUE(dic.HasKey("one") ); + + + EXPECT_TRUE(dic.Erase("two")); + EXPECT_EQ(std::distance(dic.Begin(), dic.End()), 2u); + EXPECT_EQ(dic.GetKeys().size(), 2u); + EXPECT_FALSE(dic.HasKey("two")); + + dic.Clear(); + EXPECT_EQ(std::distance(dic.Begin(), dic.End()), 0u); + EXPECT_EQ(dic.GetKeys().size(), 0u); + EXPECT_FALSE(dic.HasKey("one")); + EXPECT_FALSE(dic.HasKey("two")); + EXPECT_FALSE(dic.HasKey("object")); + + // move assignment + dic = createMetaDataDictionary(); + + EXPECT_TRUE(dic.HasKey("one")); + EXPECT_TRUE(dic.HasKey("two")); + EXPECT_TRUE(dic.HasKey("object")); + EXPECT_EQ(dic.GetKeys().size(), 3u); + + + EXPECT_EQ(dic["nothing"], nullptr); + EXPECT_EQ(dic.GetKeys().size(), 4u); + EXPECT_EQ(std::distance(dic.Begin(), dic.End()), 4u); + EXPECT_TRUE(dic.HasKey("nothing")); + + +} + +TEST(MetaDataDictionary, ConstBasic) +{ + // This test exercises and checks the constant interface + const itk::MetaDataDictionary cdic = createMetaDataDictionary(); + + EXPECT_TRUE(cdic.HasKey("one")); + EXPECT_TRUE(cdic.HasKey("two")); + EXPECT_TRUE(cdic.HasKey("object")); + + EXPECT_FALSE(cdic.HasKey("three")); + EXPECT_FALSE(cdic.HasKey("")); + EXPECT_FALSE(cdic.HasKey("ONE")); + EXPECT_FALSE(cdic.HasKey("SomethingElseThatDoesNotExist")); + + EXPECT_EQ( cdic.GetKeys().size(), 3u); + + EXPECT_NE(cdic.Get("one"), nullptr); + EXPECT_NE(cdic.Get("two"), nullptr); + EXPECT_NE(cdic.Get("object"), nullptr); + EXPECT_THROW(cdic.Get("three"), itk::ExceptionObject); + EXPECT_THROW(cdic.Get(""), itk::ExceptionObject); + EXPECT_THROW(cdic.Get("ONE"), itk::ExceptionObject); + + EXPECT_EQ(cdic.GetKeys().size(), 3u); + + EXPECT_EQ(std::distance(cdic.Begin(), cdic.End()), 3u); + + + auto iter = cdic.Find("object"); + + EXPECT_NE(iter, cdic.End()); + EXPECT_EQ(iter->first, "object"); + + iter = cdic.Find("nothing"); + EXPECT_EQ(iter, cdic.End()); + + EXPECT_EQ(cdic["nothing"], nullptr); + EXPECT_EQ(cdic.GetKeys().size(), 3u); + EXPECT_EQ(std::distance(cdic.Begin(), cdic.End()), 3u); + + + float f = -99; + itk::ExposeMetaData(cdic,"one",f); + EXPECT_EQ(f, 1.0); + itk::ExposeMetaData(cdic,"two",f); + EXPECT_EQ(f, 2.0); + + itk::LightObject::Pointer objPtr; + itk::ExposeMetaData(cdic, "object", objPtr); + EXPECT_FALSE(objPtr.IsNull()); +} + + +TEST(MetaDataDictionary, CopyOnWrite) +{ + + { + itk::MetaDataDictionary dic = createMetaDataDictionary(); + const itk::MetaDataDictionary dic_copy = dic; + + // The use_count is not exposed in the interface, but it is in the + // print method. + std::cout << "The use_count for the std::map in the dictionary should be 2." << std::endl; + dic.Print(std::cout); + + dic["one"] = createMetaDataObject(11.0f); + + float f = -99; + itk::ExposeMetaData(dic,"one",f); + EXPECT_EQ(f, 11.0f); + itk::ExposeMetaData(dic_copy,"one",f); + EXPECT_EQ(f, 1.0f); + + } + + { + itk::MetaDataDictionary dic = createMetaDataDictionary(); + const itk::MetaDataDictionary dic_copy = dic; + + dic.Set("two",createMetaDataObject(22.0f)); + + float f = -99; + itk::ExposeMetaData(dic,"two",f); + EXPECT_EQ(f, 22.0f); + itk::ExposeMetaData(dic_copy,"two",f); + EXPECT_EQ(f, 2.0f); + + } + + { + itk::MetaDataDictionary dic = createMetaDataDictionary(); + const itk::MetaDataDictionary dic_copy = dic; + + dic.Set("three",createMetaDataObject(3.0f)); + + float f = -99; + itk::ExposeMetaData(dic,"three",f); + EXPECT_EQ(f, 3.0f); + EXPECT_FALSE(dic_copy.HasKey("three")); + } + + { + itk::MetaDataDictionary dic = createMetaDataDictionary(); + const itk::MetaDataDictionary dic_copy = dic; + + dic.Erase("two"); + + EXPECT_FALSE(dic.HasKey("two")); + EXPECT_TRUE(dic_copy.HasKey("two")); + } + + { + itk::MetaDataDictionary dic = createMetaDataDictionary(); + const itk::MetaDataDictionary dic_copy = dic; + + dic.Clear(); + + EXPECT_FALSE(dic.HasKey("one")); + EXPECT_FALSE(dic.HasKey("two")); + EXPECT_FALSE(dic.HasKey("object")); + EXPECT_EQ(dic.GetKeys().size(), 0u); + + EXPECT_TRUE(dic_copy.HasKey("one")); + EXPECT_TRUE(dic_copy.HasKey("two")); + EXPECT_TRUE(dic_copy.HasKey("object")); + EXPECT_EQ(dic_copy.GetKeys().size(), 3u); + + float f = -99; + itk::ExposeMetaData(dic_copy,"one",f); + EXPECT_EQ(f, 1.0f); + + } + + +} From fb0d42b46831905e4f7f0a9562c1e076e5b21433 Mon Sep 17 00:00:00 2001 From: Bradley Lowekamp Date: Wed, 30 Jan 2019 11:50:12 -0500 Subject: [PATCH 4/5] BUG: Do not modify MetaDataDictionary with operator[] const The constant implementation of MetaDataDictionary::operator[] might add an default initialized key if the key did not exist already. --- Modules/Core/Common/include/itkMetaDataDictionary.h | 3 +++ Modules/Core/Common/src/itkMetaDataDictionary.cxx | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Modules/Core/Common/include/itkMetaDataDictionary.h b/Modules/Core/Common/include/itkMetaDataDictionary.h index 6071609e17a..1303a9bd081 100644 --- a/Modules/Core/Common/include/itkMetaDataDictionary.h +++ b/Modules/Core/Common/include/itkMetaDataDictionary.h @@ -86,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; diff --git a/Modules/Core/Common/src/itkMetaDataDictionary.cxx b/Modules/Core/Common/src/itkMetaDataDictionary.cxx index a10646a2bab..ebb108cdb86 100644 --- a/Modules/Core/Common/src/itkMetaDataDictionary.cxx +++ b/Modules/Core/Common/src/itkMetaDataDictionary.cxx @@ -75,9 +75,13 @@ 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); + if (iter == m_Dictionary->end()) + { + return nullptr; + } + const MetaDataObjectBase * constentry = iter->second.GetPointer(); return constentry; } From acd5e0d62f5309dd9f85be21798d446357f16b03 Mon Sep 17 00:00:00 2001 From: Bradley Lowekamp Date: Wed, 30 Jan 2019 11:51:54 -0500 Subject: [PATCH 5/5] ENH: Improve ExposeMetaData efficiency Use Find and the resulting iterator to query existence and get value, instead of two separate searches. --- Modules/Core/Common/include/itkMetaDataObject.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/Core/Common/include/itkMetaDataObject.h b/Modules/Core/Common/include/itkMetaDataObject.h index 16b1763ec43..aad02728843 100644 --- a/Modules/Core/Common/include/itkMetaDataObject.h +++ b/Modules/Core/Common/include/itkMetaDataObject.h @@ -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;