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