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