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
12 changes: 5 additions & 7 deletions Modules/Core/Common/include/itkAnnulusOperator.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "itkNeighborhoodOperator.h"
#include "itkVector.h"
#include "itkPrintHelper.h"

namespace itk
{
Expand Down Expand Up @@ -225,13 +226,10 @@ class ITK_TEMPLATE_EXPORT AnnulusOperator : public NeighborhoodOperator<TPixel,
os << indent << "Thickness: " << m_Thickness << std::endl;
os << indent << "Normalize: " << m_Normalize << std::endl;
os << indent << "BrightCenter: " << m_BrightCenter << std::endl;
os << indent << "InteriorValue: " << static_cast<typename NumericTraits<PixelType>::PrintType>(m_InteriorValue)
<< std::endl;
os << indent << "AnnulusValue: " << static_cast<typename NumericTraits<PixelType>::PrintType>(m_AnnulusValue)
<< std::endl;
os << indent << "ExteriorValue: " << static_cast<typename NumericTraits<PixelType>::PrintType>(m_ExteriorValue)
<< std::endl;
os << indent << "Spacing: " << static_cast<typename NumericTraits<SpacingType>::PrintType>(m_Spacing) << std::endl;
print_helper::PrintNumericTrait(os, indent, "InteriorValue", m_InteriorValue);
print_helper::PrintNumericTrait(os, indent, "AnnulusValue", m_AnnulusValue);
print_helper::PrintNumericTrait(os, indent, "ExteriorValue", m_ExteriorValue);
print_helper::PrintNumericTrait(os, indent, "Spacing", m_Spacing);
}

protected:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define itkBinaryThresholdSpatialFunction_hxx


