1 /*========================================================================= 2 * 3 * Copyright Insight Software Consortium 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0.txt 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 *=========================================================================*/ 18 #ifndef itkImageHelper_h 19 #define itkImageHelper_h 20 21 #include "itkMacro.h" // For ITK_TEMPLATE_EXPORT. 22 #include <type_traits> // For true_type, false_type, and integral_constant. 23 24 namespace itk 25 { 26 /** \class ImageHelper 27 * \brief Fast Index/Offset computation 28 * 29 * These helper methods use recursive templates to unroll the loops 30 * of simple calculations. The resulting speed improvement varies from 31 * compiler to compiler. Some gcc compilers with debug turned on 32 * exhibit slight speed increases, but most compilers see 33 * improvement. The ComputeOffset performance improvement is 34 * impressive. For example, the Windows VS7.0 compiler shows almost a 35 * factor of 2 speed improvement with the recursive templates. Usually 36 * recursive templates use partial specialization to terminate 37 * loops. Here we use a technique used by Brad King in the itk Concept 38 * Checking code. 39 * 40 * \note This work is part of the National Alliance for Medical Image 41 * Computing (NAMIC), funded by the National Institutes of Health 42 * through the NIH Roadmap for Medical Research, Grant U54 EB005149. 43 * Information on the National Centers for Biomedical Computing 44 * can be obtained from http://commonfund.nih.gov/bioinformatics. 45 * 46 * \ingroup ITKCommon 47 */ 48 49 // Forward reference because of circular dependencies 50 template< 51 unsigned int NImageDimension 52 > 53 class ITK_TEMPLATE_EXPORT ImageBase; 54 55 template< unsigned int NImageDimension, unsigned int NLoop > 56 class ImageHelper 57 { 58 public: 59 using ImageType = ImageBase< NImageDimension >; 60 using IndexType = typename ImageType::IndexType; 61 using OffsetType = typename ImageType::OffsetType; 62 using OffsetValueType = typename ImageType::OffsetValueType; 63 using IndexValueType = typename ImageType::IndexValueType; 64 65 /** ComputeIndex with recursive templates */ ComputeIndex(const IndexType & bufferedRegionIndex,OffsetValueType offset,const OffsetValueType offsetTable[],IndexType & index)66 inline static void ComputeIndex(const IndexType & bufferedRegionIndex, 67 OffsetValueType offset, 68 const OffsetValueType offsetTable[], 69 IndexType & index) 70 { 71 ImageHelper< NImageDimension, NLoop - 1 >:: 72 ComputeIndexInner( bufferedRegionIndex, 73 offset, 74 offsetTable, 75 index, 76 std::integral_constant<bool, NLoop == 1>{} ); 77 } 78 ComputeIndexInner(const IndexType & bufferedRegionIndex,OffsetValueType & offset,const OffsetValueType offsetTable[],IndexType & index,std::false_type)79 inline static void ComputeIndexInner(const IndexType & bufferedRegionIndex, 80 OffsetValueType & offset, 81 const OffsetValueType offsetTable[], 82 IndexType & index, 83 std::false_type) 84 { 85 index[NLoop] = static_cast< IndexValueType >( offset / offsetTable[NLoop] ); 86 offset -= ( index[NLoop] * offsetTable[NLoop] ); 87 index[NLoop] += bufferedRegionIndex[NLoop]; 88 ImageHelper< NImageDimension, NLoop - 1 >:: 89 ComputeIndexInner( bufferedRegionIndex, 90 offset, 91 offsetTable, 92 index, 93 std::integral_constant<bool, NLoop == 1>{} ); 94 } 95 ComputeIndexInner(const IndexType & bufferedRegionIndex,OffsetValueType & offset,const OffsetValueType[],IndexType & index,std::true_type)96 inline static void ComputeIndexInner(const IndexType & bufferedRegionIndex, 97 OffsetValueType & offset, 98 const OffsetValueType[], 99 IndexType & index, 100 std::true_type) 101 { 102 // Do last 103 index[0] = bufferedRegionIndex[0] + static_cast< IndexValueType >( offset ); 104 } 105 106 // ComputeOffset 107 // ComputeOffset(const IndexType & bufferedRegionIndex,const IndexType & index,const OffsetValueType offsetTable[],OffsetValueType & offset)108 inline static void ComputeOffset(const IndexType & bufferedRegionIndex, 109 const IndexType & index, 110 const OffsetValueType offsetTable[], 111 OffsetValueType & offset) 112 { 113 ImageHelper< NImageDimension, NLoop - 1 >:: 114 ComputeOffsetInner( bufferedRegionIndex, 115 index, 116 offsetTable, 117 offset, 118 std::integral_constant<bool, NLoop == 1>{} ); 119 } 120 ComputeOffsetInner(const IndexType & bufferedRegionIndex,const IndexType & index,const OffsetValueType offsetTable[],OffsetValueType & offset,std::false_type)121 inline static void ComputeOffsetInner(const IndexType & bufferedRegionIndex, 122 const IndexType & index, 123 const OffsetValueType offsetTable[], 124 OffsetValueType & offset, 125 std::false_type) 126 { 127 offset += ( index[NLoop] - bufferedRegionIndex[NLoop] ) * offsetTable[NLoop]; 128 ImageHelper< NImageDimension, NLoop - 1 >:: 129 ComputeOffsetInner( bufferedRegionIndex, 130 index, 131 offsetTable, 132 offset, 133 std::integral_constant<bool, NLoop == 1>{} ); 134 } 135 ComputeOffsetInner(const IndexType & bufferedRegionIndex,const IndexType & index,const OffsetValueType[],OffsetValueType & offset,std::true_type)136 inline static void ComputeOffsetInner(const IndexType & bufferedRegionIndex, 137 const IndexType & index, 138 const OffsetValueType[], 139 OffsetValueType & offset, 140 std::true_type) 141 { 142 // Do last 143 offset += index[0] - bufferedRegionIndex[0]; 144 } 145 }; 146 } // end namespace itk 147 148 #endif 149