small-0.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra/test - Constructors and assignment for Small.
  3. // (c) Daniel Llorens - 2014, 2016-2017, 2019
  4. // This library is free software; you can redistribute it and/or modify it under
  5. // the terms of the GNU Lesser General Public License as published by the Free
  6. // Software Foundation; either version 3 of the License, or (at your option) any
  7. // later version.
  8. // See also small-1.cc.
  9. #include <iostream>
  10. #include <iterator>
  11. #include "ra/test.hh"
  12. #include "mpdebug.hh"
  13. using std::cout, std::endl, std::flush, ra::TestRecorder;
  14. using complex = std::complex<double>;
  15. using ra::mp::int_list, ra::int_c;
  16. struct test_type { int a; };
  17. std::string typecheck(auto && a)
  18. {
  19. return std::source_location::current().function_name();
  20. };
  21. int main()
  22. {
  23. TestRecorder tr;
  24. tr.section("std::array is used internally so these are fundamental");
  25. {
  26. static_assert(3==ra::size(std::array { 3, 4, 5 }));
  27. static_assert(3==ra::size_s(std::array { 3, 4, 5 }));
  28. }
  29. tr.section("Small isn't an aggregate so T; and T {}; are the same, unlike std::array");
  30. {
  31. std::array<int, 9> a; // default init, unlike {} which is aggregate init
  32. cout << ra::start(a) << endl;
  33. ra::Small<int, 9> b; // default init, just like {}
  34. cout << b << endl;
  35. ra::Small<int, 3> c(ra::none); // if you want to be explicit
  36. cout << c << endl;
  37. }
  38. tr.section("can't really init std::array with constant");
  39. {
  40. std::array<int, 9> a = {1};
  41. tr.test_eq(1, a[0]);
  42. tr.test_eq(0, a[1]);
  43. ra::Small<int, 9> b = {1};
  44. tr.test_eq(1, b);
  45. }
  46. tr.section("predicates");
  47. {
  48. tr.test(std::is_standard_layout_v<ra::Small<float, 2>>);
  49. ra::Small<int, 2, 3> a;
  50. static_assert(std::input_iterator<decltype(a.begin())>);
  51. }
  52. tr.section("BUG ambiguous case I");
  53. {
  54. double U[] = { 1, 2, 3 };
  55. ra::Small<ra::Big<double, 1>, 1> u = { {U} };
  56. tr.test_eq(U, u[0]);
  57. // std::cout << "---------" << std::endl;
  58. // ra::Small<ra::Big<double, 1>, 1> v = { U }; // BUG [ra45] (Big inits as empty, then assignment fails)
  59. // std::cout << "---------" << std::endl;
  60. // cout << v << endl;
  61. }
  62. // tr.section("BUG ambiguous case II");
  63. // {
  64. // ra::Small<int, 1, 2> a({ 1, 2 }); // BUG ambiguous [ra46]
  65. // // ra::Small<int, 1, 2> a { 1, 2 }; // works as ravel
  66. // // ra::Small<int, 1, 2> a {{ 1, 2 }}; // works
  67. // // ra::Small<int, 1, 2> a({{ 1, 2 }}); // works
  68. // tr.test_eq(1, a(0, 0));
  69. // tr.test_eq(2, a(0, 1));
  70. // }
  71. /*
  72. Small nested constructors rely on initialized_list so that we can size-check
  73. the arguments. This check has to be done at run time but I consider that
  74. preferable to the builtin array syntax which defect errors non-detectable
  75. (even though excess errors are compile time).
  76. Still, if we ever want to do that, it's good to know that we can construct
  77. higher rank builtin array types like this.
  78. */
  79. tr.section("= unbraced");
  80. {
  81. ra::Small<int, 2> a = {9, 3};
  82. tr.test_eq(9, a[0]);
  83. tr.test_eq(3, a[1]);
  84. }
  85. tr.section("basic facts about builtin arrays");
  86. {
  87. using A0 = double[3];
  88. using A1 = A0[2];
  89. using A2 = double[2][3];
  90. A1 x1 = {{1, 2, 3}, {4, 5, 6}};
  91. A2 x2 = {{1, 2, 3}, {4, 5, 6}};
  92. tr.test_eq(2u, std::rank<A1>::value);
  93. tr.test_eq(2, ra::start(x1).rank());
  94. tr.test_eq(2u, std::rank<A2>::value);
  95. tr.test_eq(2, ra::start(x2).rank());
  96. tr.test_eq(ra::start(x2), x1);
  97. }
  98. tr.section("top level generics on builtin arrays");
  99. {
  100. int a[3] = {1, 2, 3};
  101. tr.test_eq(1, ra::rank(a));
  102. tr.test_eq(3, ra::size(a));
  103. tr.test_eq(3, ra::shape(a)[0]);
  104. }
  105. tr.section("top level generics on builtin arrays II");
  106. {
  107. int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
  108. tr.test_eq(2, ra::rank(a));
  109. tr.test_eq(6, ra::size(a));
  110. tr.test_eq(2, ra::shape(a)[0]);
  111. tr.test_eq(3, ra::shape(a)[1]);
  112. }
  113. tr.section("scalar constructors");
  114. {
  115. tr.section("scalar paren unbraced");
  116. {
  117. ra::Small<int, 2> a(9);
  118. tr.test_eq(9, a[0]);
  119. tr.test_eq(9, a[1]);
  120. }
  121. tr.section("scalar op unbraced");
  122. {
  123. ra::Small<complex, 2> a = 9.;
  124. tr.test_eq(9., a[0]);
  125. tr.test_eq(9., a[1]);
  126. }
  127. tr.section("variants I wish didn't work :-/ just checking for regressions");
  128. {
  129. {
  130. ra::Small<int, 2> a({9});
  131. tr.test_eq(9, a[0]);
  132. tr.test_eq(9, a[1]);
  133. }
  134. {
  135. ra::Small<int, 2> a {9};
  136. tr.test_eq(9, a[0]);
  137. tr.test_eq(9, a[1]);
  138. }
  139. {
  140. ra::Small<complex, 2> a = {9.};
  141. tr.test_eq(9., a[0]);
  142. tr.test_eq(9., a[1]);
  143. }
  144. }
  145. }
  146. tr.section("empty");
  147. {
  148. ra::Small<int, 0> x;
  149. tr.test_eq(0, x.size());
  150. }
  151. tr.section("rank 0");
  152. {
  153. tr.section("default");
  154. {
  155. ra::Small<int> x;
  156. x = 3;
  157. tr.test_eq(3, x());
  158. }
  159. tr.section("rank 0 paren unbraced");
  160. {
  161. ra::Small<int> a(9);
  162. tr.test_eq(9, a());
  163. }
  164. tr.section("rank 0 paren braced");
  165. {
  166. ra::Small<int> a({9});
  167. tr.test_eq(9, a());
  168. }
  169. tr.section("rank 0 op unbraced");
  170. {
  171. ra::Small<int> a = 9;
  172. tr.test_eq(9, a());
  173. }
  174. tr.section("rank 0 op braced");
  175. {
  176. ra::Small<int> a = {9};
  177. tr.test_eq(9, a());
  178. }
  179. tr.section("rank 0 raw braced");
  180. {
  181. ra::Small<int> a {9};
  182. tr.test_eq(9, a());
  183. }
  184. }
  185. tr.section("rank 1");
  186. {
  187. tr.section("= unbraced");
  188. {
  189. ra::Small<int, 2> a = {9, 3};
  190. tr.test_eq(9, a[0]);
  191. tr.test_eq(3, a[1]);
  192. }
  193. tr.section("raw unbraced");
  194. {
  195. ra::Small<int, 2> a {9, 3};
  196. tr.test_eq(9, a[0]);
  197. tr.test_eq(3, a[1]);
  198. }
  199. tr.section("paren unbraced");
  200. {
  201. ra::Small<int, 2> a({9, 3});
  202. tr.test_eq(9, a[0]);
  203. tr.test_eq(3, a[1]);
  204. }
  205. tr.section("paren raw");
  206. {
  207. ra::Small<int, 2> a(9, 3);
  208. tr.test_eq(9, a[0]);
  209. tr.test_eq(3, a[1]);
  210. }
  211. tr.section("= scalar init");
  212. {
  213. ra::Small<int, 2> a = 9;
  214. tr.test_eq(9, a[0]);
  215. tr.test_eq(9, a[1]);
  216. }
  217. tr.section("= scalar init with non-ra::scalar type"); // [ra44]
  218. {
  219. ra::Small<test_type, 2> a = test_type { 9 };
  220. tr.test_eq(9, a[0].a);
  221. tr.test_eq(9, a[1].a);
  222. a = test_type { 3 };
  223. tr.test_eq(3, a[0].a);
  224. tr.test_eq(3, a[1].a);
  225. }
  226. // Braced versions used to work but now they don't. This is on purpose.
  227. // tr.section("= braced");
  228. // {
  229. // ra::Small<int, 2> a = {{9, 3}};
  230. // tr.test_eq(9, a[0]);
  231. // tr.test_eq(3, a[1]);
  232. // }
  233. // tr.section("raw braced");
  234. // {
  235. // ra::Small<int, 2> a {{9, 3}};
  236. // tr.test_eq(9, a[0]);
  237. // tr.test_eq(3, a[1]);
  238. // }
  239. // tr.section("paren braced");
  240. // {
  241. // ra::Small<int, 2> a({{9, 3}});
  242. // tr.test_eq(9, a[0]);
  243. // tr.test_eq(3, a[1]);
  244. // }
  245. }
  246. tr.section("rank 2");
  247. {
  248. tr.section("rank 2 (paren unun)");
  249. {
  250. ra::Small<double, 2, 2> a({1, 2}, {3, 4});
  251. tr.test_eq(1., a(0, 0));
  252. tr.test_eq(2., a(0, 1));
  253. tr.test_eq(3., a(1, 0));
  254. tr.test_eq(4., a(1, 1));
  255. }
  256. tr.section("rank 2 (paren un)");
  257. {
  258. ra::Small<double, 2, 2> a({{1, 2}, {3, 4}});
  259. tr.test_eq(1., a(0, 0));
  260. tr.test_eq(2., a(0, 1));
  261. tr.test_eq(3., a(1, 0));
  262. tr.test_eq(4., a(1, 1));
  263. }
  264. tr.section("rank 2 (= unbraced)");
  265. {
  266. ra::Small<double, 2, 2> a = {{1., 2.}, {3., 4.}};
  267. tr.test_eq(1., a(0, 0));
  268. tr.test_eq(2., a(0, 1));
  269. tr.test_eq(3., a(1, 0));
  270. tr.test_eq(4., a(1, 1));
  271. }
  272. tr.section("rank 2 (raw unbraced) I");
  273. {
  274. ra::Small<double, 2, 2> a {{1, 2}, {3, 4}};
  275. tr.test_eq(1., a(0, 0));
  276. tr.test_eq(2., a(0, 1));
  277. tr.test_eq(3., a(1, 0));
  278. tr.test_eq(4., a(1, 1));
  279. }
  280. tr.section("rank 2 (raw unbraced) II");
  281. {
  282. ra::Small<double, 2, 3> a {{1, 2, 3}, {4, 5, 6}};
  283. tr.test_eq(1., a(0, 0));
  284. tr.test_eq(2., a(0, 1));
  285. tr.test_eq(3., a(0, 2));
  286. tr.test_eq(4., a(1, 0));
  287. tr.test_eq(5., a(1, 1));
  288. tr.test_eq(6., a(1, 2));
  289. }
  290. tr.section("rank 2 (paren raw)");
  291. {
  292. ra::Small<double, 2, 2> a({1, 2}, {3, 4});
  293. tr.test_eq(1., a(0, 0));
  294. tr.test_eq(2., a(0, 1));
  295. tr.test_eq(3., a(1, 0));
  296. tr.test_eq(4., a(1, 1));
  297. }
  298. tr.section("size 1, higher rank");
  299. {
  300. ra::Small<int, 1, 1> a = {{4}}; // nested
  301. tr.test_eq(4, a(0, 0));
  302. ra::Small<int, 1, 1> b = {4}; // ravel
  303. tr.test_eq(4, b(0, 0));
  304. }
  305. tr.section("singular sizes I");
  306. {
  307. ra::Small<int, 1, 2> a = {{4, 3}}; // nested. This requires the nested constructor with size(0)==1.
  308. tr.test_eq(4, a(0, 0));
  309. tr.test_eq(3, a(0, 1));
  310. ra::Small<int, 1, 2> b = {4, 3}; // ravel
  311. tr.test_eq(4, b(0, 0));
  312. tr.test_eq(3, b(0, 1));
  313. ra::Small<int, 1, 2> c = {4}; // scalar
  314. tr.test_eq(4, c(0, 0));
  315. tr.test_eq(4, c(0, 1));
  316. // ra::Small<int, 1, 3> d = {4, 2}; // ravel // [ra42] FIXME cannot check ct errors yet
  317. // tr.test_eq(4, b(0, 0));
  318. // tr.test_eq(2, b(0, 1));
  319. }
  320. // Braced versions used to work but now they don't. This is on purpose.
  321. // tr.section("rank 2 (paren braced)");
  322. // {
  323. // ra::Small<double, 2, 2> a({{{1, 2}, {3, 4}}});
  324. // tr.test_eq(1., a(0, 0));
  325. // tr.test_eq(2., a(0, 1));
  326. // tr.test_eq(3., a(1, 0));
  327. // tr.test_eq(4., a(1, 1));
  328. // }
  329. // tr.section("rank 2 (= braced)");
  330. // {
  331. // ra::Small<double, 2, 2> a = {{{1, 2}, {3, 4}}};
  332. // tr.test_eq(1., a(0, 0));
  333. // tr.test_eq(2., a(0, 1));
  334. // tr.test_eq(3., a(1, 0));
  335. // tr.test_eq(4., a(1, 1));
  336. // }
  337. // tr.section("rank 2 (raw braced)");
  338. // {
  339. // ra::Small<double, 2, 2> a {{{1, 2}, {3, 4}}};
  340. // tr.test_eq(1., a(0, 0));
  341. // tr.test_eq(2., a(0, 1));
  342. // tr.test_eq(3., a(1, 0));
  343. // tr.test_eq(4., a(1, 1));
  344. // }
  345. }
  346. tr.section("higher rank, unbraced");
  347. {
  348. ra::Small<int, 2, 3, 4, 2> a = {{{{ 1, 2}, { 3, 4}, { 5, 6}, { 7, 8}},
  349. {{ 9, 10}, {11, 12}, {13, 14}, {15, 16}},
  350. {{17, 18}, {19, 20}, {21, 22}, {23, 24}}},
  351. {{{25, 26}, {27, 28}, {29, 30}, {31, 32}},
  352. {{33, 34}, {35, 36}, {37, 38}, {39, 40}},
  353. {{41, 42}, {43, 44}, {45, 46}, {47, 48}}}};
  354. // FIXME reshape for Small or something! Big/View have these things.
  355. ra::Small<int, 2, 3, 4, 2> b = 0;
  356. ra::ViewSmall<int, int_list<48>, int_list<1>> c(b.data());
  357. c = ra::iota(48, 1);
  358. tr.test_eq(b, a);
  359. tr.test_eq(2, ra::shape(a, 0));
  360. tr.test_eq(3, ra::shape(a, 1));
  361. tr.test_eq(4, ra::shape(a, 2));
  362. tr.test_eq(2, ra::shape(a, 3));
  363. }
  364. tr.section("item constructor");
  365. {
  366. ra::Small<int, 2, 2> a = {{1, 2}, ra::iota(2, 33)};
  367. tr.test_eq(1, a(0, 0));
  368. tr.test_eq(2, a(0, 1));
  369. tr.test_eq(33, a(1, 0));
  370. tr.test_eq(34, a(1, 1));
  371. }
  372. tr.section("raveling constructor");
  373. {
  374. ra::Small<int, 2, 2> a = {1, 2, 3, 4};
  375. tr.test_eq(1, a(0, 0));
  376. tr.test_eq(2, a(0, 1));
  377. tr.test_eq(3, a(1, 0));
  378. tr.test_eq(4, a(1, 1));
  379. }
  380. tr.section("raveling constructor from iterators");
  381. {
  382. int AA[4] = { 1, 2, 3, 4 };
  383. auto a = ra::from_ravel<ra::Small<int, 2, 2>>(std::ranges::subrange(AA, AA+4));
  384. tr.test_eq(1, a(0, 0));
  385. tr.test_eq(2, a(0, 1));
  386. tr.test_eq(3, a(1, 0));
  387. tr.test_eq(4, a(1, 1));
  388. auto b = ra::from_ravel<ra::Small<int, 2, 2>>(AA);
  389. tr.test_eq(1, b(0, 0));
  390. tr.test_eq(2, b(0, 1));
  391. tr.test_eq(3, b(1, 0));
  392. tr.test_eq(4, b(1, 1));
  393. auto c = ra::from_ravel<ra::Small<int, 2, 2>>(ra::Small<int, 4> { 1, 2, 3, 4});
  394. tr.test_eq(1, c(0, 0));
  395. tr.test_eq(2, c(0, 1));
  396. tr.test_eq(3, c(1, 0));
  397. tr.test_eq(4, c(1, 1));
  398. }
  399. tr.section("nested Small I");
  400. {
  401. ra::Small<ra::Small<int, 2>, 2> a = {{1, 2}, {3, 4}};
  402. tr.test_eq(1, a(0)(0));
  403. tr.test_eq(2, a(0)(1));
  404. tr.test_eq(3, a(1)(0));
  405. tr.test_eq(4, a(1)(1));
  406. }
  407. tr.section("nested Small II");
  408. {
  409. auto test = [&](auto && a)
  410. {
  411. tr.test_eq(1, a(0)(0, 0));
  412. tr.test_eq(2, a(0)(0, 1));
  413. tr.test_eq(3, a(0)(0, 2));
  414. tr.test_eq(4, a(0)(1, 0));
  415. tr.test_eq(5, a(0)(1, 1));
  416. tr.test_eq(6, a(0)(1, 2));
  417. tr.test_eq(10, a(1)(0, 0));
  418. tr.test_eq(20, a(1)(0, 1));
  419. tr.test_eq(30, a(1)(0, 2));
  420. tr.test_eq(40, a(1)(1, 0));
  421. tr.test_eq(50, a(1)(1, 1));
  422. tr.test_eq(60, a(1)(1, 2));
  423. };
  424. using In = ra::Small<int, 2, 3>;
  425. ra::Small<In, 2> a = {{{1, 2, 3}, {4, 5, 6}}, {{10, 20, 30}, {40, 50, 60}}};
  426. test(a);
  427. ra::Small<In, 2> b = {In {{1, 2, 3}, {4, 5, 6}}, In {{10, 20, 30}, {40, 50, 60}}};
  428. test(b);
  429. int x[2][3] = {{1, 2, 3}, {4, 5, 6}};
  430. int y[2][3] = {{10, 20, 30}, {40, 50, 60}};
  431. ra::Small<In, 2> c = {x, y};
  432. test(c);
  433. }
  434. tr.section("operator=");
  435. {
  436. tr.section("operator= rank 1");
  437. {
  438. ra::Small<complex, 2> a { 3, 4 };
  439. a = complex(99.);
  440. tr.test_eq(99., a[0]);
  441. tr.test_eq(99., a[1]);
  442. a = 88.;
  443. tr.test_eq(88., a[0]);
  444. tr.test_eq(88., a[1]);
  445. a += 1.;
  446. tr.test_eq(89., a[0]);
  447. tr.test_eq(89., a[1]);
  448. }
  449. tr.section("operator= rank 2 unbraced");
  450. {
  451. ra::Small<int, 2, 2> a = 0;
  452. a = {{1, 2}, {3, 4}};
  453. tr.test_eq(1, a(0, 0));
  454. tr.test_eq(2, a(0, 1));
  455. tr.test_eq(3, a(1, 0));
  456. tr.test_eq(4, a(1, 1));
  457. }
  458. // tr.section("operator= rank 2 braced"); // Doesn't work but cannot check ct errors [ra42]
  459. // {
  460. // ra::Small<int, 2, 2> a = 0;
  461. // a = {{{1, 2}, {3, 4}}};
  462. // tr.test_eq(1, a(0, 0));
  463. // tr.test_eq(2, a(0, 1));
  464. // tr.test_eq(3, a(1, 0));
  465. // tr.test_eq(4, a(1, 1));
  466. // }
  467. tr.section("operator= of view into view");
  468. {
  469. {
  470. ra::Small<int, 2, 2> a = {{1, 2}, {3, 4}};
  471. ra::ViewSmall<int, int_list<2>, int_list<1>> a0 = a(0);
  472. ra::ViewSmall<int, int_list<2>, int_list<1>> a1 = a(1);
  473. a0 = a1;
  474. tr.test_eq(ra::Small<int, 2, 2> {{3, 4}, {3, 4}}, a);
  475. }
  476. {
  477. ra::Small<int, 2, 2> a = {{1, 2}, {3, 4}};
  478. ra::ViewSmall<int, int_list<2>, int_list<1>> a0 = a(0);
  479. a0 = a(1);
  480. tr.test_eq(ra::Small<int, 2, 2> {{3, 4}, {3, 4}}, a);
  481. }
  482. }
  483. tr.section("repeat a test from test/big-0 [ra38]");
  484. {
  485. ra::Small<double, 2> A = {1, 2};
  486. ra::Small<double, 2> X = {0, 0};
  487. X(ra::all) = A();
  488. tr.test_eq(ra::start({1, 2}), X);
  489. }
  490. tr.section("operator=(scalar) on non-unit steps");
  491. {
  492. ra::Small<int, 2, 2> a(0);
  493. diag(a) = 1;
  494. tr.test_eq(ra::Small<int, 2, 2> {{1, 0}, {0, 1}}, a);
  495. }
  496. }
  497. // These tests should fail at compile time. No way to check them yet [ra42].
  498. // tr.section("size checks");
  499. // {
  500. // ra::Small<int, 3> a = { 1, 2, 3 };
  501. // ra::Small<int, 2> b = { 4, 5 };
  502. // ra::Small<int, 3> c = a+b;
  503. // cout << c << endl;
  504. // }
  505. // self type assigment
  506. {
  507. ra::Small<int, 3> a = 0;
  508. ra::Small<int, 3> b = {9, 8, 7};
  509. ra::Small<int, 3> c = {9, 8, 7};
  510. auto pa = a.data();
  511. tr.test_eq(a, 0);
  512. cout << typecheck(a()) << endl;
  513. a() = b();
  514. tr.test_eq(a, c);
  515. tr.test_eq(ra::scalar(a.data()), ra::scalar(pa));
  516. a = 0;
  517. tr.test_eq(a, 0);
  518. cout << typecheck(a()) << endl;
  519. a = b;
  520. tr.test_eq(a, c);
  521. tr.test_eq(ra::scalar(a.data()), ra::scalar(pa));
  522. }
  523. // ra::shape / ra::size are static for Small types
  524. {
  525. ra::Small<int, 3, 4> a = 0;
  526. tr.test_eq(2, int_c<rank(a)>::value);
  527. tr.test_eq(3, int_c<shape(a)[0]>::value);
  528. tr.test_eq(4, int_c<shape(a)[1]>::value);
  529. // FIXME std::size makes this ambiguous without the qualifier, which looks wrong to me :-/
  530. tr.test_eq(12, int_c<ra::size(a)>::value);
  531. }
  532. return tr.summary();
  533. }