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 itkFixedArray_h
19 #define itkFixedArray_h
20 
21 #include "itkMacro.h"
22 #include <algorithm>
23 #include <array>
24 
25 namespace itk
26 {
27 
28 /** \class FixedArray
29  *  \brief Simulate a standard C array with copy semantics.
30  *
31  * Simulates a standard C array, except that copy semantics are used instead
32  * of reference semantics.  Also, arrays of different sizes cannot be
33  * assigned to one another, and size information is known for function
34  * returns.
35  *
36  * \tparam TValue Element type stored at each location in the array.
37  * \tparam VLength    = Length of the array.
38  *
39  * The length of the array is fixed at compile time. If you wish to
40  * specify the length of the array at run-time, use the class itk::Array.
41  * If you wish to change to change the length of the array at run-time,
42  * you're best off using std::vector<>.
43  *
44  * \ingroup DataRepresentation
45  * \ingroup ITKCommon
46  *
47  * \wiki
48  * \wikiexample{Utilities/FixedArray,C-style array}
49  * \endwiki
50  */
51 template< typename TValue, unsigned int VLength = 3 >
52 class ITK_TEMPLATE_EXPORT FixedArray
53 {
54 public:
55   /** Length constant */
56   static constexpr unsigned int Length = VLength;
57 
58   /** Dimension constant */
59   static constexpr unsigned int Dimension = VLength;
60 
61   /** The element type stored at each location in the FixedArray. */
62   using ValueType = TValue;
63 
64   /** A type representing the C-array version of this FixedArray. */
65   typedef ValueType CArray[VLength];
66 
67   /** An iterator through the array. */
68   using Iterator = ValueType *;
69 
70   /** A const iterator through the array. */
71   using ConstIterator = const ValueType *;
72 
73   class ConstReverseIterator;
74 
75   /** \class ReverseIterator
76    * \brief A reverse iterator through an array.
77    * \ingroup ITKCommon
78    */
79   class ReverseIterator
80   {
81   public:
ReverseIterator(Iterator i)82     explicit ReverseIterator(Iterator i):m_Iterator(i) {}
83     ReverseIterator operator++()        { return ReverseIterator( --m_Iterator ); }
84     ReverseIterator operator++(int)     { return ReverseIterator( m_Iterator-- ); }
85     ReverseIterator operator--()        { return ReverseIterator( ++m_Iterator ); }
86     ReverseIterator operator--(int)     { return ReverseIterator( m_Iterator++ ); }
87     Iterator operator->() const { return ( m_Iterator - 1 ); }
88     ValueType & operator*() const { return *( m_Iterator - 1 ); }
89     bool operator!=(const ReverseIterator & rit) const { return m_Iterator != rit.m_Iterator; }
90     bool operator==(const ReverseIterator & rit) const { return m_Iterator == rit.m_Iterator; }
91 
92   private:
93     Iterator m_Iterator;
94     friend class ConstReverseIterator;
95   };
96 
97   /** \class ConstReverseIterator
98    * \brief A const reverse iterator through an array.
99    * \ingroup ITKCommon
100    */
101   class ConstReverseIterator
102   {
103   public:
ConstReverseIterator(ConstIterator i)104     explicit ConstReverseIterator(ConstIterator i):m_Iterator(i) {}
ConstReverseIterator(const ReverseIterator & rit)105     ConstReverseIterator(const ReverseIterator & rit) { m_Iterator = rit.m_Iterator; }
106     ConstReverseIterator operator++()         { return ConstReverseIterator( --m_Iterator ); }
107     ConstReverseIterator operator++(int)      { return ConstReverseIterator( m_Iterator-- ); }
108     ConstReverseIterator operator--()         { return ConstReverseIterator( ++m_Iterator ); }
109     ConstReverseIterator operator--(int)      { return ConstReverseIterator( m_Iterator++ ); }
110     ConstIterator operator->() const { return ( m_Iterator - 1 ); }
111     const ValueType & operator*() const { return *( m_Iterator - 1 ); }
112     bool operator!=(const ConstReverseIterator & rit) const { return m_Iterator != rit.m_Iterator; }
113     bool operator==(const ConstReverseIterator & rit) const { return m_Iterator == rit.m_Iterator; }
114 
115   private:
116     ConstIterator m_Iterator;
117   };
118 
119   /** A pointer to the ValueType. */
120   using pointer = ValueType *;
121 
122   /** A const pointer to the ValueType. */
123   using const_pointer = const ValueType *;
124 
125   /** A reference to the ValueType. */
126   using reference = ValueType &;
127 
128   /** A const reference to the ValueType. */
129   using const_reference = const ValueType &;
130 
131   /** The return type of the non-const overloads of begin() and end(). */
132   using iterator = ValueType *;
133 
134   /** The return type of cbegin() and cend(), and the const overloads of begin() and end(). */
135   using const_iterator = const ValueType *;
136 
137   using reverse_iterator = std::reverse_iterator<iterator>;
138 
139   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
140 
141   using SizeType = unsigned int;
142 
143 public:
144   /** Constructors */
145   FixedArray() = default;
146   FixedArray(const FixedArray &) = default;
147   FixedArray & operator=(const FixedArray & ) = default;
148   FixedArray(FixedArray &&) = default;
149   FixedArray & operator=(FixedArray && ) = default;
150   ~FixedArray() = default;
151 
152   /** Conversion constructors */
153   FixedArray(const ValueType r[VLength]);
154   FixedArray(const ValueType & );
155 
156   /** Explicit constructor for std::array. */
FixedArray(const std::array<ValueType,VLength> & stdArray)157   explicit FixedArray(const std::array<ValueType, VLength>& stdArray)
158   {
159     std::copy_n(stdArray.cbegin(), VLength, m_InternalArray);
160   }
161 
162   /** Constructor to initialize a fixed array from another of any data type */
163   template< typename TFixedArrayValueType >
FixedArray(const FixedArray<TFixedArrayValueType,VLength> & r)164   FixedArray(const FixedArray< TFixedArrayValueType, VLength > & r)
165   {
166     auto input = r.cbegin();
167 
168     for (auto& element : m_InternalArray)
169     {
170       element = static_cast< TValue >( *input++ );
171     }
172   }
173 
174   template< typename TScalarValue >
FixedArray(const TScalarValue * r)175   FixedArray(const TScalarValue *r)
176   {
177     std::copy_n(r, VLength, m_InternalArray);
178   }
179 
180   /** Operator= defined for a variety of types. */
181   template< typename TFixedArrayValueType >
182   FixedArray & operator=(const FixedArray< TFixedArrayValueType, VLength > & r)
183   {
184     auto input = r.cbegin();
185 
186     for (auto& element : m_InternalArray)
187     {
188       element = static_cast< TValue >( *input++ );
189     }
190     return *this;
191   }
192 
193   FixedArray & operator=(const ValueType r[VLength]);
194 
195   /** Operators == and != are used to compare whether two arrays are equal.
196    * Note that arrays are equal when the number of components (size) is the
197    * same, and each component value is equal. */
198   bool operator==(const FixedArray & r) const;
199 
200   bool operator!=(const FixedArray & r) const
201   { return !operator==(r); }
202 
203   /** Allow the FixedArray to be indexed normally.  No bounds checking is done.
204    * The separate versions are a work-around for an integer conversion bug in
205    * Visual C++. */
206   reference operator[](short index)                { return m_InternalArray[index]; }
207   const_reference operator[](short index) const { return m_InternalArray[index]; }
208   reference operator[](unsigned short index)       { return m_InternalArray[index]; }
209   const_reference operator[](unsigned short index) const { return m_InternalArray[index]; }
210   reference operator[](int index)                  { return m_InternalArray[index]; }
211   const_reference operator[](int index) const { return m_InternalArray[index]; }
212 // false positive warnings with GCC
213 #if defined( __GNUC__ )
214 #if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 9 ) || ( __GNUC__ >= 7 )
215 #pragma GCC diagnostic push
216 #pragma GCC diagnostic ignored "-Warray-bounds"
217 #endif
218 #endif
219   reference operator[](unsigned int index)         { return m_InternalArray[index]; }
220   const_reference operator[](unsigned int index) const { return m_InternalArray[index]; }
221 #if defined( __GNUC__ )
222 #if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 9 ) || ( __GNUC__ >= 7 )
223 #pragma GCC diagnostic pop
224 #endif
225 #endif
226   reference operator[](long index)                 { return m_InternalArray[index]; }
227   const_reference operator[](long index) const { return m_InternalArray[index]; }
228   reference operator[](unsigned long index)        { return m_InternalArray[index]; }
229   const_reference operator[](unsigned long index) const { return m_InternalArray[index]; }
230   reference operator[](long long index)                 { return m_InternalArray[index]; }
231   const_reference operator[](long long index) const { return m_InternalArray[index]; }
232   reference operator[](unsigned long long index)        { return m_InternalArray[index]; }
233   const_reference operator[](unsigned long long index) const { return m_InternalArray[index]; }
234 
235   /** Set/Get element methods are more convenient in wrapping languages */
SetElement(unsigned int index,const_reference value)236   void SetElement(unsigned int index, const_reference value)
237   { m_InternalArray[index] = value; }
GetElement(unsigned int index)238   const_reference GetElement(unsigned int index) const { return m_InternalArray[index]; }
239 
240   /** Return a pointer to the data. */
GetDataPointer()241   ValueType * GetDataPointer()
242   {
243     return m_InternalArray;
244   }
245 
GetDataPointer()246   const ValueType * GetDataPointer() const
247   {
248     return m_InternalArray;
249   }
250 
251   /** Get various iterators to the array. */
252   Iterator      Begin();
253 
254   ConstIterator Begin() const;
255 
256   Iterator      End();
257 
258   ConstIterator End() const;
259 
260   itkLegacyMacro(ReverseIterator      rBegin());
261 
262   itkLegacyMacro(ConstReverseIterator rBegin() const);
263 
264   itkLegacyMacro(ReverseIterator      rEnd());
265 
266   itkLegacyMacro(ConstReverseIterator rEnd() const);
267 
cbegin()268   const_iterator cbegin() const noexcept
269   {
270     return m_InternalArray;
271   }
272 
begin()273   iterator begin() noexcept
274   {
275     return m_InternalArray;
276   }
277 
begin()278   const_iterator begin() const noexcept
279   {
280     return this->cbegin();
281   }
282 
cend()283   const_iterator cend() const noexcept
284   {
285     return m_InternalArray + VLength;
286   }
287 
end()288   iterator end() noexcept
289   {
290     return m_InternalArray + VLength;
291   }
292 
end()293   const_iterator end() const noexcept
294   {
295     return this->cend();
296   }
297 
rbegin()298   reverse_iterator rbegin()
299   {
300     return reverse_iterator{ this->end() };
301   }
302 
crbegin()303   const_reverse_iterator crbegin() const
304   {
305     return const_reverse_iterator{ this->cend() };
306   }
307 
rbegin()308   const_reverse_iterator rbegin() const
309   {
310     return this->crbegin();
311   }
312 
rend()313   reverse_iterator rend()
314   {
315     return reverse_iterator{ this->begin() };
316   }
317 
crend()318   const_reverse_iterator crend() const
319   {
320     return const_reverse_iterator{ this->cbegin() };
321   }
322 
rend()323   const_reverse_iterator rend() const
324   {
325     return this->crend();
326   }
327 
328   SizeType      Size() const;
329 
330   void Fill(const ValueType &);
331 
swap(FixedArray & other)332   void swap(FixedArray &other)
333     {
334       std::swap(m_InternalArray, other.m_InternalArray);
335     }
336 
337 private:
338   /** Internal C array representation. */
339   CArray m_InternalArray;
340 
341 public:
342 
343   static FixedArray Filled(const ValueType &);
344 };
345 
346 template< typename TValue, unsigned int VLength >
347 std::ostream & operator<<(std::ostream & os, const FixedArray< TValue, VLength > & arr);
348 
349 
350 template< typename TValue, unsigned int VLength >
swap(FixedArray<TValue,VLength> & a,FixedArray<TValue,VLength> & b)351 inline void swap( FixedArray<TValue, VLength> &a, FixedArray<TValue, VLength> &b )
352 {
353   a.swap(b);
354 }
355 
356 } // namespace itk
357 
358 #ifndef ITK_MANUAL_INSTANTIATION
359 #include "itkFixedArray.hxx"
360 #endif
361 
362 #include "itkNumericTraitsFixedArrayPixel.h"
363 
364 #endif
365