1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
5//
6// This Source Code Form is subject to the terms of the Mozilla
7// Public License v. 2.0. If a copy of the MPL was not distributed
8// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9
10#ifndef EIGEN_EMULATE_ARRAY_H
11#define EIGEN_EMULATE_ARRAY_H
12
13
14
15// The array class is only available starting with cxx11. Emulate our own here
16// if needed. Beware, msvc still doesn't advertise itself as a c++11 compiler!
17// Moreover, CUDA doesn't support the STL containers, so we use our own instead.
18#if (__cplusplus <= 199711L && EIGEN_COMP_MSVC < 1900) || defined(__CUDACC__) || defined(EIGEN_AVOID_STL_ARRAY)
19
20namespace Eigen {
21template <typename T, size_t n> class array {
22 public:
23  EIGEN_DEVICE_FUNC
24  EIGEN_STRONG_INLINE T& operator[] (size_t index) { return values[index]; }
25  EIGEN_DEVICE_FUNC
26  EIGEN_STRONG_INLINE const T& operator[] (size_t index) const { return values[index]; }
27
28  EIGEN_DEVICE_FUNC
29  EIGEN_STRONG_INLINE T& front() { return values[0]; }
30  EIGEN_DEVICE_FUNC
31  EIGEN_STRONG_INLINE const T& front() const { return values[0]; }
32
33  EIGEN_DEVICE_FUNC
34  EIGEN_STRONG_INLINE T& back() { return values[n-1]; }
35  EIGEN_DEVICE_FUNC
36  EIGEN_STRONG_INLINE const T& back() const { return values[n-1]; }
37
38  EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
39  static std::size_t size() { return n; }
40
41  T values[n];
42
43  EIGEN_DEVICE_FUNC
44  EIGEN_STRONG_INLINE array() { }
45  EIGEN_DEVICE_FUNC
46  EIGEN_STRONG_INLINE array(const T& v) {
47    EIGEN_STATIC_ASSERT(n==1, YOU_MADE_A_PROGRAMMING_MISTAKE)
48    values[0] = v;
49  }
50  EIGEN_DEVICE_FUNC
51  EIGEN_STRONG_INLINE array(const T& v1, const T& v2) {
52    EIGEN_STATIC_ASSERT(n==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
53    values[0] = v1;
54    values[1] = v2;
55  }
56  EIGEN_DEVICE_FUNC
57  EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3) {
58    EIGEN_STATIC_ASSERT(n==3, YOU_MADE_A_PROGRAMMING_MISTAKE)
59    values[0] = v1;
60    values[1] = v2;
61    values[2] = v3;
62  }
63  EIGEN_DEVICE_FUNC
64  EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3,
65                            const T& v4) {
66    EIGEN_STATIC_ASSERT(n==4, YOU_MADE_A_PROGRAMMING_MISTAKE)
67    values[0] = v1;
68    values[1] = v2;
69    values[2] = v3;
70    values[3] = v4;
71  }
72  EIGEN_DEVICE_FUNC
73  EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3, const T& v4,
74                            const T& v5) {
75    EIGEN_STATIC_ASSERT(n==5, YOU_MADE_A_PROGRAMMING_MISTAKE)
76    values[0] = v1;
77    values[1] = v2;
78    values[2] = v3;
79    values[3] = v4;
80    values[4] = v5;
81  }
82  EIGEN_DEVICE_FUNC
83  EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3, const T& v4,
84                            const T& v5, const T& v6) {
85    EIGEN_STATIC_ASSERT(n==6, YOU_MADE_A_PROGRAMMING_MISTAKE)
86    values[0] = v1;
87    values[1] = v2;
88    values[2] = v3;
89    values[3] = v4;
90    values[4] = v5;
91    values[5] = v6;
92  }
93  EIGEN_DEVICE_FUNC
94  EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3, const T& v4,
95                            const T& v5, const T& v6, const T& v7) {
96    EIGEN_STATIC_ASSERT(n==7, YOU_MADE_A_PROGRAMMING_MISTAKE)
97    values[0] = v1;
98    values[1] = v2;
99    values[2] = v3;
100    values[3] = v4;
101    values[4] = v5;
102    values[5] = v6;
103    values[6] = v7;
104  }
105  EIGEN_DEVICE_FUNC
106  EIGEN_STRONG_INLINE array(
107      const T& v1, const T& v2, const T& v3, const T& v4,
108      const T& v5, const T& v6, const T& v7, const T& v8) {
109    EIGEN_STATIC_ASSERT(n==8, YOU_MADE_A_PROGRAMMING_MISTAKE)
110    values[0] = v1;
111    values[1] = v2;
112    values[2] = v3;
113    values[3] = v4;
114    values[4] = v5;
115    values[5] = v6;
116    values[6] = v7;
117    values[7] = v8;
118  }
119
120#if EIGEN_HAS_VARIADIC_TEMPLATES
121  EIGEN_DEVICE_FUNC
122  EIGEN_STRONG_INLINE array(std::initializer_list<T> l) {
123    eigen_assert(l.size() == n);
124    internal::smart_copy(l.begin(), l.end(), values);
125  }
126#endif
127};
128
129
130// Specialize array for zero size
131template <typename T> class array<T, 0> {
132 public:
133  EIGEN_DEVICE_FUNC
134  EIGEN_STRONG_INLINE T& operator[] (size_t) {
135    eigen_assert(false && "Can't index a zero size array");
136    return dummy;
137  }
138  EIGEN_DEVICE_FUNC
139  EIGEN_STRONG_INLINE const T& operator[] (size_t) const {
140    eigen_assert(false && "Can't index a zero size array");
141    return dummy;
142  }
143
144  EIGEN_DEVICE_FUNC
145  EIGEN_STRONG_INLINE T& front() {
146    eigen_assert(false && "Can't index a zero size array");
147    return dummy;
148  }
149  EIGEN_DEVICE_FUNC
150  EIGEN_STRONG_INLINE const T& front() const {
151    eigen_assert(false && "Can't index a zero size array");
152    return dummy;
153  }
154  EIGEN_DEVICE_FUNC
155  EIGEN_STRONG_INLINE T& back() {
156    eigen_assert(false && "Can't index a zero size array");
157    return dummy;
158  }
159  EIGEN_DEVICE_FUNC
160  EIGEN_STRONG_INLINE const T& back() const {
161    eigen_assert(false && "Can't index a zero size array");
162    return dummy;
163  }
164
165  static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE std::size_t size() { return 0; }
166
167  EIGEN_DEVICE_FUNC
168  EIGEN_STRONG_INLINE array() : dummy() { }
169
170#if EIGEN_HAS_VARIADIC_TEMPLATES
171  EIGEN_DEVICE_FUNC array(std::initializer_list<T> l) : dummy() {
172    eigen_assert(l.size() == 0);
173  }
174#endif
175
176 private:
177  T dummy;
178};
179
180// Comparison operator
181// Todo: implement !=, <, <=, >,  and >=
182template<class T, std::size_t N>
183EIGEN_DEVICE_FUNC bool operator==(const array<T,N>& lhs, const array<T,N>& rhs) {
184  for (std::size_t i = 0; i < N; ++i) {
185    if (lhs[i] != rhs[i]) {
186      return false;
187    }
188  }
189  return true;
190}
191
192
193namespace internal {
194template<std::size_t I, class T, std::size_t N>
195EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& array_get(array<T,N>& a) {
196  return a[I];
197}
198template<std::size_t I, class T, std::size_t N>
199EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& array_get(const array<T,N>& a) {
200  return a[I];
201}
202
203template <typename T> struct array_size;
204template<class T, std::size_t N> struct array_size<array<T,N> > {
205  static const size_t value = N;
206};
207template <typename T> struct array_size;
208template<class T, std::size_t N> struct array_size<array<T,N>& > {
209  static const size_t value = N;
210};
211template <typename T> struct array_size;
212template<class T, std::size_t N> struct array_size<const array<T,N> > {
213  static const size_t value = N;
214};
215template <typename T> struct array_size;
216template<class T, std::size_t N> struct array_size<const array<T,N>& > {
217  static const size_t value = N;
218};
219
220}  // end namespace internal
221}  // end namespace Eigen
222
223#else
224
225// The compiler supports c++11, and we're not targetting cuda: use std::array as Eigen::array
226#include <array>
227namespace Eigen {
228
229template <typename T, std::size_t N> using array = std::array<T, N>;
230
231namespace internal {
232/* std::get is only constexpr in C++14, not yet in C++11
233 *     - libstdc++ from version 4.7 onwards has it nevertheless,
234 *                                          so use that
235 *     - libstdc++ older versions: use _M_instance directly
236 *     - libc++ all versions so far: use __elems_ directly
237 *     - all other libs: use std::get to be portable, but
238 *                       this may not be constexpr
239 */
240#if defined(__GLIBCXX__) && __GLIBCXX__ < 20120322
241#define STD_GET_ARR_HACK             a._M_instance[I]
242#elif defined(_LIBCPP_VERSION)
243#define STD_GET_ARR_HACK             a.__elems_[I]
244#else
245#define STD_GET_ARR_HACK             std::template get<I, T, N>(a)
246#endif
247
248template<std::size_t I, class T, std::size_t N> constexpr inline T&       array_get(std::array<T,N>&       a) { return (T&)       STD_GET_ARR_HACK; }
249template<std::size_t I, class T, std::size_t N> constexpr inline T&&      array_get(std::array<T,N>&&      a) { return (T&&)      STD_GET_ARR_HACK; }
250template<std::size_t I, class T, std::size_t N> constexpr inline T const& array_get(std::array<T,N> const& a) { return (T const&) STD_GET_ARR_HACK; }
251
252#undef STD_GET_ARR_HACK
253
254template <typename T> struct array_size;
255template<class T, std::size_t N> struct array_size<const std::array<T,N> > {
256  static const size_t value = N;
257};
258template <typename T> struct array_size;
259template<class T, std::size_t N> struct array_size<std::array<T,N> > {
260  static const size_t value = N;
261};
262}  // end namespace internal
263}  // end namespace Eigen
264
265#endif
266
267#endif  // EIGEN_EMULATE_ARRAY_H
268