diff --git a/Modules/Core/Common/include/itkNeighborhood.hxx b/Modules/Core/Common/include/itkNeighborhood.hxx index 5f9b70991ee..2f0e730d400 100644 --- a/Modules/Core/Common/include/itkNeighborhood.hxx +++ b/Modules/Core/Common/include/itkNeighborhood.hxx @@ -19,6 +19,7 @@ #define itkNeighborhood_hxx #include "itkNumericTraits.h" +#include "itkPrintHelper.h" namespace itk { @@ -115,22 +116,11 @@ template void Neighborhood::PrintSelf(std::ostream & os, Indent indent) const { + using namespace itk::print_helper; os << indent << "Size: " << static_cast::PrintType>(m_Size) << std::endl; os << indent << "Radius: " << static_cast::PrintType>(m_Radius) << std::endl; - - os << indent << "StrideTable: [ "; - for (DimensionValueType i = 0; i < VDimension; ++i) - { - os << indent.GetNextIndent() << m_StrideTable[i] << ' '; - } - os << ']' << std::endl; - - os << indent << "OffsetTable: [ "; - for (DimensionValueType i = 0; i < m_OffsetTable.size(); ++i) - { - os << indent.GetNextIndent() << m_OffsetTable[i] << ' '; - } - os << ']' << std::endl; + os << indent << "StrideTable: " << m_StrideTable << std::endl; + os << indent << "OffsetTable: " << m_OffsetTable << std::endl; } } // namespace itk diff --git a/Modules/Core/Common/include/itkPrintHelper.h b/Modules/Core/Common/include/itkPrintHelper.h index f4ccdf64bbf..b998583aad5 100644 --- a/Modules/Core/Common/include/itkPrintHelper.h +++ b/Modules/Core/Common/include/itkPrintHelper.h @@ -21,6 +21,8 @@ #include #include +#include +#include // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112467 #if defined(ITK_WRAPPING_PARSER) && defined(__GNUC__) && !defined(__clang__) @@ -41,13 +43,45 @@ std::ostream & operator<<(std::ostream & os, const std::vector & v) { if (v.empty()) + { + return os << "[]"; + } + + os << '['; + std::copy(v.begin(), v.end() - 1, std::ostream_iterator(os, ", ")); + return os << v.back() << ']'; +} + +template +std::ostream & +operator<<(std::ostream & os, const std::list & l) +{ + if (l.empty()) + { + return os << "[]"; + } + + os << '['; + std::copy(l.begin(), std::prev(l.end()), std::ostream_iterator(os, ", ")); + return os << l.back() << ']'; +} + +// Stream insertion operator for C-style arrays, excluding character arrays (strings) +template >> +std::ostream & +operator<<(std::ostream & os, const T (&arr)[VLength]) +{ + if constexpr (VLength == 0) { return os << "()"; } os << '('; - std::copy(v.begin(), v.end() - 1, std::ostream_iterator(os, ", ")); - return os << v.back() << ')'; + for (size_t i = 0; i < VLength - 1; ++i) + { + os << arr[i] << ", "; + } + return os << arr[VLength - 1] << ')'; } } // namespace itk::print_helper diff --git a/Modules/Core/Common/test/CMakeLists.txt b/Modules/Core/Common/test/CMakeLists.txt index 8c29c2c9f88..d89ec1e6e8c 100644 --- a/Modules/Core/Common/test/CMakeLists.txt +++ b/Modules/Core/Common/test/CMakeLists.txt @@ -1895,6 +1895,7 @@ set( itkOptimizerParametersGTest.cxx itkPointGTest.cxx itkPointSetGTest.cxx + itkPrintHelperGTest.cxx itkRGBAPixelGTest.cxx itkRGBPixelGTest.cxx itkShapedImageNeighborhoodRangeGTest.cxx diff --git a/Modules/Core/Common/test/itkPrintHelperGTest.cxx b/Modules/Core/Common/test/itkPrintHelperGTest.cxx new file mode 100644 index 00000000000..8bf29df88e6 --- /dev/null +++ b/Modules/Core/Common/test/itkPrintHelperGTest.cxx @@ -0,0 +1,91 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * 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 + * + * https://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 "itkPrintHelper.h" +#include "itkOffset.h" +#include "gtest/gtest.h" +#include +#include +#include + +TEST(PrintHelper, Vector) +{ + using namespace itk::print_helper; + std::vector v{ 1, 2, 3, 4, 5 }; + std::ostringstream oss; + oss << v; + EXPECT_EQ(oss.str(), "[1, 2, 3, 4, 5]"); +} + +TEST(PrintHelper, EmptyVector) +{ + using namespace itk::print_helper; + std::vector v; + std::ostringstream oss; + oss << v; + EXPECT_EQ(oss.str(), "[]"); +} + +TEST(PrintHelper, List) +{ + using namespace itk::print_helper; + std::list l{ 1, 2, 3, 4, 5 }; + std::ostringstream oss; + oss << l; + EXPECT_EQ(oss.str(), "[1, 2, 3, 4, 5]"); +} + +TEST(PrintHelper, EmptyList) +{ + using namespace itk::print_helper; + std::list l; + std::ostringstream oss; + oss << l; + EXPECT_EQ(oss.str(), "[]"); +} + +TEST(PrintHelper, CStyleArray) +{ + using namespace itk::print_helper; + int arr[5] = { 1, 2, 3, 4, 5 }; + std::ostringstream oss; + oss << arr; + EXPECT_EQ(oss.str(), "(1, 2, 3, 4, 5)"); +} + +TEST(PrintHelper, CStyleArraySingleElement) +{ + using namespace itk::print_helper; + int arr[1] = { 42 }; + std::ostringstream oss; + oss << arr; + EXPECT_EQ(oss.str(), "(42)"); +} + +TEST(PrintHelper, VectorOfOffsets) +{ + using namespace itk::print_helper; + std::vector> v; + itk::Offset<2> o1{ { 1, 2 } }; + itk::Offset<2> o2{ { 3, 4 } }; + v.push_back(o1); + v.push_back(o2); + std::ostringstream oss; + oss << v; + EXPECT_EQ(oss.str(), "[[1, 2], [3, 4]]"); +} diff --git a/Modules/Core/Transform/include/itkScalableAffineTransform.hxx b/Modules/Core/Transform/include/itkScalableAffineTransform.hxx index a32d5ff4d1f..5d3334dee01 100644 --- a/Modules/Core/Transform/include/itkScalableAffineTransform.hxx +++ b/Modules/Core/Transform/include/itkScalableAffineTransform.hxx @@ -20,6 +20,7 @@ #include "itkMath.h" #include "itkNumericTraits.h" +#include "itkPrintHelper.h" #include "vnl/algo/vnl_matrix_inverse.h" namespace itk @@ -77,19 +78,10 @@ template void ScalableAffineTransform::PrintSelf(std::ostream & os, Indent indent) const { + using namespace itk::print_helper; Superclass::PrintSelf(os, indent); - os << indent << "Scale : "; - for (unsigned int i = 0; i < VDimension; ++i) - { - os << m_Scale[i] << ' '; - } - os << std::endl; - os << indent << "MatrixScale : "; - for (unsigned int i = 0; i < VDimension; ++i) - { - os << m_MatrixScale[i] << ' '; - } - os << std::endl; + os << indent << "Scale: " << m_Scale << std::endl; + os << indent << "MatrixScale: " << m_MatrixScale << std::endl; } template diff --git a/Modules/Filtering/ImageFeature/include/itkHoughTransform2DCirclesImageFilter.hxx b/Modules/Filtering/ImageFeature/include/itkHoughTransform2DCirclesImageFilter.hxx index 18dfab97895..007e354d3a7 100644 --- a/Modules/Filtering/ImageFeature/include/itkHoughTransform2DCirclesImageFilter.hxx +++ b/Modules/Filtering/ImageFeature/include/itkHoughTransform2DCirclesImageFilter.hxx @@ -23,6 +23,7 @@ #include "itkGaussianDerivativeImageFunction.h" #include "itkMinimumMaximumImageCalculator.h" #include "itkMath.h" +#include "itkPrintHelper.h" namespace itk { @@ -282,6 +283,7 @@ void HoughTransform2DCirclesImageFilter::PrintSelf(std::ostream & os, Indent indent) const { + using namespace itk::print_helper; Superclass::PrintSelf(os, indent); os << indent << "Threshold: " << m_Threshold << std::endl; @@ -297,15 +299,7 @@ HoughTransform2DCirclesImageFilter::PrintType(m_OldModifiedTime) << std::endl; } diff --git a/Modules/Filtering/ImageFeature/include/itkHoughTransform2DLinesImageFilter.hxx b/Modules/Filtering/ImageFeature/include/itkHoughTransform2DLinesImageFilter.hxx index 20c16ae4101..eb8f0bc5c49 100644 --- a/Modules/Filtering/ImageFeature/include/itkHoughTransform2DLinesImageFilter.hxx +++ b/Modules/Filtering/ImageFeature/include/itkHoughTransform2DLinesImageFilter.hxx @@ -23,6 +23,7 @@ #include "itkMinimumMaximumImageCalculator.h" #include "itkCastImageFilter.h" #include "itkMath.h" +#include "itkPrintHelper.h" namespace itk { @@ -356,6 +357,7 @@ template void HoughTransform2DLinesImageFilter::PrintSelf(std::ostream & os, Indent indent) const { + using namespace itk::print_helper; Superclass::PrintSelf(os, indent); os << indent << "Threshold: " << m_Threshold << std::endl; @@ -365,15 +367,7 @@ HoughTransform2DLinesImageFilter::PrintSelf(s os << indent << "Accumulator blur variance: " << m_Variance << std::endl; itkPrintSelfObjectMacro(SimplifyAccumulator); - os << indent << "LinesList: " << std::endl; - unsigned int i = 0; - auto it = m_LinesList.begin(); - while (it != m_LinesList.end()) - { - os << indent << '[' << i << "]: " << *it << std::endl; - ++it; - ++i; - } + os << indent << "LinesList: " << m_LinesList << std::endl; os << indent << "OldModifiedTime: " << NumericTraits::PrintType(m_OldModifiedTime) << std::endl; }