diff --git a/Modules/Core/Common/include/itkMetaDataObject.h b/Modules/Core/Common/include/itkMetaDataObject.h index 45fc3236cbd..09dbc3a61ec 100644 --- a/Modules/Core/Common/include/itkMetaDataObject.h +++ b/Modules/Core/Common/include/itkMetaDataObject.h @@ -63,11 +63,6 @@ namespace itk * string "[UNKNOWN PRINT CHARACTERISTICS]" that works for all possible * MetaDataObject types. * - * The application developer may overload the default implementation to provide - * a specialized Print() characteristics to produce results desirable for their application. - * A set of very crude Macros {NATIVE_TYPE_METADATAPRINT, ITK_OBJECT_TYPE_METADATAPRINT_1COMMA, - * ITK_IMAGE_TYPE_METADATAPRINT } are provided to facilitate a very simple implementation, and as an example. - * * \ingroup ITKCommon * */ @@ -123,13 +118,6 @@ class ITK_TEMPLATE_EXPORT MetaDataObject : public MetaDataObjectBase void SetMetaDataObjectValue(const MetaDataObjectType & newValue); - /** - * Defines the default behavior for printing out this element - * \param os An output stream - */ - void - Print(std::ostream & os) const override; - /** Returns (metaDataObject1 == metaDataObject2). */ friend bool operator==(const Self & lhs, const Self & rhs) @@ -144,10 +132,21 @@ class ITK_TEMPLATE_EXPORT MetaDataObject : public MetaDataObjectBase return !(lhs == rhs); } + /** Helper to print contents of a MetaDataObject. */ + void + PrintValue(std::ostream & os) const; + protected: MetaDataObject() = default; ~MetaDataObject() override = default; + /** + * Defines the default behavior for printing out this element + * \param os An output stream + */ + void + PrintSelf(std::ostream & os, Indent indent) const override; + private: /** Assigns the value of `source` to `target`. * \note The trailing return type is there, just to enable SFINAE.*/ @@ -262,53 +261,8 @@ ExposeMetaData(const MetaDataDictionary & Dictionary, const std::string key, T & return true; } -} // end namespace itk -/** - * \def ITK_NATIVE_TYPE_METADATAPRINT( TYPE_NAME ) - * \brief An ugly macro to facilitate creating a simple implementation of - * the MetaDataObject::Print() function for types that - * have operator<< defined. - * \param TYPE_NAME the native type parameter type - */ -#define ITK_NATIVE_TYPE_METADATAPRINT(TYPE_NAME) \ - template <> \ - void itk::MetaDataObject::Print(std::ostream & os) const \ - { \ - os << this->m_MetaDataObjectValue << std::endl; \ - } - -/** - * \def ITK_OBJECT_TYPE_METADATAPRINT_1COMMA( TYPE_NAME_PART1, TYPE_NAME_PART2 ) - * \brief An ugly macro to facilitate creating a simple implementation of - * the MetaDataObject< Type >::Print() function for - * itk::Objects that have 1 comma in their type definition - * \param TYPE_NAME_PART1 - * \param TYPE_NAME_PART2 - */ -#define ITK_OBJECT_TYPE_METADATAPRINT_1COMMA(TYPE_NAME_PART1, TYPE_NAME_PART2) \ - template <> \ - void itk::MetaDataObject::Print(std::ostream & os) const \ - { \ - this->m_MetaDataObjectValue->Print(os); \ - } - -/** - * \def ITK_IMAGE_TYPE_METADATAPRINT( STORAGE_TYPE ) - * An ugly macro to facilitate creating a simple implementation of - * the MetaDataObject::Print() function for - * itk::Image\\::Pointer - * \param STORAGE_TYPE The storage type of the image type to print. - */ -#define ITK_IMAGE_TYPE_METADATAPRINT(STORAGE_TYPE) \ - ITK_OBJECT_TYPE_METADATAPRINT_1COMMA(itk::Image::Pointer) \ - ITK_OBJECT_TYPE_METADATAPRINT_1COMMA(itk::Image::Pointer) \ - ITK_OBJECT_TYPE_METADATAPRINT_1COMMA(itk::Image::Pointer) \ - ITK_OBJECT_TYPE_METADATAPRINT_1COMMA(itk::Image::Pointer) \ - ITK_OBJECT_TYPE_METADATAPRINT_1COMMA(itk::Image::Pointer) \ - ITK_OBJECT_TYPE_METADATAPRINT_1COMMA(itk::Image::Pointer) \ - ITK_OBJECT_TYPE_METADATAPRINT_1COMMA(itk::Image::Pointer) \ - ITK_OBJECT_TYPE_METADATAPRINT_1COMMA(itk::Image::Pointer) +} // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION # include "itkMetaDataObject.hxx" diff --git a/Modules/Core/Common/include/itkMetaDataObject.hxx b/Modules/Core/Common/include/itkMetaDataObject.hxx index 23b92f234db..a257fd42668 100644 --- a/Modules/Core/Common/include/itkMetaDataObject.hxx +++ b/Modules/Core/Common/include/itkMetaDataObject.hxx @@ -28,9 +28,79 @@ #ifndef itkMetaDataObject_hxx #define itkMetaDataObject_hxx +#include +#include + +template +inline constexpr bool is_iterable_print_v = false; +// Specialize for std::vector and std::vector> +template +inline constexpr bool is_iterable_print_v, std::void_t<>> = true; +template +inline constexpr bool is_iterable_print_v>, std::void_t<>> = true; namespace itk { +template +void +printIterable(std::ostream & os, const TIterable & iterable) +{ + if constexpr (is_iterable_print_v) + { + os << "["; + auto begin = std::begin(iterable); + auto end = std::end(iterable); + for (auto it = begin; it != end; ++it) + { + if (it != begin) + { + os << ", "; + } + printIterable(os, *it); + } + os << "]"; + } + else + { + // Handle non-iterable types + os << iterable; + } +} + +template +void +MetaDataObject::PrintValue(std::ostream & os) const +{ + if constexpr (is_iterable_print_v) + { + os << "["; + auto begin = std::begin(m_MetaDataObjectValue); + auto end = std::end(m_MetaDataObjectValue); + for (auto it = begin; it != end; ++it) + { + if (it != begin) + { + os << ", "; + } + printIterable(os, *it); + } + os << "]"; + } + else + { + os << m_MetaDataObjectValue; + } +} + +template +void +MetaDataObject::PrintSelf(std::ostream & os, Indent indent) const +{ + os << indent; + this->PrintValue(os); + os << std::endl; +} + template const char * MetaDataObject::GetMetaDataObjectTypeName() const @@ -59,12 +129,6 @@ MetaDataObject::SetMetaDataObjectValue(const MetaDataObjectT Self::Assign(m_MetaDataObjectValue, newValue); } -template -void -MetaDataObject::Print(std::ostream & os) const -{ - Superclass::Print(os); -} } // end namespace itk diff --git a/Modules/Core/Common/include/itkMetaDataObjectBase.h b/Modules/Core/Common/include/itkMetaDataObjectBase.h index 7ebec314f46..358cb8e664b 100644 --- a/Modules/Core/Common/include/itkMetaDataObjectBase.h +++ b/Modules/Core/Common/include/itkMetaDataObjectBase.h @@ -86,17 +86,16 @@ class ITKCommon_EXPORT MetaDataObjectBase : public LightObject return !(lhs == rhs); } +protected: + MetaDataObjectBase(); + ~MetaDataObjectBase() override; /** * Defines the default behavior for printing out this element * \param os An output stream */ - virtual void - Print(std::ostream & os) const; - -protected: - MetaDataObjectBase(); - ~MetaDataObjectBase() override; + void + PrintSelf(std::ostream & os, Indent indent) const override; private: virtual bool diff --git a/Modules/Core/Common/src/itkMetaDataObjectBase.cxx b/Modules/Core/Common/src/itkMetaDataObjectBase.cxx index ee198d97c4d..a980d3bb513 100644 --- a/Modules/Core/Common/src/itkMetaDataObjectBase.cxx +++ b/Modules/Core/Common/src/itkMetaDataObjectBase.cxx @@ -41,9 +41,9 @@ MetaDataObjectBase::GetMetaDataObjectTypeInfo() const void -MetaDataObjectBase::Print(std::ostream & os) const +MetaDataObjectBase::PrintSelf(std::ostream & os, Indent indent) const { - os << "[UNKNOWN_PRINT_CHARACTERISTICS]" << std::endl; + os << indent << "[UNKNOWN_PRINT_CHARACTERISTICS]" << std::endl; } } // end namespace itk diff --git a/Modules/Core/Common/test/itkMetaDataObjectTest.cxx b/Modules/Core/Common/test/itkMetaDataObjectTest.cxx index 84e75b03c2b..7ed7c753107 100644 --- a/Modules/Core/Common/test/itkMetaDataObjectTest.cxx +++ b/Modules/Core/Common/test/itkMetaDataObjectTest.cxx @@ -44,6 +44,8 @@ testMetaData(const TMetaData & value) std::cout << "The metadata's type name is: " << metaDataObject->GetMetaDataObjectTypeName() << std::endl; std::cout << "The metadata object: " << std::endl; metaDataObject->Print(std::cout); + std::cout << "The metadata value only: " << std::endl; + metaDataObject->PrintValue(std::cout); std::cout << std::endl << std::endl; @@ -68,6 +70,17 @@ itkMetaDataObjectTest(int, char *[]) result += testMetaData(-24); result += testMetaData(-24); result += testMetaData("I T K"); + // Exercise printing of std::vector and std::vector> + // These two types are special cased in itk::MetaDataObject::PrintValue() + auto v3 = std::vector{ 1.0, 2.0, 3.0 }; + result += testMetaData>(v3); + result += testMetaData>>(std::vector>{ v3, v3 }); + // Exercise itk::Array + auto a3 = itk::Array(3, 5.0); + result += testMetaData>(a3); + // Exercise itk::Matrix + auto m3 = itk::Matrix(); + result += testMetaData>(m3); using ImageType = itk::Image; ImageType::Pointer image = nullptr;