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 itkIndex_h
19 #define itkIndex_h
20
21 #include "itkOffset.h"
22
23 namespace itk
24 {
25
26 /** \struct Index
27 * \brief Represent a n-dimensional index in a n-dimensional image.
28 *
29 * Index is a templated class to represent a multi-dimensional index,
30 * i.e. (i,j,k,...). Index is templated over the dimension of the index.
31 * ITK assumes the first element of an index is the fastest moving index.
32 *
33 * For efficiency sake, Index does not define a default constructor, a
34 * copy constructor, or an operator=. We rely on the compiler to provide
35 * efficient bitwise copies.
36 *
37 * Index is an "aggregate" class. Its data is public (m_InternalArray)
38 * allowing for fast and convenient instantiations/assignments.
39 *
40 * The following syntax for assigning an aggregate type like this is allowed/suggested:
41 *
42 *
43 * Index<3> var{{ 256, 256, 20 }}; // Also prevent narrowing conversions
44 * Index<3> var = {{ 256, 256, 20 }};
45 *
46 * The doubled braces {{ and }} are required to prevent `gcc -Wall'
47 * (and perhaps other compilers) from complaining about a partly
48 * bracketed initializer.
49 *
50 * As an aggregate type that is intended to provide highest performance
51 * characteristics, this class is not appropriate to inherit from,
52 * so setting this struct as final.
53 *
54 * \ingroup ImageAccess
55 * \ingroup ImageObjects
56 * \ingroup ITKCommon
57 *
58 * \wiki
59 * \wikiexample{SimpleOperations/DistanceBetweenIndices,Distance between two indices}
60 * \wikiexample{Images/Index,An object which holds the index of a pixel}
61 * \endwiki
62 */
63
64 template <unsigned int VDimension = 2>
65 struct ITK_TEMPLATE_EXPORT Index final
66 {
67 public:
68 // Using the `rule of zero` to this aggregate type
69 // C++20 changes the definition of aggregate such that classes with any user-declared ctors are no longer aggregates.
70
71 /** Standard class type aliases. */
72 using Self = Index;
73
74 /** Compatible Index and value type alias */
75 using IndexType = Index<VDimension>;
76 using IndexValueType = ::itk::IndexValueType;
77
78 /** Compatible Size type alias. */
79 using SizeType = Size<VDimension>;
80
81 /** Compatible Offset and Offset value type alias. */
82 using OffsetType = Offset<VDimension>;
83 using OffsetValueType = ::itk::OffsetValueType;
84
85 /** Dimension constant */
86 static constexpr unsigned int Dimension = VDimension;
87
88 /** Get the dimension. */
GetIndexDimensionfinal89 static constexpr unsigned int GetIndexDimension()
90 {
91 return VDimension;
92 }
93
94
95 /** Add a size to an index. */
96 const Self operator+(const SizeType & sz) const
97 {
98 Self result;
99
100 for( unsigned int i = 0; i < VDimension; i++ )
101 {
102 result[i] = m_InternalArray[i] + static_cast<IndexValueType>( sz[i] );
103 }
104 return result;
105 }
106
107 /** Increment index by a size. */
108 const Self & operator+=(const SizeType & sz)
109 {
110 for( unsigned int i = 0; i < VDimension; i++ )
111 {
112 m_InternalArray[i] += static_cast<IndexValueType>( sz[i] );
113 }
114 return *this;
115 }
116
117 /** Subtract a size from an index.
118 */
119 const Self operator-(const SizeType & sz) const
120 {
121 Self result;
122
123 for( unsigned int i = 0; i < VDimension; i++ )
124 {
125 result[i] = m_InternalArray[i] - static_cast<IndexValueType>( sz[i] );
126 }
127 return result;
128 }
129
130 /** Decrement index by a size. */
131 const Self & operator-=(const SizeType & sz)
132 {
133 for( unsigned int i = 0; i < VDimension; i++ )
134 {
135 m_InternalArray[i] -= static_cast<IndexValueType>( sz[i] );
136 }
137 return *this;
138 }
139
140 /** Add an offset to an index. */
141 const Self operator+(const OffsetType & offset) const
142 {
143 Self result;
144
145 for( unsigned int i = 0; i < VDimension; i++ )
146 {
147 result[i] = m_InternalArray[i] + offset[i];
148 }
149 return result;
150 }
151
152 /** Increment index by an offset. */
153 const Self & operator+=(const OffsetType & offset)
154 {
155 for( unsigned int i = 0; i < VDimension; i++ )
156 {
157 m_InternalArray[i] += offset[i];
158 }
159 return *this;
160 }
161
162 /** Decrement index by an offset. */
163 const Self & operator-=(const OffsetType & offset)
164 {
165 for( unsigned int i = 0; i < VDimension; i++ )
166 {
167 m_InternalArray[i] -= offset[i];
168 }
169 return *this;
170 }
171
172 /** Subtract an offset from an index. */
173 const Self operator-(const OffsetType & off) const
174 {
175 Self result;
176
177 for( unsigned int i = 0; i < VDimension; i++ )
178 {
179 result[i] = m_InternalArray[i] - off.m_InternalArray[i];
180 }
181 return result;
182 }
183
184 /** Subtract two indices. */
185 const OffsetType operator-(const Self & vec) const
186 {
187 OffsetType result;
188
189 for( unsigned int i = 0; i < VDimension; i++ )
190 {
191 result[i] = m_InternalArray[i] - vec.m_InternalArray[i];
192 }
193 return result;
194 }
195
196 /**
197 * Multiply an index by a size (elementwise product).
198 */
199 const Self operator*(const SizeType & vec) const
200 {
201 Self result;
202
203 for( unsigned int i = 0; i < VDimension; i++ )
204 {
205 result[i] = m_InternalArray[i] * static_cast<IndexValueType>( vec.m_InternalArray[i] );
206 }
207 return result;
208 }
209
210 /** Get the index. This provides a read only pointer to the index.
211 * \sa SetIndex() */
GetIndexfinal212 const IndexValueType * GetIndex() const
213 {
214 return m_InternalArray;
215 }
216
217 /** Set the index.
218 * Try to prototype this function so that val has to point to a block of
219 * memory that is the appropriate size.
220 * \sa GetIndex() */
SetIndexfinal221 void SetIndex(const IndexValueType val[VDimension])
222 {
223 std::copy(val,
224 val + VDimension,
225 m_InternalArray);
226 }
227
228 /** Sets the value of one of the elements.
229 * This method is mainly intended to facilitate the access to elements
230 * from Tcl and Python where C++ notation is not very convenient.
231 * \warning No bound checking is performed.
232 * \sa SetIndex()
233 * \sa GetElement() */
SetElementfinal234 void SetElement(unsigned long element, IndexValueType val)
235 {
236 m_InternalArray[element] = val;
237 }
238
239 /** Gets the value of one of the elements.
240 * This method is mainly intended to facilitate the access to elements
241 * from Tcl and Python where C++ notation is not very convenient.
242 * \warning No bound checking is performed
243 * \sa GetIndex()
244 * \sa SetElement() */
GetElementfinal245 IndexValueType GetElement(unsigned long element) const
246 {
247 return m_InternalArray[element];
248 }
249
250 /** Set one value for the index in all dimensions. Useful for initializing
251 * an offset to zero. */
Fillfinal252 void Fill(IndexValueType value)
253 {
254 std::fill_n(begin(), size(), value);
255 } // MATCH std::array assign, ITK Fill
256
257 /** Index is an "aggregate" class. Its data is public (m_InternalArray)
258 * allowing for fast and convenient instantiations/assignments.
259 * ( See main class documentation for an example of initialization)
260 */
261 /*
262 * Ask the compiler to align a type to the maximum useful alignment for the target
263 * machine you are compiling for. Whenever you leave out the alignment factor in an
264 * aligned attribute specification, the compiler automatically sets the alignment
265 * for the type to the largest alignment that is ever used for any data type on
266 * the target machine you are compiling for. Doing this can often make copy
267 * operations more efficient, because the compiler can use whatever instructions
268 * copy the biggest chunks of memory when performing copies to or from the variables
269 * that have types that you have aligned this way.
270 */
271 static_assert( VDimension > 0, "Error: Only positive value sized VDimension allowed" );
272 alignas(IndexValueType) IndexValueType m_InternalArray[VDimension];
273
274 /** Copy values from a FixedArray by rounding each one of the components */
275 template <typename TCoordRep>
CopyWithRoundfinal276 inline void CopyWithRound(const FixedArray<TCoordRep, VDimension> & point)
277 {
278 for( unsigned int i = 0; i < VDimension; ++i )
279 {
280 m_InternalArray[i] = Math::Round<IndexValueType>(point[i]);
281 }
282 }
283
284 /** Copy values from a FixedArray by casting each one of the components */
285 template <typename TCoordRep>
CopyWithCastfinal286 inline void CopyWithCast(const FixedArray<TCoordRep, VDimension> & point)
287 {
288 for( unsigned int i = 0; i < VDimension; ++i )
289 {
290 m_InternalArray[i] = static_cast<IndexValueType>( point[i] );
291 }
292 }
293
294 /** Return a basis vector of the form [0, ..., 0, 1, 0, ... 0] where the "1"
295 * is positioned in the location specified by the parameter "dim". Valid
296 * values of "dim" are 0, ..., VDimension-1. */
297 static Self GetBasisIndex(unsigned int dim);
298
299
300 // ======================= Mirror the access pattern behavior of the std::array class
301 /**
302 * Mirror the std::array type aliases and member function
303 * so that the Index class can be treated as a container
304 * class in a way that is similar to the std::array.
305 */
306 using value_type = ::itk::IndexValueType;
307 using reference = value_type &;
308 using const_reference = const value_type &;
309 using iterator = value_type *;
310 using const_iterator = const value_type *;
311 using size_type = unsigned int;
312 using difference_type = std::ptrdiff_t;
313 using reverse_iterator = std::reverse_iterator<iterator>;
314 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
315
316 /**
317 * Mirror behavior of the std::array manipulations
318 * See std::array for documentation on these methods
319 */
assignfinal320 void assign(const value_type & newValue)
321 {
322 std::fill_n(begin(), size(), newValue);
323 }
324
swapfinal325 void swap(Index & other)
326 {
327 std::swap(m_InternalArray, other.m_InternalArray);
328 }
329
beginfinal330 iterator begin()
331 {
332 return iterator(&m_InternalArray[0]);
333 }
334
beginfinal335 const_iterator begin() const
336 {
337 return const_iterator(&m_InternalArray[0]);
338 }
339
endfinal340 iterator end()
341 {
342 return iterator(&m_InternalArray[VDimension]);
343 }
344
endfinal345 const_iterator end() const
346 {
347 return const_iterator(&m_InternalArray[VDimension]);
348 }
349
rbeginfinal350 reverse_iterator rbegin()
351 {
352 return reverse_iterator(end() );
353 }
354
rbeginfinal355 const_reverse_iterator rbegin() const
356 {
357 return const_reverse_iterator(end() );
358 }
359
rendfinal360 reverse_iterator rend()
361 {
362 return reverse_iterator(begin() );
363 }
364
rendfinal365 const_reverse_iterator rend() const
366 {
367 return const_reverse_iterator(begin() );
368 }
369
sizefinal370 constexpr size_type size() const
371 {
372 return VDimension;
373 }
374
max_sizefinal375 constexpr size_type max_size() const
376 {
377 return VDimension;
378 }
379
emptyfinal380 constexpr bool empty() const
381 {
382 return false;
383 }
384
385 reference operator[](size_type pos)
386 {
387 return m_InternalArray[pos];
388 }
389
390 const_reference operator[](size_type pos) const
391 {
392 return m_InternalArray[pos];
393 }
394
atfinal395 reference at(size_type pos)
396 {
397 ExceptionThrowingBoundsCheck(pos); return m_InternalArray[pos];
398 }
399
atfinal400 const_reference at(size_type pos) const
401 {
402 ExceptionThrowingBoundsCheck(pos); return m_InternalArray[pos];
403 }
404
frontfinal405 reference front()
406 {
407 return *begin();
408 }
409
frontfinal410 const_reference front() const
411 {
412 return *begin();
413 }
414
backfinal415 reference back()
416 {
417 return VDimension ? *(end() - 1) : *end();
418 }
419
backfinal420 const_reference back() const
421 {
422 return VDimension ? *(end() - 1) : *end();
423 }
424
datafinal425 IndexValueType * data()
426 {
427 return &m_InternalArray[0];
428 }
429
datafinal430 const IndexValueType * data() const
431 {
432 return &m_InternalArray[0];
433 }
434
435 private:
ExceptionThrowingBoundsCheckfinal436 void ExceptionThrowingBoundsCheck(size_type pos) const
437 {
438 if( pos >= VDimension )
439 {
440 throw std::out_of_range("array::ExceptionThrowingBoundsCheck");
441 }
442 }
443
444 }; //------------ End struct Index
445
446 template <unsigned int VDimension>
447 Index<VDimension>
448 Index<VDimension>
GetBasisIndex(unsigned int dim)449 ::GetBasisIndex(unsigned int dim)
450 {
451 Self ind{{0}};
452
453 ind.m_InternalArray[dim] = 1;
454 return ind;
455 }
456
457 template <unsigned int VDimension>
458 std::ostream & operator<<(std::ostream & os, const Index<VDimension> & obj)
459 {
460 os << "[";
461 for( unsigned int i = 0; i + 1 < VDimension; ++i )
462 {
463 os << obj[i] << ", ";
464 }
465 if( VDimension >= 1 )
466 {
467 os << obj[VDimension - 1];
468 }
469 os << "]";
470 return os;
471 }
472
473 // ======================= Mirror the access pattern behavior of the std::array class
474 // Array comparisons.
475 template <unsigned int VDimension>
476 inline bool
477 operator==(const Index<VDimension> & one, const Index<VDimension> & two)
478 {
479 return std::equal(one.begin(), one.end(), two.begin() );
480 }
481
482 template <unsigned int VDimension>
483 inline bool
484 operator!=(const Index<VDimension> & one, const Index<VDimension> & two)
485 {
486 return !(one == two);
487 }
488
489 template <unsigned int VDimension>
490 inline bool
491 operator<(const Index<VDimension> & one, const Index<VDimension> & two)
492 {
493 return std::lexicographical_compare(one.begin(), one.end(),
494 two.begin(), two.end() );
495 }
496
497 template <unsigned int VDimension>
498 inline bool
499 operator>(const Index<VDimension> & one, const Index<VDimension> & two)
500 {
501 return two < one;
502 }
503
504 template <unsigned int VDimension>
505 inline bool
506 operator<=(const Index<VDimension> & one, const Index<VDimension> & two)
507 {
508 return !(one > two);
509 }
510
511 template <unsigned int VDimension>
512 inline bool
513 operator>=(const Index<VDimension> & one, const Index<VDimension> & two)
514 {
515 return !(one < two);
516 }
517
518 // Specialized algorithms [6.2.2.2].
519 template <unsigned int VDimension>
520 inline void
swap(Index<VDimension> & one,Index<VDimension> & two)521 swap(Index<VDimension> & one, Index<VDimension> & two)
522 {
523 std::swap(one.m_InternalArray, two.m_InternalArray);
524 }
525
526 // static constexpr definition explicitly needed in C++11
527 template< unsigned int VDimension >
528 constexpr unsigned int Index<VDimension>::Dimension;
529 } // end namespace itk
530
531 #endif
532