#include "itkPrintHelper.h"
namespace itk
{

Expand All @@ -28,12 +29,8 @@ BinaryThresholdSpatialFunction<TFunction>::PrintSelf(std::ostream & os, Indent i
{
Superclass::PrintSelf(os, indent);

os << indent
<< "LowerThreshold: " << static_cast<typename NumericTraits<FunctionOutputType>::PrintType>(m_LowerThreshold)
<< std::endl;
os << indent
<< "UpperThreshold: " << static_cast<typename NumericTraits<FunctionOutputType>::PrintType>(m_UpperThreshold)
<< std::endl;
print_helper::PrintNumericTrait(os, indent, "LowerThreshold", m_LowerThreshold);
print_helper::PrintNumericTrait(os, indent, "UpperThreshold", m_UpperThreshold);

itkPrintSelfObjectMacro(Function);
}
Expand Down
4 changes: 2 additions & 2 deletions Modules/Core/Common/include/itkImageDuplicator.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define itkImageDuplicator_hxx

#include "itkImageAlgorithm.h"
#include "itkPrintHelper.h"

namespace itk
{
Expand Down Expand Up @@ -64,8 +65,7 @@ ImageDuplicator<TInputImage>::PrintSelf(std::ostream & os, Indent indent) const
itkPrintSelfObjectMacro(InputImage);
itkPrintSelfObjectMacro(DuplicateImage);

os << indent << "InternalImageTime: " << static_cast<NumericTraits<ModifiedTimeType>::PrintType>(m_InternalImageTime)
<< std::endl;
print_helper::PrintNumericTrait(os, indent, "InternalImageTime", m_InternalImageTime);
}
} // end namespace itk

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define itkMinimumMaximumImageCalculator_hxx

#include "itkImageRegionConstIteratorWithIndex.h"
#include "itkPrintHelper.h"

namespace itk
{
Expand Down Expand Up @@ -113,8 +114,8 @@ MinimumMaximumImageCalculator<TInputImage>::PrintSelf(std::ostream & os, Indent
{
Superclass::PrintSelf(os, indent);

os << indent << "Minimum: " << static_cast<typename NumericTraits<PixelType>::PrintType>(m_Minimum) << std::endl;
os << indent << "Maximum: " << static_cast<typename NumericTraits<PixelType>::PrintType>(m_Maximum) << std::endl;
print_helper::PrintNumericTrait(os, indent, "Minimum", m_Minimum);
print_helper::PrintNumericTrait(os, indent, "Maximum", m_Maximum);
os << indent << "Index of Minimum: " << m_IndexOfMinimum << std::endl;
os << indent << "Index of Maximum: " << m_IndexOfMaximum << std::endl;
itkPrintSelfObjectMacro(Image);
Expand Down
4 changes: 2 additions & 2 deletions Modules/Core/Common/include/itkNeighborhood.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ void
Neighborhood<TPixel, VDimension, TContainer>::PrintSelf(std::ostream & os, Indent indent) const
{
using namespace itk::print_helper;
os << indent << "Size: " << static_cast<typename NumericTraits<SizeType>::PrintType>(m_Size) << std::endl;
os << indent << "Radius: " << static_cast<typename NumericTraits<SizeType>::PrintType>(m_Radius) << std::endl;
print_helper::PrintNumericTrait(os, indent, "Size", m_Size);
print_helper::PrintNumericTrait(os, indent, "Radius", m_Radius);
os << indent << "StrideTable: " << m_StrideTable << std::endl;
os << indent << "OffsetTable: " << m_OffsetTable << std::endl;
}
Expand Down
5 changes: 2 additions & 3 deletions Modules/Core/Common/include/itkObjectStore.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,8 @@ ObjectStore<TObjectType>::PrintSelf(std::ostream & os, Indent indent) const
Superclass::PrintSelf(os, indent);

os << indent << "GrowthStrategy: " << m_GrowthStrategy << std::endl;
os << indent << "Size: " << static_cast<NumericTraits<SizeValueType>::PrintType>(m_Size) << std::endl;
os << indent << "LinearGrowthSize: " << static_cast<NumericTraits<SizeValueType>::PrintType>(m_LinearGrowthSize)
<< std::endl;
print_helper::PrintNumericTrait(os, indent, "Size", m_Size);
print_helper::PrintNumericTrait(os, indent, "LinearGrowthSize", m_LinearGrowthSize);
os << indent << "FreeList: " << m_FreeList << std::endl;
}
} // end namespace itk
Expand Down
7 changes: 3 additions & 4 deletions Modules/Core/Common/include/itkPointSetToImageFilter.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "itkBoundingBox.h"
#include "itkNumericTraits.h"
#include "itkMath.h"
#include "itkPrintHelper.h"

namespace itk
{
Expand Down Expand Up @@ -227,10 +228,8 @@ PointSetToImageFilter<TInputPointSet, TOutputImage>::PrintSelf(std::ostream & os
os << indent << "Origin: " << m_Origin << std::endl;
os << indent << "Spacing: " << m_Spacing << std::endl;
os << indent << "Direction: " << m_Direction << std::endl;
os << indent << "Inside Value : " << static_cast<typename NumericTraits<ValueType>::PrintType>(m_InsideValue)
<< std::endl;
os << indent << "Outside Value : " << static_cast<typename NumericTraits<ValueType>::PrintType>(m_OutsideValue)
<< std::endl;
print_helper::PrintNumericTrait(os, indent, "Inside Value ", m_InsideValue);
print_helper::PrintNumericTrait(os, indent, "Outside Value ", m_OutsideValue);
}
} // end namespace itk

Expand Down
58 changes: 58 additions & 0 deletions Modules/Core/Common/include/itkPrintHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#ifndef itkPrintHelper_h
#define itkPrintHelper_h

#include "itkIndent.h"

#include <array>
#include <iostream>
#include <iterator>
Expand All @@ -27,13 +29,27 @@
#include <type_traits>


namespace itk
{
// Forward declaration so itkPrintHelper.h can be safely included from
// itkMacro.h without re-entering itkNumericTraits.h (which itself uses
// macros defined later in itkMacro.h). Every PrintNumericTrait() call
// site needs the full NumericTraits<T> specialization in scope, but those
// sites already #include "itkNumericTraits.h" directly or transitively.
template <typename T>
class NumericTraits;
} // namespace itk

namespace itk::print_helper
{

// Forward declarations so the per-container bodies below see all overloads at
// definition time. Required for nested cases like vector<list<T>>, where the
// recursive `os << *it` is parsed before the list overload would otherwise be
// declared, and ADL on std container types never reaches itk::print_helper.
// PrintNumericTrait further down also dispatches through `os << value` and
// must see these forward declarations to instantiate against std container
// member types at the call site.
template <typename T>
std::ostream &
operator<<(std::ostream & os, const std::vector<T> & v);
Expand All @@ -50,6 +66,48 @@ template <typename T, size_t VLength, typename = std::enable_if_t<!std::is_same_
std::ostream &
operator<<(std::ostream & os, const T (&arr)[VLength]);

/** \brief Print "<name>: <value>\n" indented, matching ITK's PrintSelf style.
*
* Formats and writes a single named member to \a os preceded by \a indent,
* followed by a newline. When \c NumericTraits<T>::PrintType differs from
* \a T (the relevant case being the \c char family, whose \c PrintType is
* \c int, so values render numerically rather than as ASCII characters) the
* value is forwarded through a \c static_cast. When the two types coincide
* (the common case, including all built-in scalars wider than \c char and
* \c std::complex specialisations whose \c PrintType is \c Self) the cast
* step is skipped entirely so the value's own stream insertion overload is
* selected directly.
*
* Equivalent to the boilerplate
* \code
* os << indent << "Name: "
* << static_cast<typename NumericTraits<T>::PrintType>(m_Name)
* << std::endl;
* \endcode
* but with explicit \a os and \a indent parameters and no preprocessor
* macro expansion.
*
* Typical use inside a \c PrintSelf override:
* \code
* print_helper::PrintNumericTrait(os, indent, "Threshold", m_Threshold);
* \endcode
*/
template <typename T>
inline void
PrintNumericTrait(std::ostream & os, const Indent & indent, const char * name, const T & value)
{
os << indent << name << ": ";
if constexpr (std::is_same_v<T, typename NumericTraits<T>::PrintType>)
{
os << value;
}
else
{
os << static_cast<typename NumericTraits<T>::PrintType>(value);
}
os << std::endl;
}

template <typename T>
std::ostream &
operator<<(std::ostream & os, const std::vector<T> & v)
Expand Down
28 changes: 10 additions & 18 deletions Modules/Core/Common/include/itkResourceProbe.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -58,24 +58,16 @@ ResourceProbe<ValueType, MeanType>::Print(std::ostream & os, Indent indent) cons
{
using namespace print_helper;

os << indent << "StartValue: " << static_cast<typename NumericTraits<ValueType>::PrintType>(m_StartValue)
<< std::endl;
os << indent << "TotalValue: " << static_cast<typename NumericTraits<ValueType>::PrintType>(m_TotalValue)
<< std::endl;
os << indent << "MinimumValue: " << static_cast<typename NumericTraits<ValueType>::PrintType>(m_MinimumValue)
<< std::endl;
os << indent << "MaximumValue: " << static_cast<typename NumericTraits<ValueType>::PrintType>(m_MaximumValue)
<< std::endl;
os << indent
<< "StandardDeviation: " << static_cast<typename NumericTraits<ValueType>::PrintType>(m_StandardDeviation)
<< std::endl;
os << indent << "StandardError: " << static_cast<typename NumericTraits<ValueType>::PrintType>(m_StandardError)
<< std::endl;

os << indent << "NumberOfStarts: " << static_cast<NumericTraits<CountType>::PrintType>(m_NumberOfStarts) << std::endl;
os << indent << "NumberOfStops: " << static_cast<NumericTraits<CountType>::PrintType>(m_NumberOfStops) << std::endl;
os << indent << "NumberOfIteration: " << static_cast<NumericTraits<CountType>::PrintType>(m_NumberOfIteration)
<< std::endl;
print_helper::PrintNumericTrait(os, indent, "StartValue", m_StartValue);
print_helper::PrintNumericTrait(os, indent, "TotalValue", m_TotalValue);
print_helper::PrintNumericTrait(os, indent, "MinimumValue", m_MinimumValue);
print_helper::PrintNumericTrait(os, indent, "MaximumValue", m_MaximumValue);
print_helper::PrintNumericTrait(os, indent, "StandardDeviation", m_StandardDeviation);
print_helper::PrintNumericTrait(os, indent, "StandardError", m_StandardError);

print_helper::PrintNumericTrait(os, indent, "NumberOfStarts", m_NumberOfStarts);
print_helper::PrintNumericTrait(os, indent, "NumberOfStops", m_NumberOfStops);
print_helper::PrintNumericTrait(os, indent, "NumberOfIteration", m_NumberOfIteration);

os << indent << "ProbeValueList: " << m_ProbeValueList << std::endl;

Expand Down
53 changes: 53 additions & 0 deletions Modules/Core/Common/test/itkPrintHelperGTest.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "itkOffset.h"
#include "gtest/gtest.h"
#include <array>
#include <complex>
#include <sstream>
#include <vector>
#include <list>
Expand Down Expand Up @@ -130,3 +131,55 @@ TEST(PrintHelper, ArrayOfVector)
oss << a;
EXPECT_EQ(oss.str(), "([1, 2], [3])");
}

TEST(PrintHelper, PrintNumericTraitDouble)
{
std::ostringstream oss;
itk::print_helper::PrintNumericTrait(oss, itk::Indent{}, "Value", 3.5);
EXPECT_EQ(oss.str(), "Value: 3.5\n");
}

TEST(PrintHelper, PrintNumericTraitIntIsIdentityCast)
{
// PrintType<int> == int, so the constexpr branch skips static_cast and
// streams the value directly.
std::ostringstream oss;
itk::print_helper::PrintNumericTrait(oss, itk::Indent{}, "Count", 42);
EXPECT_EQ(oss.str(), "Count: 42\n");
}

TEST(PrintHelper, PrintNumericTraitCharRendersNumerically)
{
// PrintType<unsigned char> == int. Without the cast the value would be
// emitted as the ASCII character; the helper must produce the integer.
std::ostringstream oss;
const unsigned char ch = 65;
itk::print_helper::PrintNumericTrait(oss, itk::Indent{}, "Byte", ch);
EXPECT_EQ(oss.str(), "Byte: 65\n");
}

TEST(PrintHelper, PrintNumericTraitSignedCharRendersNumerically)
{
std::ostringstream oss;
const signed char sc = -7;
itk::print_helper::PrintNumericTrait(oss, itk::Indent{}, "Offset", sc);
EXPECT_EQ(oss.str(), "Offset: -7\n");
}

TEST(PrintHelper, PrintNumericTraitComplexIsIdentityCast)
{
// NumericTraits<std::complex<T>>::PrintType is Self, so PrintNumericTrait
// forwards to the value's own ostream insertion overload unchanged.
std::ostringstream oss;
std::complex<double> z{ 1.0, -2.5 };
itk::print_helper::PrintNumericTrait(oss, itk::Indent{}, "Z", z);
EXPECT_EQ(oss.str(), "Z: (1,-2.5)\n");
}

TEST(PrintHelper, PrintNumericTraitIndentation)
{
std::ostringstream oss;
itk::Indent indent{ 4 };
itk::print_helper::PrintNumericTrait(oss, indent, "Threshold", 0.125);
EXPECT_EQ(oss.str(), " Threshold: 0.125\n");
Comment thread
hjmjohnson marked this conversation as resolved.
}
5 changes: 3 additions & 2 deletions Modules/Core/GPUCommon/include/itkGPUReduction.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define itkGPUReduction_hxx

#include "itkMacro.h"
#include "itkPrintHelper.h"

// #define CPU_VERIFY

Expand Down Expand Up @@ -59,8 +60,8 @@ GPUReduction<TElement>::PrintSelf(std::ostream & os, Indent indent) const
os << indent << "Size: " << m_Size << std::endl;
itkPrintSelfBooleanMacro(SmallBlock);

os << indent << "GPUResult: " << static_cast<typename NumericTraits<TElement>::PrintType>(m_GPUResult) << std::endl;
os << indent << "CPUResult: " << static_cast<typename NumericTraits<TElement>::PrintType>(m_CPUResult) << std::endl;
print_helper::PrintNumericTrait(os, indent, "GPUResult", m_GPUResult);
print_helper::PrintNumericTrait(os, indent, "CPUResult", m_CPUResult);
}

template <typename TElement>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ BSplineInterpolateImageFunction<TImageType, TCoordinate, TCoefficientType>::Prin
Superclass::PrintSelf(os, indent);

os << indent << "Scratch: " << m_Scratch << std::endl;
os << indent
<< "DataLength: " << static_cast<typename NumericTraits<typename TImageType::SizeType>::PrintType>(m_DataLength)
<< std::endl;
print_helper::PrintNumericTrait(os, indent, "DataLength", m_DataLength);
os << indent << "SplineOrder: " << m_SplineOrder << std::endl;

itkPrintSelfObjectMacro(Coefficients);
Expand All @@ -73,8 +71,7 @@ BSplineInterpolateImageFunction<TImageType, TCoordinate, TCoefficientType>::Prin

itkPrintSelfBooleanMacro(UseImageDirection);

os << indent << "NumberOfWorkUnits: " << static_cast<NumericTraits<ThreadIdType>::PrintType>(m_NumberOfWorkUnits)
<< std::endl;
print_helper::PrintNumericTrait(os, indent, "NumberOfWorkUnits", m_NumberOfWorkUnits);

os << indent << "ThreadedEvaluateIndex: ";
if (m_ThreadedEvaluateIndex != nullptr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "itkConstNeighborhoodIterator.h"

#include <cassert>
#include "itkPrintHelper.h"

namespace itk
{
Expand All @@ -32,8 +33,7 @@ NeighborhoodOperatorImageFunction<TInputImage, TOutput>::PrintSelf(std::ostream
{
Superclass::PrintSelf(os, indent);

os << indent << "Operator: " << static_cast<typename NumericTraits<NeighborhoodType>::PrintType>(m_Operator)
<< std::endl;
print_helper::PrintNumericTrait(os, indent, "Operator", m_Operator);
}

template <typename TInputImage, typename TOutput>
Expand Down
Loading
Loading