xref: /aosp_15_r20/external/eigen/Eigen/src/Core/StlIterators.h (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2018 Gael Guennebaud <[email protected]>
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_STLITERATORS_H
11 #define EIGEN_STLITERATORS_H
12 
13 namespace Eigen {
14 
15 namespace internal {
16 
17 template<typename IteratorType>
18 struct indexed_based_stl_iterator_traits;
19 
20 template<typename  Derived>
21 class indexed_based_stl_iterator_base
22 {
23 protected:
24   typedef indexed_based_stl_iterator_traits<Derived> traits;
25   typedef typename traits::XprType XprType;
26   typedef indexed_based_stl_iterator_base<typename traits::non_const_iterator> non_const_iterator;
27   typedef indexed_based_stl_iterator_base<typename traits::const_iterator> const_iterator;
28   typedef typename internal::conditional<internal::is_const<XprType>::value,non_const_iterator,const_iterator>::type other_iterator;
29   // NOTE: in C++03 we cannot declare friend classes through typedefs because we need to write friend class:
30   friend class indexed_based_stl_iterator_base<typename traits::const_iterator>;
31   friend class indexed_based_stl_iterator_base<typename traits::non_const_iterator>;
32 public:
33   typedef Index difference_type;
34   typedef std::random_access_iterator_tag iterator_category;
35 
indexed_based_stl_iterator_base()36   indexed_based_stl_iterator_base() EIGEN_NO_THROW : mp_xpr(0), m_index(0) {}
indexed_based_stl_iterator_base(XprType & xpr,Index index)37   indexed_based_stl_iterator_base(XprType& xpr, Index index) EIGEN_NO_THROW : mp_xpr(&xpr), m_index(index) {}
38 
indexed_based_stl_iterator_base(const non_const_iterator & other)39   indexed_based_stl_iterator_base(const non_const_iterator& other) EIGEN_NO_THROW
40     : mp_xpr(other.mp_xpr), m_index(other.m_index)
41   {}
42 
43   indexed_based_stl_iterator_base& operator=(const non_const_iterator& other)
44   {
45     mp_xpr = other.mp_xpr;
46     m_index = other.m_index;
47     return *this;
48   }
49 
50   Derived& operator++() { ++m_index; return derived(); }
51   Derived& operator--() { --m_index; return derived(); }
52 
53   Derived operator++(int) { Derived prev(derived()); operator++(); return prev;}
54   Derived operator--(int) { Derived prev(derived()); operator--(); return prev;}
55 
56   friend Derived operator+(const indexed_based_stl_iterator_base& a, Index b) { Derived ret(a.derived()); ret += b; return ret; }
57   friend Derived operator-(const indexed_based_stl_iterator_base& a, Index b) { Derived ret(a.derived()); ret -= b; return ret; }
58   friend Derived operator+(Index a, const indexed_based_stl_iterator_base& b) { Derived ret(b.derived()); ret += a; return ret; }
59   friend Derived operator-(Index a, const indexed_based_stl_iterator_base& b) { Derived ret(b.derived()); ret -= a; return ret; }
60 
61   Derived& operator+=(Index b) { m_index += b; return derived(); }
62   Derived& operator-=(Index b) { m_index -= b; return derived(); }
63 
64   difference_type operator-(const indexed_based_stl_iterator_base& other) const
65   {
66     eigen_assert(mp_xpr == other.mp_xpr);
67     return m_index - other.m_index;
68   }
69 
70   difference_type operator-(const other_iterator& other) const
71   {
72     eigen_assert(mp_xpr == other.mp_xpr);
73     return m_index - other.m_index;
74   }
75 
76   bool operator==(const indexed_based_stl_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index == other.m_index; }
77   bool operator!=(const indexed_based_stl_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index != other.m_index; }
78   bool operator< (const indexed_based_stl_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index <  other.m_index; }
79   bool operator<=(const indexed_based_stl_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index <= other.m_index; }
80   bool operator> (const indexed_based_stl_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index >  other.m_index; }
81   bool operator>=(const indexed_based_stl_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index >= other.m_index; }
82 
83   bool operator==(const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index == other.m_index; }
84   bool operator!=(const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index != other.m_index; }
85   bool operator< (const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index <  other.m_index; }
86   bool operator<=(const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index <= other.m_index; }
87   bool operator> (const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index >  other.m_index; }
88   bool operator>=(const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index >= other.m_index; }
89 
90 protected:
91 
derived()92   Derived& derived() { return static_cast<Derived&>(*this); }
derived()93   const Derived& derived() const { return static_cast<const Derived&>(*this); }
94 
95   XprType *mp_xpr;
96   Index m_index;
97 };
98 
99 template<typename  Derived>
100 class indexed_based_stl_reverse_iterator_base
101 {
102 protected:
103   typedef indexed_based_stl_iterator_traits<Derived> traits;
104   typedef typename traits::XprType XprType;
105   typedef indexed_based_stl_reverse_iterator_base<typename traits::non_const_iterator> non_const_iterator;
106   typedef indexed_based_stl_reverse_iterator_base<typename traits::const_iterator> const_iterator;
107   typedef typename internal::conditional<internal::is_const<XprType>::value,non_const_iterator,const_iterator>::type other_iterator;
108   // NOTE: in C++03 we cannot declare friend classes through typedefs because we need to write friend class:
109   friend class indexed_based_stl_reverse_iterator_base<typename traits::const_iterator>;
110   friend class indexed_based_stl_reverse_iterator_base<typename traits::non_const_iterator>;
111 public:
112   typedef Index difference_type;
113   typedef std::random_access_iterator_tag iterator_category;
114 
indexed_based_stl_reverse_iterator_base()115   indexed_based_stl_reverse_iterator_base() : mp_xpr(0), m_index(0) {}
indexed_based_stl_reverse_iterator_base(XprType & xpr,Index index)116   indexed_based_stl_reverse_iterator_base(XprType& xpr, Index index) : mp_xpr(&xpr), m_index(index) {}
117 
indexed_based_stl_reverse_iterator_base(const non_const_iterator & other)118   indexed_based_stl_reverse_iterator_base(const non_const_iterator& other)
119     : mp_xpr(other.mp_xpr), m_index(other.m_index)
120   {}
121 
122   indexed_based_stl_reverse_iterator_base& operator=(const non_const_iterator& other)
123   {
124     mp_xpr = other.mp_xpr;
125     m_index = other.m_index;
126     return *this;
127   }
128 
129   Derived& operator++() { --m_index; return derived(); }
130   Derived& operator--() { ++m_index; return derived(); }
131 
132   Derived operator++(int) { Derived prev(derived()); operator++(); return prev;}
133   Derived operator--(int) { Derived prev(derived()); operator--(); return prev;}
134 
135   friend Derived operator+(const indexed_based_stl_reverse_iterator_base& a, Index b) { Derived ret(a.derived()); ret += b; return ret; }
136   friend Derived operator-(const indexed_based_stl_reverse_iterator_base& a, Index b) { Derived ret(a.derived()); ret -= b; return ret; }
137   friend Derived operator+(Index a, const indexed_based_stl_reverse_iterator_base& b) { Derived ret(b.derived()); ret += a; return ret; }
138   friend Derived operator-(Index a, const indexed_based_stl_reverse_iterator_base& b) { Derived ret(b.derived()); ret -= a; return ret; }
139 
140   Derived& operator+=(Index b) { m_index -= b; return derived(); }
141   Derived& operator-=(Index b) { m_index += b; return derived(); }
142 
143   difference_type operator-(const indexed_based_stl_reverse_iterator_base& other) const
144   {
145     eigen_assert(mp_xpr == other.mp_xpr);
146     return other.m_index - m_index;
147   }
148 
149   difference_type operator-(const other_iterator& other) const
150   {
151     eigen_assert(mp_xpr == other.mp_xpr);
152     return other.m_index - m_index;
153   }
154 
155   bool operator==(const indexed_based_stl_reverse_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index == other.m_index; }
156   bool operator!=(const indexed_based_stl_reverse_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index != other.m_index; }
157   bool operator< (const indexed_based_stl_reverse_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index >  other.m_index; }
158   bool operator<=(const indexed_based_stl_reverse_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index >= other.m_index; }
159   bool operator> (const indexed_based_stl_reverse_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index <  other.m_index; }
160   bool operator>=(const indexed_based_stl_reverse_iterator_base& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index <= other.m_index; }
161 
162   bool operator==(const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index == other.m_index; }
163   bool operator!=(const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index != other.m_index; }
164   bool operator< (const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index >  other.m_index; }
165   bool operator<=(const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index >= other.m_index; }
166   bool operator> (const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index <  other.m_index; }
167   bool operator>=(const other_iterator& other) const { eigen_assert(mp_xpr == other.mp_xpr); return m_index <= other.m_index; }
168 
169 protected:
170 
derived()171   Derived& derived() { return static_cast<Derived&>(*this); }
derived()172   const Derived& derived() const { return static_cast<const Derived&>(*this); }
173 
174   XprType *mp_xpr;
175   Index m_index;
176 };
177 
178 template<typename XprType>
179 class pointer_based_stl_iterator
180 {
181   enum { is_lvalue  = internal::is_lvalue<XprType>::value };
182   typedef pointer_based_stl_iterator<typename internal::remove_const<XprType>::type> non_const_iterator;
183   typedef pointer_based_stl_iterator<typename internal::add_const<XprType>::type> const_iterator;
184   typedef typename internal::conditional<internal::is_const<XprType>::value,non_const_iterator,const_iterator>::type other_iterator;
185   // NOTE: in C++03 we cannot declare friend classes through typedefs because we need to write friend class:
186   friend class pointer_based_stl_iterator<typename internal::add_const<XprType>::type>;
187   friend class pointer_based_stl_iterator<typename internal::remove_const<XprType>::type>;
188 public:
189   typedef Index difference_type;
190   typedef typename XprType::Scalar value_type;
191   typedef std::random_access_iterator_tag iterator_category;
192   typedef typename internal::conditional<bool(is_lvalue), value_type*, const value_type*>::type pointer;
193   typedef typename internal::conditional<bool(is_lvalue), value_type&, const value_type&>::type reference;
194 
195 
pointer_based_stl_iterator()196   pointer_based_stl_iterator() EIGEN_NO_THROW : m_ptr(0) {}
pointer_based_stl_iterator(XprType & xpr,Index index)197   pointer_based_stl_iterator(XprType& xpr, Index index) EIGEN_NO_THROW : m_incr(xpr.innerStride())
198   {
199     m_ptr = xpr.data() + index * m_incr.value();
200   }
201 
pointer_based_stl_iterator(const non_const_iterator & other)202   pointer_based_stl_iterator(const non_const_iterator& other) EIGEN_NO_THROW
203     : m_ptr(other.m_ptr), m_incr(other.m_incr)
204   {}
205 
206   pointer_based_stl_iterator& operator=(const non_const_iterator& other) EIGEN_NO_THROW
207   {
208     m_ptr = other.m_ptr;
209     m_incr.setValue(other.m_incr);
210     return *this;
211   }
212 
213   reference operator*()         const { return *m_ptr;   }
214   reference operator[](Index i) const { return *(m_ptr+i*m_incr.value()); }
215   pointer   operator->()        const { return m_ptr;    }
216 
217   pointer_based_stl_iterator& operator++() { m_ptr += m_incr.value(); return *this; }
218   pointer_based_stl_iterator& operator--() { m_ptr -= m_incr.value(); return *this; }
219 
220   pointer_based_stl_iterator operator++(int) { pointer_based_stl_iterator prev(*this); operator++(); return prev;}
221   pointer_based_stl_iterator operator--(int) { pointer_based_stl_iterator prev(*this); operator--(); return prev;}
222 
223   friend pointer_based_stl_iterator operator+(const pointer_based_stl_iterator& a, Index b) { pointer_based_stl_iterator ret(a); ret += b; return ret; }
224   friend pointer_based_stl_iterator operator-(const pointer_based_stl_iterator& a, Index b) { pointer_based_stl_iterator ret(a); ret -= b; return ret; }
225   friend pointer_based_stl_iterator operator+(Index a, const pointer_based_stl_iterator& b) { pointer_based_stl_iterator ret(b); ret += a; return ret; }
226   friend pointer_based_stl_iterator operator-(Index a, const pointer_based_stl_iterator& b) { pointer_based_stl_iterator ret(b); ret -= a; return ret; }
227 
228   pointer_based_stl_iterator& operator+=(Index b) { m_ptr += b*m_incr.value(); return *this; }
229   pointer_based_stl_iterator& operator-=(Index b) { m_ptr -= b*m_incr.value(); return *this; }
230 
231   difference_type operator-(const pointer_based_stl_iterator& other) const {
232     return (m_ptr - other.m_ptr)/m_incr.value();
233   }
234 
235   difference_type operator-(const other_iterator& other) const {
236     return (m_ptr - other.m_ptr)/m_incr.value();
237   }
238 
239   bool operator==(const pointer_based_stl_iterator& other) const { return m_ptr == other.m_ptr; }
240   bool operator!=(const pointer_based_stl_iterator& other) const { return m_ptr != other.m_ptr; }
241   bool operator< (const pointer_based_stl_iterator& other) const { return m_ptr <  other.m_ptr; }
242   bool operator<=(const pointer_based_stl_iterator& other) const { return m_ptr <= other.m_ptr; }
243   bool operator> (const pointer_based_stl_iterator& other) const { return m_ptr >  other.m_ptr; }
244   bool operator>=(const pointer_based_stl_iterator& other) const { return m_ptr >= other.m_ptr; }
245 
246   bool operator==(const other_iterator& other) const { return m_ptr == other.m_ptr; }
247   bool operator!=(const other_iterator& other) const { return m_ptr != other.m_ptr; }
248   bool operator< (const other_iterator& other) const { return m_ptr <  other.m_ptr; }
249   bool operator<=(const other_iterator& other) const { return m_ptr <= other.m_ptr; }
250   bool operator> (const other_iterator& other) const { return m_ptr >  other.m_ptr; }
251   bool operator>=(const other_iterator& other) const { return m_ptr >= other.m_ptr; }
252 
253 protected:
254 
255   pointer m_ptr;
256   internal::variable_if_dynamic<Index, XprType::InnerStrideAtCompileTime> m_incr;
257 };
258 
259 template<typename _XprType>
260 struct indexed_based_stl_iterator_traits<generic_randaccess_stl_iterator<_XprType> >
261 {
262   typedef _XprType XprType;
263   typedef generic_randaccess_stl_iterator<typename internal::remove_const<XprType>::type> non_const_iterator;
264   typedef generic_randaccess_stl_iterator<typename internal::add_const<XprType>::type> const_iterator;
265 };
266 
267 template<typename XprType>
268 class generic_randaccess_stl_iterator : public indexed_based_stl_iterator_base<generic_randaccess_stl_iterator<XprType> >
269 {
270 public:
271   typedef typename XprType::Scalar value_type;
272 
273 protected:
274 
275   enum {
276     has_direct_access = (internal::traits<XprType>::Flags & DirectAccessBit) ? 1 : 0,
277     is_lvalue  = internal::is_lvalue<XprType>::value
278   };
279 
280   typedef indexed_based_stl_iterator_base<generic_randaccess_stl_iterator> Base;
281   using Base::m_index;
282   using Base::mp_xpr;
283 
284   // TODO currently const Transpose/Reshape expressions never returns const references,
285   // so lets return by value too.
286   //typedef typename internal::conditional<bool(has_direct_access), const value_type&, const value_type>::type read_only_ref_t;
287   typedef const value_type read_only_ref_t;
288 
289 public:
290 
291   typedef typename internal::conditional<bool(is_lvalue), value_type *, const value_type *>::type pointer;
292   typedef typename internal::conditional<bool(is_lvalue), value_type&, read_only_ref_t>::type reference;
293 
294   generic_randaccess_stl_iterator() : Base() {}
295   generic_randaccess_stl_iterator(XprType& xpr, Index index) : Base(xpr,index) {}
296   generic_randaccess_stl_iterator(const typename Base::non_const_iterator& other) : Base(other) {}
297   using Base::operator=;
298 
299   reference operator*()         const { return   (*mp_xpr)(m_index);   }
300   reference operator[](Index i) const { return   (*mp_xpr)(m_index+i); }
301   pointer   operator->()        const { return &((*mp_xpr)(m_index)); }
302 };
303 
304 template<typename _XprType, DirectionType Direction>
305 struct indexed_based_stl_iterator_traits<subvector_stl_iterator<_XprType,Direction> >
306 {
307   typedef _XprType XprType;
308   typedef subvector_stl_iterator<typename internal::remove_const<XprType>::type, Direction> non_const_iterator;
309   typedef subvector_stl_iterator<typename internal::add_const<XprType>::type, Direction> const_iterator;
310 };
311 
312 template<typename XprType, DirectionType Direction>
313 class subvector_stl_iterator : public indexed_based_stl_iterator_base<subvector_stl_iterator<XprType,Direction> >
314 {
315 protected:
316 
317   enum { is_lvalue  = internal::is_lvalue<XprType>::value };
318 
319   typedef indexed_based_stl_iterator_base<subvector_stl_iterator> Base;
320   using Base::m_index;
321   using Base::mp_xpr;
322 
323   typedef typename internal::conditional<Direction==Vertical,typename XprType::ColXpr,typename XprType::RowXpr>::type SubVectorType;
324   typedef typename internal::conditional<Direction==Vertical,typename XprType::ConstColXpr,typename XprType::ConstRowXpr>::type ConstSubVectorType;
325 
326 
327 public:
328   typedef typename internal::conditional<bool(is_lvalue), SubVectorType, ConstSubVectorType>::type reference;
329   typedef typename reference::PlainObject value_type;
330 
331 private:
332   class subvector_stl_iterator_ptr
333   {
334   public:
335       subvector_stl_iterator_ptr(const reference &subvector) : m_subvector(subvector) {}
336       reference* operator->() { return &m_subvector; }
337   private:
338       reference m_subvector;
339   };
340 public:
341 
342   typedef subvector_stl_iterator_ptr pointer;
343 
344   subvector_stl_iterator() : Base() {}
345   subvector_stl_iterator(XprType& xpr, Index index) : Base(xpr,index) {}
346 
347   reference operator*()         const { return (*mp_xpr).template subVector<Direction>(m_index); }
348   reference operator[](Index i) const { return (*mp_xpr).template subVector<Direction>(m_index+i); }
349   pointer   operator->()        const { return (*mp_xpr).template subVector<Direction>(m_index); }
350 };
351 
352 template<typename _XprType, DirectionType Direction>
353 struct indexed_based_stl_iterator_traits<subvector_stl_reverse_iterator<_XprType,Direction> >
354 {
355   typedef _XprType XprType;
356   typedef subvector_stl_reverse_iterator<typename internal::remove_const<XprType>::type, Direction> non_const_iterator;
357   typedef subvector_stl_reverse_iterator<typename internal::add_const<XprType>::type, Direction> const_iterator;
358 };
359 
360 template<typename XprType, DirectionType Direction>
361 class subvector_stl_reverse_iterator : public indexed_based_stl_reverse_iterator_base<subvector_stl_reverse_iterator<XprType,Direction> >
362 {
363 protected:
364 
365   enum { is_lvalue  = internal::is_lvalue<XprType>::value };
366 
367   typedef indexed_based_stl_reverse_iterator_base<subvector_stl_reverse_iterator> Base;
368   using Base::m_index;
369   using Base::mp_xpr;
370 
371   typedef typename internal::conditional<Direction==Vertical,typename XprType::ColXpr,typename XprType::RowXpr>::type SubVectorType;
372   typedef typename internal::conditional<Direction==Vertical,typename XprType::ConstColXpr,typename XprType::ConstRowXpr>::type ConstSubVectorType;
373 
374 
375 public:
376   typedef typename internal::conditional<bool(is_lvalue), SubVectorType, ConstSubVectorType>::type reference;
377   typedef typename reference::PlainObject value_type;
378 
379 private:
380   class subvector_stl_reverse_iterator_ptr
381   {
382   public:
383       subvector_stl_reverse_iterator_ptr(const reference &subvector) : m_subvector(subvector) {}
384       reference* operator->() { return &m_subvector; }
385   private:
386       reference m_subvector;
387   };
388 public:
389 
390   typedef subvector_stl_reverse_iterator_ptr pointer;
391 
392   subvector_stl_reverse_iterator() : Base() {}
393   subvector_stl_reverse_iterator(XprType& xpr, Index index) : Base(xpr,index) {}
394 
395   reference operator*()         const { return (*mp_xpr).template subVector<Direction>(m_index); }
396   reference operator[](Index i) const { return (*mp_xpr).template subVector<Direction>(m_index+i); }
397   pointer   operator->()        const { return (*mp_xpr).template subVector<Direction>(m_index); }
398 };
399 
400 } // namespace internal
401 
402 
403 /** returns an iterator to the first element of the 1D vector or array
404   * \only_for_vectors
405   * \sa end(), cbegin()
406   */
407 template<typename Derived>
408 inline typename DenseBase<Derived>::iterator DenseBase<Derived>::begin()
409 {
410   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
411   return iterator(derived(), 0);
412 }
413 
414 /** const version of begin() */
415 template<typename Derived>
416 inline typename DenseBase<Derived>::const_iterator DenseBase<Derived>::begin() const
417 {
418   return cbegin();
419 }
420 
421 /** returns a read-only const_iterator to the first element of the 1D vector or array
422   * \only_for_vectors
423   * \sa cend(), begin()
424   */
425 template<typename Derived>
426 inline typename DenseBase<Derived>::const_iterator DenseBase<Derived>::cbegin() const
427 {
428   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
429   return const_iterator(derived(), 0);
430 }
431 
432 /** returns an iterator to the element following the last element of the 1D vector or array
433   * \only_for_vectors
434   * \sa begin(), cend()
435   */
436 template<typename Derived>
437 inline typename DenseBase<Derived>::iterator DenseBase<Derived>::end()
438 {
439   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
440   return iterator(derived(), size());
441 }
442 
443 /** const version of end() */
444 template<typename Derived>
445 inline typename DenseBase<Derived>::const_iterator DenseBase<Derived>::end() const
446 {
447   return cend();
448 }
449 
450 /** returns a read-only const_iterator to the element following the last element of the 1D vector or array
451   * \only_for_vectors
452   * \sa begin(), cend()
453   */
454 template<typename Derived>
455 inline typename DenseBase<Derived>::const_iterator DenseBase<Derived>::cend() const
456 {
457   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
458   return const_iterator(derived(), size());
459 }
460 
461 } // namespace Eigen
462 
463 #endif // EIGEN_STLITERATORS_H
464