stl_iterators.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2018-2019 Gael Guennebaud <gael.guennebaud@inria.fr>
  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. #include "main.h"
  10. #include <iterator>
  11. #include <numeric>
  12. template< class Iterator >
  13. std::reverse_iterator<Iterator>
  14. make_reverse_iterator( Iterator i )
  15. {
  16. return std::reverse_iterator<Iterator>(i);
  17. }
  18. #if !EIGEN_HAS_CXX11
  19. template<class ForwardIt>
  20. ForwardIt is_sorted_until(ForwardIt firstIt, ForwardIt lastIt)
  21. {
  22. if (firstIt != lastIt) {
  23. ForwardIt next = firstIt;
  24. while (++next != lastIt) {
  25. if (*next < *firstIt)
  26. return next;
  27. firstIt = next;
  28. }
  29. }
  30. return lastIt;
  31. }
  32. template<class ForwardIt>
  33. bool is_sorted(ForwardIt firstIt, ForwardIt lastIt)
  34. {
  35. return ::is_sorted_until(firstIt, lastIt) == lastIt;
  36. }
  37. #else
  38. using std::is_sorted;
  39. #endif
  40. template<typename XprType>
  41. bool is_pointer_based_stl_iterator(const internal::pointer_based_stl_iterator<XprType> &) { return true; }
  42. template<typename XprType>
  43. bool is_generic_randaccess_stl_iterator(const internal::generic_randaccess_stl_iterator<XprType> &) { return true; }
  44. template<typename Iter>
  45. bool is_default_constructible_and_assignable(const Iter& it)
  46. {
  47. #if EIGEN_HAS_CXX11
  48. VERIFY(std::is_default_constructible<Iter>::value);
  49. VERIFY(std::is_nothrow_default_constructible<Iter>::value);
  50. #endif
  51. Iter it2;
  52. it2 = it;
  53. return (it==it2);
  54. }
  55. template<typename Xpr>
  56. void check_begin_end_for_loop(Xpr xpr)
  57. {
  58. const Xpr& cxpr(xpr);
  59. Index i = 0;
  60. i = 0;
  61. for(typename Xpr::iterator it = xpr.begin(); it!=xpr.end(); ++it) { VERIFY_IS_EQUAL(*it,xpr[i++]); }
  62. i = 0;
  63. for(typename Xpr::const_iterator it = xpr.cbegin(); it!=xpr.cend(); ++it) { VERIFY_IS_EQUAL(*it,xpr[i++]); }
  64. i = 0;
  65. for(typename Xpr::const_iterator it = cxpr.begin(); it!=cxpr.end(); ++it) { VERIFY_IS_EQUAL(*it,xpr[i++]); }
  66. i = 0;
  67. for(typename Xpr::const_iterator it = xpr.begin(); it!=xpr.end(); ++it) { VERIFY_IS_EQUAL(*it,xpr[i++]); }
  68. {
  69. // simple API check
  70. typename Xpr::const_iterator cit = xpr.begin();
  71. cit = xpr.cbegin();
  72. #if EIGEN_HAS_CXX11
  73. auto tmp1 = xpr.begin();
  74. VERIFY(tmp1==xpr.begin());
  75. auto tmp2 = xpr.cbegin();
  76. VERIFY(tmp2==xpr.cbegin());
  77. #endif
  78. }
  79. VERIFY( xpr.end() -xpr.begin() == xpr.size() );
  80. VERIFY( xpr.cend()-xpr.begin() == xpr.size() );
  81. VERIFY( xpr.end() -xpr.cbegin() == xpr.size() );
  82. VERIFY( xpr.cend()-xpr.cbegin() == xpr.size() );
  83. if(xpr.size()>0) {
  84. VERIFY(xpr.begin() != xpr.end());
  85. VERIFY(xpr.begin() < xpr.end());
  86. VERIFY(xpr.begin() <= xpr.end());
  87. VERIFY(!(xpr.begin() == xpr.end()));
  88. VERIFY(!(xpr.begin() > xpr.end()));
  89. VERIFY(!(xpr.begin() >= xpr.end()));
  90. VERIFY(xpr.cbegin() != xpr.end());
  91. VERIFY(xpr.cbegin() < xpr.end());
  92. VERIFY(xpr.cbegin() <= xpr.end());
  93. VERIFY(!(xpr.cbegin() == xpr.end()));
  94. VERIFY(!(xpr.cbegin() > xpr.end()));
  95. VERIFY(!(xpr.cbegin() >= xpr.end()));
  96. VERIFY(xpr.begin() != xpr.cend());
  97. VERIFY(xpr.begin() < xpr.cend());
  98. VERIFY(xpr.begin() <= xpr.cend());
  99. VERIFY(!(xpr.begin() == xpr.cend()));
  100. VERIFY(!(xpr.begin() > xpr.cend()));
  101. VERIFY(!(xpr.begin() >= xpr.cend()));
  102. }
  103. }
  104. template<typename Scalar, int Rows, int Cols>
  105. void test_stl_iterators(int rows=Rows, int cols=Cols)
  106. {
  107. typedef Matrix<Scalar,Rows,1> VectorType;
  108. #if EIGEN_HAS_CXX11
  109. typedef Matrix<Scalar,1,Cols> RowVectorType;
  110. #endif
  111. typedef Matrix<Scalar,Rows,Cols,ColMajor> ColMatrixType;
  112. typedef Matrix<Scalar,Rows,Cols,RowMajor> RowMatrixType;
  113. VectorType v = VectorType::Random(rows);
  114. const VectorType& cv(v);
  115. ColMatrixType A = ColMatrixType::Random(rows,cols);
  116. const ColMatrixType& cA(A);
  117. RowMatrixType B = RowMatrixType::Random(rows,cols);
  118. Index i, j;
  119. // Verify that iterators are default constructible (See bug #1900)
  120. {
  121. VERIFY( is_default_constructible_and_assignable(v.begin()));
  122. VERIFY( is_default_constructible_and_assignable(v.end()));
  123. VERIFY( is_default_constructible_and_assignable(cv.begin()));
  124. VERIFY( is_default_constructible_and_assignable(cv.end()));
  125. VERIFY( is_default_constructible_and_assignable(A.row(0).begin()));
  126. VERIFY( is_default_constructible_and_assignable(A.row(0).end()));
  127. VERIFY( is_default_constructible_and_assignable(cA.row(0).begin()));
  128. VERIFY( is_default_constructible_and_assignable(cA.row(0).end()));
  129. VERIFY( is_default_constructible_and_assignable(B.row(0).begin()));
  130. VERIFY( is_default_constructible_and_assignable(B.row(0).end()));
  131. }
  132. // Check we got a fast pointer-based iterator when expected
  133. {
  134. VERIFY( is_pointer_based_stl_iterator(v.begin()) );
  135. VERIFY( is_pointer_based_stl_iterator(v.end()) );
  136. VERIFY( is_pointer_based_stl_iterator(cv.begin()) );
  137. VERIFY( is_pointer_based_stl_iterator(cv.end()) );
  138. j = internal::random<Index>(0,A.cols()-1);
  139. VERIFY( is_pointer_based_stl_iterator(A.col(j).begin()) );
  140. VERIFY( is_pointer_based_stl_iterator(A.col(j).end()) );
  141. VERIFY( is_pointer_based_stl_iterator(cA.col(j).begin()) );
  142. VERIFY( is_pointer_based_stl_iterator(cA.col(j).end()) );
  143. i = internal::random<Index>(0,A.rows()-1);
  144. VERIFY( is_pointer_based_stl_iterator(A.row(i).begin()) );
  145. VERIFY( is_pointer_based_stl_iterator(A.row(i).end()) );
  146. VERIFY( is_pointer_based_stl_iterator(cA.row(i).begin()) );
  147. VERIFY( is_pointer_based_stl_iterator(cA.row(i).end()) );
  148. VERIFY( is_pointer_based_stl_iterator(A.reshaped().begin()) );
  149. VERIFY( is_pointer_based_stl_iterator(A.reshaped().end()) );
  150. VERIFY( is_pointer_based_stl_iterator(cA.reshaped().begin()) );
  151. VERIFY( is_pointer_based_stl_iterator(cA.reshaped().end()) );
  152. VERIFY( is_pointer_based_stl_iterator(B.template reshaped<AutoOrder>().begin()) );
  153. VERIFY( is_pointer_based_stl_iterator(B.template reshaped<AutoOrder>().end()) );
  154. VERIFY( is_generic_randaccess_stl_iterator(A.template reshaped<RowMajor>().begin()) );
  155. VERIFY( is_generic_randaccess_stl_iterator(A.template reshaped<RowMajor>().end()) );
  156. }
  157. {
  158. check_begin_end_for_loop(v);
  159. check_begin_end_for_loop(A.col(internal::random<Index>(0,A.cols()-1)));
  160. check_begin_end_for_loop(A.row(internal::random<Index>(0,A.rows()-1)));
  161. check_begin_end_for_loop(v+v);
  162. }
  163. #if EIGEN_HAS_CXX11
  164. // check swappable
  165. {
  166. using std::swap;
  167. // pointer-based
  168. {
  169. VectorType v_copy = v;
  170. auto a = v.begin();
  171. auto b = v.end()-1;
  172. swap(a,b);
  173. VERIFY_IS_EQUAL(v,v_copy);
  174. VERIFY_IS_EQUAL(*b,*v.begin());
  175. VERIFY_IS_EQUAL(*b,v(0));
  176. VERIFY_IS_EQUAL(*a,v.end()[-1]);
  177. VERIFY_IS_EQUAL(*a,v(last));
  178. }
  179. // generic
  180. {
  181. RowMatrixType B_copy = B;
  182. auto Br = B.reshaped();
  183. auto a = Br.begin();
  184. auto b = Br.end()-1;
  185. swap(a,b);
  186. VERIFY_IS_EQUAL(B,B_copy);
  187. VERIFY_IS_EQUAL(*b,*Br.begin());
  188. VERIFY_IS_EQUAL(*b,Br(0));
  189. VERIFY_IS_EQUAL(*a,Br.end()[-1]);
  190. VERIFY_IS_EQUAL(*a,Br(last));
  191. }
  192. }
  193. // check non-const iterator with for-range loops
  194. {
  195. i = 0;
  196. for(auto x : v) { VERIFY_IS_EQUAL(x,v[i++]); }
  197. j = internal::random<Index>(0,A.cols()-1);
  198. i = 0;
  199. for(auto x : A.col(j)) { VERIFY_IS_EQUAL(x,A(i++,j)); }
  200. i = 0;
  201. for(auto x : (v+A.col(j))) { VERIFY_IS_APPROX(x,v(i)+A(i,j)); ++i; }
  202. j = 0;
  203. i = internal::random<Index>(0,A.rows()-1);
  204. for(auto x : A.row(i)) { VERIFY_IS_EQUAL(x,A(i,j++)); }
  205. i = 0;
  206. for(auto x : A.reshaped()) { VERIFY_IS_EQUAL(x,A(i++)); }
  207. }
  208. // same for const_iterator
  209. {
  210. i = 0;
  211. for(auto x : cv) { VERIFY_IS_EQUAL(x,v[i++]); }
  212. i = 0;
  213. for(auto x : cA.reshaped()) { VERIFY_IS_EQUAL(x,A(i++)); }
  214. j = 0;
  215. i = internal::random<Index>(0,A.rows()-1);
  216. for(auto x : cA.row(i)) { VERIFY_IS_EQUAL(x,A(i,j++)); }
  217. }
  218. // check reshaped() on row-major
  219. {
  220. i = 0;
  221. Matrix<Scalar,Dynamic,Dynamic,ColMajor> Bc = B;
  222. for(auto x : B.reshaped()) { VERIFY_IS_EQUAL(x,Bc(i++)); }
  223. }
  224. // check write access
  225. {
  226. VectorType w(v.size());
  227. i = 0;
  228. for(auto& x : w) { x = v(i++); }
  229. VERIFY_IS_EQUAL(v,w);
  230. }
  231. // check for dangling pointers
  232. {
  233. // no dangling because pointer-based
  234. {
  235. j = internal::random<Index>(0,A.cols()-1);
  236. auto it = A.col(j).begin();
  237. for(i=0;i<rows;++i) {
  238. VERIFY_IS_EQUAL(it[i],A(i,j));
  239. }
  240. }
  241. // no dangling because pointer-based
  242. {
  243. i = internal::random<Index>(0,A.rows()-1);
  244. auto it = A.row(i).begin();
  245. for(j=0;j<cols;++j) { VERIFY_IS_EQUAL(it[j],A(i,j)); }
  246. }
  247. {
  248. j = internal::random<Index>(0,A.cols()-1);
  249. // this would produce a dangling pointer:
  250. // auto it = (A+2*A).col(j).begin();
  251. // we need to name the temporary expression:
  252. auto tmp = (A+2*A).col(j);
  253. auto it = tmp.begin();
  254. for(i=0;i<rows;++i) {
  255. VERIFY_IS_APPROX(it[i],3*A(i,j));
  256. }
  257. }
  258. }
  259. {
  260. // check basic for loop on vector-wise iterators
  261. j=0;
  262. for (auto it = A.colwise().cbegin(); it != A.colwise().cend(); ++it, ++j) {
  263. VERIFY_IS_APPROX( it->coeff(0), A(0,j) );
  264. VERIFY_IS_APPROX( (*it).coeff(0), A(0,j) );
  265. }
  266. j=0;
  267. for (auto it = A.colwise().begin(); it != A.colwise().end(); ++it, ++j) {
  268. (*it).coeffRef(0) = (*it).coeff(0); // compilation check
  269. it->coeffRef(0) = it->coeff(0); // compilation check
  270. VERIFY_IS_APPROX( it->coeff(0), A(0,j) );
  271. VERIFY_IS_APPROX( (*it).coeff(0), A(0,j) );
  272. }
  273. // check valuetype gives us a copy
  274. j=0;
  275. for (auto it = A.colwise().cbegin(); it != A.colwise().cend(); ++it, ++j) {
  276. typename decltype(it)::value_type tmp = *it;
  277. VERIFY_IS_NOT_EQUAL( tmp.data() , it->data() );
  278. VERIFY_IS_APPROX( tmp, A.col(j) );
  279. }
  280. }
  281. #endif
  282. if(rows>=3) {
  283. VERIFY_IS_EQUAL((v.begin()+rows/2)[1], v(rows/2+1));
  284. VERIFY_IS_EQUAL((A.rowwise().begin()+rows/2)[1], A.row(rows/2+1));
  285. }
  286. if(cols>=3) {
  287. VERIFY_IS_EQUAL((A.colwise().begin()+cols/2)[1], A.col(cols/2+1));
  288. }
  289. // check std::sort
  290. {
  291. // first check that is_sorted returns false when required
  292. if(rows>=2)
  293. {
  294. v(1) = v(0)-Scalar(1);
  295. #if EIGEN_HAS_CXX11
  296. VERIFY(!is_sorted(std::begin(v),std::end(v)));
  297. #else
  298. VERIFY(!is_sorted(v.cbegin(),v.cend()));
  299. #endif
  300. }
  301. // on a vector
  302. {
  303. std::sort(v.begin(),v.end());
  304. VERIFY(is_sorted(v.begin(),v.end()));
  305. VERIFY(!::is_sorted(make_reverse_iterator(v.end()),make_reverse_iterator(v.begin())));
  306. }
  307. // on a column of a column-major matrix -> pointer-based iterator and default increment
  308. {
  309. j = internal::random<Index>(0,A.cols()-1);
  310. // std::sort(begin(A.col(j)),end(A.col(j))); // does not compile because this returns const iterators
  311. typename ColMatrixType::ColXpr Acol = A.col(j);
  312. std::sort(Acol.begin(),Acol.end());
  313. VERIFY(is_sorted(Acol.cbegin(),Acol.cend()));
  314. A.setRandom();
  315. std::sort(A.col(j).begin(),A.col(j).end());
  316. VERIFY(is_sorted(A.col(j).cbegin(),A.col(j).cend()));
  317. A.setRandom();
  318. }
  319. // on a row of a rowmajor matrix -> pointer-based iterator and runtime increment
  320. {
  321. i = internal::random<Index>(0,A.rows()-1);
  322. typename ColMatrixType::RowXpr Arow = A.row(i);
  323. VERIFY_IS_EQUAL( std::distance(Arow.begin(),Arow.end()), cols);
  324. std::sort(Arow.begin(),Arow.end());
  325. VERIFY(is_sorted(Arow.cbegin(),Arow.cend()));
  326. A.setRandom();
  327. std::sort(A.row(i).begin(),A.row(i).end());
  328. VERIFY(is_sorted(A.row(i).cbegin(),A.row(i).cend()));
  329. A.setRandom();
  330. }
  331. // with a generic iterator
  332. {
  333. Reshaped<RowMatrixType,RowMatrixType::SizeAtCompileTime,1> B1 = B.reshaped();
  334. std::sort(B1.begin(),B1.end());
  335. VERIFY(is_sorted(B1.cbegin(),B1.cend()));
  336. B.setRandom();
  337. // assertion because nested expressions are different
  338. // std::sort(B.reshaped().begin(),B.reshaped().end());
  339. // VERIFY(is_sorted(B.reshaped().cbegin(),B.reshaped().cend()));
  340. // B.setRandom();
  341. }
  342. }
  343. // check with partial_sum
  344. {
  345. j = internal::random<Index>(0,A.cols()-1);
  346. typename ColMatrixType::ColXpr Acol = A.col(j);
  347. std::partial_sum(Acol.begin(), Acol.end(), v.begin());
  348. VERIFY_IS_APPROX(v(seq(1,last)), v(seq(0,last-1))+Acol(seq(1,last)));
  349. // inplace
  350. std::partial_sum(Acol.begin(), Acol.end(), Acol.begin());
  351. VERIFY_IS_APPROX(v, Acol);
  352. }
  353. // stress random access as required by std::nth_element
  354. if(rows>=3)
  355. {
  356. v.setRandom();
  357. VectorType v1 = v;
  358. std::sort(v1.begin(),v1.end());
  359. std::nth_element(v.begin(), v.begin()+rows/2, v.end());
  360. VERIFY_IS_APPROX(v1(rows/2), v(rows/2));
  361. v.setRandom();
  362. v1 = v;
  363. std::sort(v1.begin()+rows/2,v1.end());
  364. std::nth_element(v.begin()+rows/2, v.begin()+rows/4, v.end());
  365. VERIFY_IS_APPROX(v1(rows/4), v(rows/4));
  366. }
  367. #if EIGEN_HAS_CXX11
  368. // check rows/cols iterators with range-for loops
  369. {
  370. j = 0;
  371. for(auto c : A.colwise()) { VERIFY_IS_APPROX(c.sum(), A.col(j).sum()); ++j; }
  372. j = 0;
  373. for(auto c : B.colwise()) { VERIFY_IS_APPROX(c.sum(), B.col(j).sum()); ++j; }
  374. j = 0;
  375. for(auto c : B.colwise()) {
  376. i = 0;
  377. for(auto& x : c) {
  378. VERIFY_IS_EQUAL(x, B(i,j));
  379. x = A(i,j);
  380. ++i;
  381. }
  382. ++j;
  383. }
  384. VERIFY_IS_APPROX(A,B);
  385. B.setRandom();
  386. i = 0;
  387. for(auto r : A.rowwise()) { VERIFY_IS_APPROX(r.sum(), A.row(i).sum()); ++i; }
  388. i = 0;
  389. for(auto r : B.rowwise()) { VERIFY_IS_APPROX(r.sum(), B.row(i).sum()); ++i; }
  390. }
  391. // check rows/cols iterators with STL algorithms
  392. {
  393. RowVectorType row = RowVectorType::Random(cols);
  394. A.rowwise() = row;
  395. VERIFY( std::all_of(A.rowwise().begin(), A.rowwise().end(), [&row](typename ColMatrixType::RowXpr x) { return internal::isApprox(x.squaredNorm(),row.squaredNorm()); }) );
  396. VERIFY( std::all_of(A.rowwise().rbegin(), A.rowwise().rend(), [&row](typename ColMatrixType::RowXpr x) { return internal::isApprox(x.squaredNorm(),row.squaredNorm()); }) );
  397. VectorType col = VectorType::Random(rows);
  398. A.colwise() = col;
  399. VERIFY( std::all_of(A.colwise().begin(), A.colwise().end(), [&col](typename ColMatrixType::ColXpr x) { return internal::isApprox(x.squaredNorm(),col.squaredNorm()); }) );
  400. VERIFY( std::all_of(A.colwise().rbegin(), A.colwise().rend(), [&col](typename ColMatrixType::ColXpr x) { return internal::isApprox(x.squaredNorm(),col.squaredNorm()); }) );
  401. VERIFY( std::all_of(A.colwise().cbegin(), A.colwise().cend(), [&col](typename ColMatrixType::ConstColXpr x) { return internal::isApprox(x.squaredNorm(),col.squaredNorm()); }) );
  402. VERIFY( std::all_of(A.colwise().crbegin(), A.colwise().crend(), [&col](typename ColMatrixType::ConstColXpr x) { return internal::isApprox(x.squaredNorm(),col.squaredNorm()); }) );
  403. i = internal::random<Index>(0,A.rows()-1);
  404. A.setRandom();
  405. A.row(i).setZero();
  406. VERIFY_IS_EQUAL( std::find_if(A.rowwise().begin(), A.rowwise().end(), [](typename ColMatrixType::RowXpr x) { return x.squaredNorm() == Scalar(0); })-A.rowwise().begin(), i );
  407. VERIFY_IS_EQUAL( std::find_if(A.rowwise().rbegin(), A.rowwise().rend(), [](typename ColMatrixType::RowXpr x) { return x.squaredNorm() == Scalar(0); })-A.rowwise().rbegin(), (A.rows()-1) - i );
  408. j = internal::random<Index>(0,A.cols()-1);
  409. A.setRandom();
  410. A.col(j).setZero();
  411. VERIFY_IS_EQUAL( std::find_if(A.colwise().begin(), A.colwise().end(), [](typename ColMatrixType::ColXpr x) { return x.squaredNorm() == Scalar(0); })-A.colwise().begin(), j );
  412. VERIFY_IS_EQUAL( std::find_if(A.colwise().rbegin(), A.colwise().rend(), [](typename ColMatrixType::ColXpr x) { return x.squaredNorm() == Scalar(0); })-A.colwise().rbegin(), (A.cols()-1) - j );
  413. }
  414. {
  415. using VecOp = VectorwiseOp<ArrayXXi, 0>;
  416. STATIC_CHECK(( internal::is_same<VecOp::const_iterator, decltype(std::declval<const VecOp&>().cbegin())>::value ));
  417. STATIC_CHECK(( internal::is_same<VecOp::const_iterator, decltype(std::declval<const VecOp&>().cend ())>::value ));
  418. #if EIGEN_COMP_CXXVER>=14
  419. STATIC_CHECK(( internal::is_same<VecOp::const_iterator, decltype(std::cbegin(std::declval<const VecOp&>()))>::value ));
  420. STATIC_CHECK(( internal::is_same<VecOp::const_iterator, decltype(std::cend (std::declval<const VecOp&>()))>::value ));
  421. #endif
  422. }
  423. #endif
  424. }
  425. #if EIGEN_HAS_CXX11
  426. // When the compiler sees expression IsContainerTest<C>(0), if C is an
  427. // STL-style container class, the first overload of IsContainerTest
  428. // will be viable (since both C::iterator* and C::const_iterator* are
  429. // valid types and NULL can be implicitly converted to them). It will
  430. // be picked over the second overload as 'int' is a perfect match for
  431. // the type of argument 0. If C::iterator or C::const_iterator is not
  432. // a valid type, the first overload is not viable, and the second
  433. // overload will be picked.
  434. template <class C,
  435. class Iterator = decltype(::std::declval<const C&>().begin()),
  436. class = decltype(::std::declval<const C&>().end()),
  437. class = decltype(++::std::declval<Iterator&>()),
  438. class = decltype(*::std::declval<Iterator>()),
  439. class = typename C::const_iterator>
  440. bool IsContainerType(int /* dummy */) { return true; }
  441. template <class C>
  442. bool IsContainerType(long /* dummy */) { return false; }
  443. template <typename Scalar, int Rows, int Cols>
  444. void test_stl_container_detection(int rows=Rows, int cols=Cols)
  445. {
  446. typedef Matrix<Scalar,Rows,1> VectorType;
  447. typedef Matrix<Scalar,Rows,Cols,ColMajor> ColMatrixType;
  448. typedef Matrix<Scalar,Rows,Cols,RowMajor> RowMatrixType;
  449. ColMatrixType A = ColMatrixType::Random(rows, cols);
  450. RowMatrixType B = RowMatrixType::Random(rows, cols);
  451. Index i = 1;
  452. using ColMatrixColType = decltype(A.col(i));
  453. using ColMatrixRowType = decltype(A.row(i));
  454. using RowMatrixColType = decltype(B.col(i));
  455. using RowMatrixRowType = decltype(B.row(i));
  456. // Vector and matrix col/row are valid Stl-style container.
  457. VERIFY_IS_EQUAL(IsContainerType<VectorType>(0), true);
  458. VERIFY_IS_EQUAL(IsContainerType<ColMatrixColType>(0), true);
  459. VERIFY_IS_EQUAL(IsContainerType<ColMatrixRowType>(0), true);
  460. VERIFY_IS_EQUAL(IsContainerType<RowMatrixColType>(0), true);
  461. VERIFY_IS_EQUAL(IsContainerType<RowMatrixRowType>(0), true);
  462. // But the matrix itself is not a valid Stl-style container.
  463. VERIFY_IS_EQUAL(IsContainerType<ColMatrixType>(0), rows == 1 || cols == 1);
  464. VERIFY_IS_EQUAL(IsContainerType<RowMatrixType>(0), rows == 1 || cols == 1);
  465. }
  466. #endif
  467. EIGEN_DECLARE_TEST(stl_iterators)
  468. {
  469. for(int i = 0; i < g_repeat; i++) {
  470. CALL_SUBTEST_1(( test_stl_iterators<double,2,3>() ));
  471. CALL_SUBTEST_1(( test_stl_iterators<float,7,5>() ));
  472. CALL_SUBTEST_1(( test_stl_iterators<int,Dynamic,Dynamic>(internal::random<int>(5,10), internal::random<int>(5,10)) ));
  473. CALL_SUBTEST_1(( test_stl_iterators<int,Dynamic,Dynamic>(internal::random<int>(10,200), internal::random<int>(10,200)) ));
  474. }
  475. #if EIGEN_HAS_CXX11
  476. CALL_SUBTEST_1(( test_stl_container_detection<float,1,1>() ));
  477. CALL_SUBTEST_1(( test_stl_container_detection<float,5,5>() ));
  478. #endif
  479. }