big.hh 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra - Arrays with dynamic lengths/strides, cf small.hh.
  3. // (c) Daniel Llorens - 2013-2023
  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. #pragma once
  9. #include "small.hh"
  10. #include <memory>
  11. #include <iosfwd>
  12. namespace ra {
  13. struct Dim { dim_t len, step; };
  14. inline std::ostream & operator<<(std::ostream & o, Dim const & dim)
  15. { o << "[Dim " << dim.len << " " << dim.step << "]"; return o; }
  16. // --------------------
  17. // Develop indices for Big
  18. // --------------------
  19. namespace indexer1 {
  20. template <class Dimv, class P>
  21. constexpr dim_t
  22. shorter(Dimv const & dimv, P && p)
  23. {
  24. RA_CHECK(ssize(dimv)>=start(p).len(0), "Too many indices.");
  25. // use dim.data() to skip the size check.
  26. dim_t c = 0;
  27. for_each([&c](auto && d, auto && p) { RA_CHECK(inside(p, d.len)); c += d.step*p; },
  28. ptr(dimv.data()), p);
  29. return c;
  30. }
  31. // for rank matching on rank<driving rank, no slicing. TODO Static check?
  32. template <class Dimv, class P>
  33. constexpr dim_t
  34. longer(rank_t framer, Dimv const & dimv, P const & p)
  35. {
  36. RA_CHECK(framer<=ssize(p), "Too few indices.");
  37. dim_t c = 0;
  38. for (rank_t k=0; k<framer; ++k) {
  39. RA_CHECK(inside(p[k], dimv[k].len) || (dimv[k].len==DIM_BAD && dimv[k].step==0));
  40. c += dimv[k].step * p[k];
  41. }
  42. return c;
  43. }
  44. } // namespace indexer1
  45. // --------------------
  46. // Big iterator
  47. // --------------------
  48. // TODO Refactor with CellSmall. Take iterator like Ptr does and View should, not raw pointers
  49. // TODO Clear up Dimv's type. Should I use span/Ptr?
  50. template <class T, rank_t RANK=RANK_ANY> struct View;
  51. // V is View. FIXME Parameterize? apparently only for order-of-decl.
  52. template <class V, rank_t cellr_spec=0>
  53. struct CellBig
  54. {
  55. static_assert(cellr_spec!=RANK_ANY && cellr_spec!=RANK_BAD, "Bad cell rank.");
  56. constexpr static rank_t fullr = ra::rank_s<V>();
  57. constexpr static rank_t cellr = dependent_cell_rank(fullr, cellr_spec);
  58. constexpr static rank_t framer = dependent_frame_rank(fullr, cellr_spec);
  59. static_assert(cellr>=0 || cellr==RANK_ANY, "Bad cell rank.");
  60. static_assert(framer>=0 || framer==RANK_ANY, "Bad frame rank.");
  61. static_assert(fullr==cellr || gt_rank(fullr, cellr), "Bad cell rank.");
  62. using Dimv_ = typename std::decay_t<V>::Dimv;
  63. // FIXME necessary to support some cases of from() [ra14]. But cf https://stackoverflow.com/a/8609226
  64. using Dimv = std::conditional_t<std::is_lvalue_reference_v<V>, Dimv_ const &, Dimv_>;
  65. Dimv dimv;
  66. using atom_type = std::remove_reference_t<decltype(*(std::declval<V>().data()))>;
  67. using cell_type = View<atom_type, cellr>;
  68. using value_type = std::conditional_t<0==cellr, atom_type, cell_type>;
  69. cell_type c;
  70. constexpr CellBig(CellBig const & ci): dimv(ci.dimv), c { ci.c.dimv, ci.c.p } {}
  71. // s_ is array's full shape; split it into dimv/i (frame) and c (cell).
  72. constexpr CellBig(Dimv const & dimv_, atom_type * p_): dimv(dimv_)
  73. {
  74. // see stl_iterator for the case of dimv_[0]=0, etc. [ra12].
  75. c.p = p_;
  76. rank_t cellr = dependent_cell_rank(ssize(dimv), cellr_spec);
  77. rank_t rank = this->rank();
  78. if constexpr (RANK_ANY==framer) {
  79. RA_CHECK(rank>=0, "bad cell rank (array rank ", ssize(dimv), ", cell rank ", cellr, ").");
  80. }
  81. resize(c.dimv, cellr);
  82. for (int k=0; k<cellr; ++k) {
  83. c.dimv[k] = dimv_[rank+k];
  84. }
  85. }
  86. RA_DEF_ASSIGNOPS_DEFAULT_SET
  87. constexpr static rank_t rank_s() { return framer; }
  88. constexpr rank_t rank() const { return dependent_frame_rank(ssize(dimv), cellr_spec); }
  89. constexpr static rank_t rank() requires (framer!=DIM_ANY) { return framer; }
  90. constexpr static dim_t len_s(int i) { /* RA_CHECK(inside(k, rank())); */ return DIM_ANY; }
  91. constexpr dim_t len(int k) const { RA_CHECK(inside(k, rank())); return dimv[k].len; }
  92. constexpr dim_t step(int k) const { return k<rank() ? dimv[k].step : 0; }
  93. constexpr bool keep_step(dim_t st, int z, int j) const { return st*step(z)==step(j); }
  94. constexpr void adv(rank_t k, dim_t d) { c.p += step(k)*d; }
  95. constexpr auto
  96. flat() const
  97. {
  98. if constexpr (0==cellr) {
  99. return c.p;
  100. } else {
  101. return CellFlat<cell_type> { c };
  102. }
  103. }
  104. constexpr decltype(auto)
  105. at(auto const & i) const
  106. {
  107. if constexpr (0==cellr) {
  108. return c.p[indexer1::longer(rank(), dimv, i)];
  109. } else {
  110. return cell_type { c.dimv, c.p + indexer1::longer(rank(), dimv, i) };
  111. }
  112. }
  113. };
  114. // --------------------
  115. // nested braces for Container initializers
  116. // --------------------
  117. // Avoid clash of T with scalar constructors (for rank 0).
  118. template <class T, rank_t rank>
  119. struct nested_braces { using list = no_arg; };
  120. template <class T, rank_t rank>
  121. requires (rank==1)
  122. struct nested_braces<T, rank>
  123. {
  124. using list = std::initializer_list<T>;
  125. template <std::size_t N>
  126. constexpr static
  127. void shape(list l, std::array<dim_t, N> & s)
  128. {
  129. static_assert(N>0);
  130. s[N-1] = l.size();
  131. }
  132. };
  133. template <class T, rank_t rank>
  134. requires (rank>1)
  135. struct nested_braces<T, rank>
  136. {
  137. using sub = nested_braces<T, rank-1>;
  138. using list = std::initializer_list<typename sub::list>;
  139. template <std::size_t N>
  140. constexpr static
  141. void shape(list l, std::array<dim_t, N> & s)
  142. {
  143. s[N-rank] = l.size();
  144. if (l.size()>0) {
  145. sub::template shape(*(l.begin()), s);
  146. } else {
  147. std::fill(s.begin()+N-rank+1, s.end(), 0);
  148. }
  149. }
  150. };
  151. // --------------------
  152. // Indexing views
  153. // --------------------
  154. // raw <- shared; raw <- unique; shared <- unique.
  155. // layout is
  156. // [data] (fixed shape)
  157. // [size] p -> [data...] (fixed rank)
  158. // [rank] [size...] p -> [data...] (var rank)
  159. // TODO size is immutable so that it can be kept together with rank.
  160. constexpr dim_t
  161. select(Dim * dim, Dim const * dim_src, dim_t i)
  162. {
  163. RA_CHECK(inside(i, dim_src->len), " i ", i, " len ", dim_src->len);
  164. return dim_src->step*i;
  165. }
  166. template <class I> requires (is_iota<I>)
  167. constexpr dim_t
  168. select(Dim * dim, Dim const * dim_src, I i)
  169. {
  170. RA_CHECK((inside(i.i, dim_src->len) && inside(i.i+(i.n-1)*i.gets(), dim_src->len))
  171. || (i.n==0 && i.i<=dim_src->len));
  172. *dim = { .len = i.n, .step = dim_src->step * i.gets() };
  173. return dim_src->step*i.i;
  174. }
  175. template <class I0, class ... I>
  176. constexpr dim_t
  177. select_loop(Dim * dim, Dim const * dim_src, I0 && i0, I && ... i)
  178. {
  179. return select(dim, dim_src, std::forward<I0>(i0))
  180. + select_loop(dim+is_beatable<I0>::skip, dim_src+is_beatable<I0>::skip_src, std::forward<I>(i) ...);
  181. }
  182. template <int n, class ... I>
  183. constexpr dim_t
  184. select_loop(Dim * dim, Dim const * dim_src, dots_t<n> dots, I && ... i)
  185. {
  186. for (Dim * end = dim+n; dim!=end; ++dim, ++dim_src) {
  187. *dim = *dim_src;
  188. }
  189. return select_loop(dim, dim_src, std::forward<I>(i) ...);
  190. }
  191. template <int n, class ... I>
  192. constexpr dim_t
  193. select_loop(Dim * dim, Dim const * dim_src, insert_t<n> insert, I && ... i)
  194. {
  195. for (Dim * end = dim+n; dim!=end; ++dim) {
  196. *dim = { .len = DIM_BAD, .step = 0 };
  197. }
  198. return select_loop(dim, dim_src, std::forward<I>(i) ...);
  199. }
  200. constexpr dim_t
  201. select_loop(Dim * dim, Dim const * dim_src)
  202. {
  203. return 0;
  204. }
  205. // --------------------
  206. // View
  207. // --------------------
  208. // TODO Parameterize on Child having .data() so that there's only one pointer.
  209. // TODO Parameterize on iterator type not on value type.
  210. // TODO A constructor, if only for RA_CHECK (nonnegative lens, steps inside, etc.)
  211. template <class T, rank_t RANK>
  212. struct View
  213. {
  214. using Dimv = std::conditional_t<RANK==RANK_ANY, std::vector<Dim>, Small<Dim, RANK==RANK_ANY ? 0 : RANK>>;
  215. Dimv dimv;
  216. T * p;
  217. template <class S>
  218. constexpr dim_t
  219. filldim(S && s)
  220. {
  221. for_each([](Dim & dim, auto && s) { dim.len = s; RA_CHECK(dim.len>=0, "Bad len ", dim.len); },
  222. dimv, s);
  223. dim_t next = 1;
  224. for (int i=dimv.size(); --i>=0;) {
  225. dimv[i].step = next;
  226. next *= dimv[i].len;
  227. }
  228. return next;
  229. }
  230. constexpr static rank_t rank_s() { return RANK; };
  231. constexpr static rank_t rank() requires (RANK!=RANK_ANY) { return RANK; }
  232. constexpr rank_t rank() const requires (RANK==RANK_ANY) { return rank_t(dimv.size()); }
  233. constexpr static dim_t len_s(int j) { return DIM_ANY; }
  234. constexpr dim_t len(int j) const { RA_CHECK(inside(j, rank())); return dimv[j].len; }
  235. constexpr dim_t step(int j) const { RA_CHECK(inside(j, rank())); return dimv[j].step; }
  236. constexpr auto data() const { return p; }
  237. constexpr dim_t size() const { return prod(map(&Dim::len, dimv)); }
  238. // FIXME Used by Big::init(). View can be a deduced type (e.g. from value_t<X>)
  239. constexpr View(): p() {}
  240. constexpr View(Dimv const & dimv_, T * p_): dimv(dimv_), p(p_) {} // [ra36]
  241. template <class SS>
  242. constexpr View(SS && s, T * p_): p(p_)
  243. {
  244. ra::resize(dimv, start(s).len(0)); // [ra37]
  245. if constexpr (std::is_convertible_v<value_t<SS>, Dim>) {
  246. start(dimv) = s;
  247. } else {
  248. filldim(s);
  249. }
  250. }
  251. constexpr View(std::initializer_list<dim_t> s, T * p_): View(start(s), p_) {}
  252. // [ra38] [ra34] and RA_DEF_ASSIGNOPS_SELF
  253. View(View && x) = default;
  254. View(View const & x) = default;
  255. View & operator=(View && x) { ra::start(*this) = x; return *this; }
  256. View & operator=(View const & x) { ra::start(*this) = x; return *this; }
  257. #define DEF_ASSIGNOPS(OP) \
  258. template <class X> View & operator OP (X && x) { ra::start(*this) OP x; return *this; }
  259. FOR_EACH(DEF_ASSIGNOPS, =, *=, +=, -=, /=)
  260. #undef DEF_ASSIGNOPS
  261. // array type is not deduced by X &&.
  262. constexpr View &
  263. operator=(typename nested_braces<T, RANK>::list x)
  264. {
  265. ra::iter<-1>(*this) = x;
  266. return *this;
  267. }
  268. // braces row-major ravel for rank!=1
  269. using ravel_arg = std::conditional_t<RANK==1, no_arg, std::initializer_list<T>>;
  270. View & operator=(ravel_arg const x)
  271. {
  272. RA_CHECK(p && size()==ssize(x), "bad assignment");
  273. std::copy(x.begin(), x.end(), begin());
  274. return *this;
  275. }
  276. constexpr bool const empty() const { return 0==size(); } // TODO Optimize
  277. template <rank_t c=0> constexpr auto iter() const && { return ra::CellBig<View<T, RANK>, c>(std::move(dimv), p); }
  278. template <rank_t c=0> constexpr auto iter() const & { return ra::CellBig<View<T, RANK> &, c>(dimv, p); }
  279. constexpr auto begin() const { return stl_iterator(iter()); }
  280. constexpr auto end() const { return stl_iterator(decltype(iter())(dimv, nullptr)); } // dimv could be anything
  281. // Specialize for rank() integer-args -> scalar, same in ra::SmallBase in small.hh.
  282. template <class ... I>
  283. constexpr decltype(auto)
  284. operator()(I && ... i) const
  285. {
  286. constexpr int scalars = (0 + ... + is_scalar_index<I>);
  287. if constexpr (scalars<RANK && (is_beatable<I>::value && ...)) {
  288. constexpr rank_t extended = (0 + ... + (is_beatable<I>::skip-is_beatable<I>::skip_src));
  289. constexpr rank_t subrank = rank_sum(RANK, extended);
  290. static_assert(subrank>=0, "Bad subrank.");
  291. View<T, subrank> sub;
  292. sub.p = data() + select_loop(sub.dimv.data(), dimv.data(), i ...);
  293. // fill the rest of dim, skipping over beatable subscripts
  294. for (int i=(0 + ... + is_beatable<I>::skip); i<subrank; ++i) {
  295. sub.dimv[i] = dimv[i-extended];
  296. }
  297. return sub;
  298. } else if constexpr (scalars==RANK) {
  299. return data()[select_loop(nullptr, dimv.data(), i ...)];
  300. // return a rank 0 view, and rely on conversion if it ends up assigned to a scalar.
  301. } else if constexpr ((is_beatable<I>::value && ...) && RANK==RANK_ANY) {
  302. constexpr rank_t extended = (0 + ... + (is_beatable<I>::skip-is_beatable<I>::skip_src));
  303. RA_CHECK(rank()+extended>=0, "bad rank");
  304. View<T, RANK_ANY> sub;
  305. sub.dimv.resize(rank()+extended);
  306. sub.p = data() + select_loop(sub.dimv.data(), dimv.data(), i ...);
  307. for (int i=(0 + ... + is_beatable<I>::skip); i<sub.rank(); ++i) {
  308. sub.dimv[i] = dimv[i-extended];
  309. }
  310. return sub;
  311. // TODO > 1 selector... This still covers (unbeatable, integer) for example, which could be reduced.
  312. } else if constexpr (!(is_beatable<I>::value && ...)) {
  313. return from(*this, std::forward<I>(i) ...);
  314. } else {
  315. static_assert(mp::always_false<I ...>); // p2593r0
  316. }
  317. }
  318. template <class I>
  319. constexpr decltype(auto)
  320. at(I && i) const
  321. {
  322. if constexpr (RANK_ANY!=RANK) {
  323. constexpr rank_t subrank = rank_diff(RANK, ra::size_s<I>());
  324. using Sub = View<T, subrank>;
  325. if constexpr (RANK_ANY==subrank) {
  326. return Sub { typename Sub::Dimv(dimv.begin()+ra::size(i), dimv.end()), // Dimv is std::vector
  327. data() + indexer1::shorter(dimv, i) };
  328. } else if constexpr (subrank>0) {
  329. return Sub { typename Sub::Dimv(ptr(dimv.begin()+ra::size(i))), // Dimv is ra::Small
  330. data() + indexer1::shorter(dimv, i) };
  331. } else {
  332. return data()[indexer1::shorter(dimv, i)];
  333. }
  334. } else {
  335. return View<T, RANK_ANY> { Dimv(dimv.begin()+i.size(), dimv.end()), // Dimv is std::vector
  336. data() + indexer1::shorter(dimv, i) };
  337. }
  338. }
  339. template <class ... I>
  340. constexpr decltype(auto)
  341. operator[](I && ... i) const
  342. {
  343. return (*this)(std::forward<I>(i) ...);
  344. }
  345. // conversion to scalar.
  346. constexpr
  347. operator T & () const
  348. {
  349. if constexpr (RANK_ANY==RANK) {
  350. RA_CHECK(rank()==0, "Error converting rank ", rank(), " to scalar.");
  351. } else {
  352. static_assert(0==RANK, "Bad rank for conversion to scalar.");
  353. }
  354. return data()[0];
  355. }
  356. // necessary here per [ra15] (?)
  357. constexpr operator T & () { return std::as_const(*this); }
  358. // conversions from var rank to fixed rank
  359. template <rank_t R> requires (R==RANK_ANY && R!=RANK)
  360. constexpr View(View<T, R> const & x): dimv(x.dimv), p(x.p) {}
  361. template <rank_t R> requires (R==RANK_ANY && R!=RANK && std::is_const_v<T>)
  362. constexpr View(View<std::remove_const_t<T>, R> const & x): dimv(x.dimv), p(x.p) {}
  363. // conversion from fixed rank to var rank
  364. template <rank_t R> requires (R!=RANK_ANY && RANK==RANK_ANY)
  365. constexpr View(View<T, R> const & x): dimv(x.dimv.begin(), x.dimv.end()), p(x.p) {}
  366. template <rank_t R> requires (R!=RANK_ANY && RANK==RANK_ANY && std::is_const_v<T>)
  367. constexpr View(View<std::remove_const_t<T>, R> const & x): dimv(x.dimv.begin(), x.dimv.end()), p(x.p) {}
  368. // conversion to const. We rely on it for Container::view().
  369. // FIXME probably illegal, and doesn't work for SmallBase. Need another way.
  370. constexpr
  371. operator View<T const, RANK> const & () const requires (!std::is_const_v<T>)
  372. {
  373. return *reinterpret_cast<View<T const, RANK> const *>(this);
  374. }
  375. };
  376. // --------------------
  377. // Container types
  378. // --------------------
  379. template <class V>
  380. struct storage_traits
  381. {
  382. using T = std::decay_t<decltype(*std::declval<V>().get())>;
  383. constexpr static V create(dim_t n) { RA_CHECK(n>=0); return V(new T[n]); }
  384. constexpr static T const * data(V const & v) { return v.get(); }
  385. constexpr static T * data(V & v) { return v.get(); }
  386. };
  387. template <class P>
  388. struct storage_traits<std::shared_ptr<P>>
  389. {
  390. using V = std::shared_ptr<P>;
  391. using T = std::decay_t<decltype(*std::declval<V>().get())>;
  392. constexpr static V create(dim_t n) { RA_CHECK(n>=0); return V(new T[n], std::default_delete<T[]>()); }
  393. constexpr static T const * data(V const & v) { return v.get(); }
  394. constexpr static T * data(V & v) { return v.get(); }
  395. };
  396. template <class T_, class A>
  397. struct storage_traits<std::vector<T_, A>>
  398. {
  399. using T = T_;
  400. static_assert(!std::is_same_v<std::remove_const_t<T>, bool>, "No pointers to bool in std::vector<bool>.");
  401. constexpr static std::vector<T, A> create(dim_t n) { return std::vector<T, A>(n); }
  402. constexpr static T const * data(std::vector<T, A> const & v) { return v.data(); }
  403. constexpr static T * data(std::vector<T, A> & v) { return v.data(); }
  404. };
  405. template <class T, rank_t RANK>
  406. constexpr bool
  407. is_c_order(View<T, RANK> const & a)
  408. {
  409. dim_t s = 1;
  410. for (int i=a.rank()-1; i>=0; --i) {
  411. if (s!=a.step(i)) {
  412. return false;
  413. }
  414. s *= a.len(i);
  415. if (s==0) {
  416. return true;
  417. }
  418. }
  419. return true;
  420. }
  421. // FIXME avoid duplicating View::p
  422. template <class Store, rank_t RANK>
  423. struct Container: public View<typename storage_traits<Store>::T, RANK>
  424. {
  425. Store store;
  426. using T = typename storage_traits<Store>::T;
  427. using View = ra::View<T, RANK>;
  428. using ViewConst = ra::View<T const, RANK>;
  429. using View::rank_s;
  430. using shape_arg = decltype(ra::shape(std::declval<View>().iter()));
  431. constexpr View & view() { return *this; }
  432. constexpr ViewConst const & view() const { return static_cast<View const &>(*this); }
  433. // Needed to set View::p. FIXME Remove duplication as in SmallBase/SmallArray, then remove the constructors and the assignment operators.
  434. Container(Container && w): store(std::move(w.store))
  435. {
  436. View::dimv = std::move(w.dimv);
  437. View::p = storage_traits<Store>::data(store);
  438. }
  439. Container(Container const & w): store(w.store)
  440. {
  441. View::dimv = w.dimv;
  442. View::p = storage_traits<Store>::data(store);
  443. }
  444. Container(Container & w): store(w.store)
  445. {
  446. View::dimv = w.dimv;
  447. View::p = storage_traits<Store>::data(store);
  448. }
  449. // override View::operator= to allow initialization-of-reference. Unfortunately operator>>(std::istream &, Container &) requires it. The presence of these operator= means that A(shape 2 3) = type-of-A [1 2 3] initializes so it doesn't behave as A(shape 2 3) = not-type-of-A [1 2 3] which will use View::operator= and frame match. See test/ownership.cc [ra20].
  450. // TODO do this through .set() op.
  451. // TODO don't require copiable T from constructors, see fill1 below. That requires initialization and not update semantics for operator=.
  452. Container & operator=(Container && w)
  453. {
  454. store = std::move(w.store);
  455. View::dimv = std::move(w.dimv);
  456. View::p = storage_traits<Store>::data(store);
  457. return *this;
  458. }
  459. Container & operator=(Container const & w)
  460. {
  461. store = w.store;
  462. View::dimv = w.dimv;
  463. View::p = storage_traits<Store>::data(store);
  464. return *this;
  465. }
  466. Container & operator=(Container & w)
  467. {
  468. store = w.store;
  469. View::dimv = w.dimv;
  470. View::p = storage_traits<Store>::data(store);
  471. return *this;
  472. }
  473. // provided so that {} calls shape_arg constructor below.
  474. Container()
  475. {
  476. if constexpr (RANK_ANY==RANK) {
  477. // rank 1 to avoid store init
  478. View::dimv = { Dim {0, 1} };
  479. } else if constexpr (0==RANK) {
  480. // cannot have zero size
  481. store = storage_traits<Store>::create(1);
  482. View::p = storage_traits<Store>::data(store);
  483. } else {
  484. for (Dim & dimi: View::dimv) { dimi = {0, 1}; } // 1 so we can push_back()
  485. }
  486. }
  487. template <class S>
  488. requires (1==ra::rank_s<S>() || RANK_ANY==ra::rank_s<S>())
  489. void
  490. init(S && s)
  491. {
  492. static_assert(!std::is_convertible_v<value_t<S>, Dim>);
  493. RA_CHECK(1==ra::rank(s), "Rank mismatch for init shape.");
  494. // [ra37] Dimv might be STL type. Otherwise I'd just View::dimv.set(map(...)).
  495. if constexpr (RANK_ANY==RANK) {
  496. ra::resize(View::dimv, ra::size(s));
  497. } else if constexpr (DIM_ANY==ra::size_s<S>()) {
  498. RA_CHECK(RANK==ra::size(s), "Bad shape [", ra::noshape, s, "] for rank ", RANK, ".");
  499. } else {
  500. static_assert(RANK==ra::size_s<S>() || DIM_BAD==ra::size_s<S>(), "Invalid shape for rank.");
  501. }
  502. store = storage_traits<Store>::create(View::filldim(s));
  503. View::p = storage_traits<Store>::data(store);
  504. }
  505. void init(ra::dim_t s) { init(std::array {s}); } // scalar allowed as shape if rank is 1.
  506. // FIXME use of fill1 requires T to be copiable, this is unfortunate as it conflicts with the semantics of view_.operator=.
  507. // store(x) avoids it for Big, but doesn't work for Unique. Should construct in place like std::vector does.
  508. template <class Pbegin> constexpr void
  509. fill1(dim_t xsize, Pbegin xbegin)
  510. {
  511. RA_CHECK(this->size()==xsize, "Mismatched sizes ", this->size(), " and ", xsize, ".");
  512. std::copy_n(xbegin, xsize, begin()); // TODO Use xpr traversal.
  513. }
  514. // shape_arg overloads handle {...} arguments. Size check is at conversion (if shape_arg is Small) or init().
  515. // explicit shape.
  516. Container(shape_arg const & s, none_t)
  517. {
  518. init(s);
  519. }
  520. template <class XX>
  521. Container(shape_arg const & s, XX && x): Container(s, none)
  522. {
  523. view() = x;
  524. }
  525. // shape from data.
  526. template <class XX>
  527. Container(XX && x): Container(ra::shape(x), none)
  528. {
  529. view() = x;
  530. }
  531. Container(typename nested_braces<T, RANK>::list x)
  532. {
  533. std::array<dim_t, RANK> s;
  534. nested_braces<T, RANK>::template shape(x, s);
  535. init(s);
  536. view() = x;
  537. }
  538. // for RANK_ANY from rank 1. FIXME higher ranks don't work; must give shape.
  539. Container(typename View::ravel_arg x)
  540. : Container(x.size(), x) {}
  541. // shape + row-major ravel. // TODO Maybe remove these? See also small.hh.
  542. Container(shape_arg const & s, std::initializer_list<T> x)
  543. : Container(s, none) { fill1(x.size(), x.begin()); }
  544. template <class TT>
  545. Container(shape_arg const & s, TT * p)
  546. : Container(s, none) { fill1(this->size(), p); }
  547. template <class P>
  548. Container(shape_arg const & s, P pbegin, P pend)
  549. : Container(s, none) { fill1(this->size(), pbegin); }
  550. // needed when shape_arg is std::vector, since that doesn't handle conversions like Small does.
  551. template <class SS>
  552. Container(SS && s, none_t) { init(std::forward<SS>(s)); }
  553. template <class SS, class XX>
  554. Container(SS && s, XX && x)
  555. : Container(std::forward<SS>(s), none) { view() = x; }
  556. template <class SS>
  557. Container(SS && s, std::initializer_list<T> x)
  558. : Container(std::forward<SS>(s), none) { fill1(x.size(), x.begin()); }
  559. using View::operator=;
  560. // resize first axis. Only for some kinds of store.
  561. void resize(dim_t const s)
  562. {
  563. static_assert(RANK==RANK_ANY || RANK>0); RA_CHECK(this->rank()>0);
  564. View::dimv[0].len = s;
  565. store.resize(View::size());
  566. View::p = store.data();
  567. }
  568. void resize(dim_t const s, T const & t)
  569. {
  570. static_assert(RANK==RANK_ANY || RANK>0); RA_CHECK(this->rank()>0);
  571. View::dimv[0].len = s;
  572. store.resize(View::size(), t);
  573. View::p = store.data();
  574. }
  575. // resize full shape. Only for some kinds of store.
  576. template <class S>
  577. requires (ra::rank_s<S>() > 0)
  578. void resize(S const & s)
  579. {
  580. ra::resize(View::dimv, start(s).len(0)); // [ra37] FIXME is View constructor
  581. store.resize(View::filldim(s));
  582. View::p = store.data();
  583. }
  584. // lets us move. A template + std::forward wouldn't work for push_back(brace-enclosed-list).
  585. void push_back(T && t)
  586. {
  587. static_assert(RANK==1 || RANK==RANK_ANY); RA_CHECK(this->rank()==1);
  588. store.push_back(std::move(t));
  589. ++View::dimv[0].len;
  590. View::p = store.data();
  591. }
  592. void push_back(T const & t)
  593. {
  594. static_assert(RANK==1 || RANK==RANK_ANY); RA_CHECK(this->rank()==1);
  595. store.push_back(t);
  596. ++View::dimv[0].len;
  597. View::p = store.data();
  598. }
  599. template <class ... A>
  600. void emplace_back(A && ... a)
  601. {
  602. static_assert(RANK==1 || RANK==RANK_ANY); RA_CHECK(this->rank()==1);
  603. store.emplace_back(std::forward<A>(a) ...);
  604. ++View::dimv[0].len;
  605. View::p = store.data();
  606. }
  607. void pop_back()
  608. {
  609. static_assert(RANK==1 || RANK==RANK_ANY); RA_CHECK(this->rank()==1);
  610. RA_CHECK(View::dimv[0].len>0);
  611. store.pop_back();
  612. --View::dimv[0].len;
  613. }
  614. constexpr bool empty() const { return 0==this->size(); }
  615. constexpr T const & back() const { RA_CHECK(this->rank()==1 && this->size()>0); return store[this->size()-1]; }
  616. constexpr T & back() { RA_CHECK(this->rank()==1 && this->size()>0); return store[this->size()-1]; }
  617. // FIXME P0847R7 https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_parameter
  618. template <class ... A> constexpr decltype(auto) operator()(A && ... a) { return view()(std::forward<A>(a) ...); }
  619. template <class ... A> constexpr decltype(auto) operator()(A && ... a) const { return view()(std::forward<A>(a) ...); }
  620. template <class ... A> constexpr decltype(auto) operator[](A && ... a) { return view()(std::forward<A>(a) ...); }
  621. template <class ... A> constexpr decltype(auto) operator[](A && ... a) const { return view()(std::forward<A>(a) ...); }
  622. constexpr auto data() { return view().data(); }
  623. constexpr auto data() const { return view().data(); }
  624. template <rank_t c=0> constexpr auto iter() { return view().template iter<c>(); }
  625. template <rank_t c=0> constexpr auto iter() const { return view().template iter<c>(); }
  626. template <class I> constexpr decltype(auto) at(I && i) { return view().at(std::forward<I>(i)); }
  627. template <class I> constexpr decltype(auto) at(I && i) const { return view().at(std::forward<I>(i)); }
  628. constexpr operator T & () { return view(); }
  629. constexpr operator T const & () const { return view(); }
  630. // Container is always compact/row-major, so STL-like iterators can be raw pointers. TODO But .iter() should also be able to benefit from this constraint, and the check should be faster for some cases (like RANK==1).
  631. constexpr auto begin() { assert(is_c_order(*this)); return view().data(); }
  632. constexpr auto begin() const { assert(is_c_order(*this)); return view().data(); }
  633. constexpr auto end() { return view().data()+this->size(); }
  634. constexpr auto end() const { return view().data()+this->size(); }
  635. };
  636. template <class Store, rank_t RANKA, rank_t RANKB>
  637. requires (RANKA!=RANKB) // rely on std::swap; else ambiguous
  638. void
  639. swap(Container<Store, RANKA> & a, Container<Store, RANKB> & b)
  640. {
  641. if constexpr (RANK_ANY==RANKA) {
  642. RA_CHECK(a.rank()==b.rank());
  643. decltype(b.dimv) c = a.dimv;
  644. start(a.dimv) = b.dimv;
  645. std::swap(b.dimv, c);
  646. } else if constexpr (RANK_ANY==RANKB) {
  647. RA_CHECK(a.rank()==b.rank());
  648. decltype(a.dimv) c = b.dimv;
  649. start(b.dimv) = a.dimv;
  650. std::swap(a.dimv, c);
  651. } else {
  652. static_assert(RANKA==RANKB);
  653. std::swap(a.dimv, b.dimv);
  654. }
  655. std::swap(a.store, b.store);
  656. std::swap(a.p, b.p);
  657. }
  658. // Default storage for Big - see https://stackoverflow.com/a/21028912
  659. // Allocator adaptor that interposes construct() calls to convert value initialization into default initialization.
  660. template <typename T, typename A=std::allocator<T>>
  661. struct default_init_allocator: public A
  662. {
  663. using a_t = std::allocator_traits<A>;
  664. using A::A;
  665. template <typename U>
  666. struct rebind
  667. {
  668. using other = default_init_allocator<U, typename a_t::template rebind_alloc<U>>;
  669. };
  670. template <typename U>
  671. void construct(U * ptr) noexcept(std::is_nothrow_default_constructible<U>::value)
  672. {
  673. ::new(static_cast<void *>(ptr)) U;
  674. }
  675. template <typename U, typename... Args>
  676. void construct(U * ptr, Args &&... args)
  677. {
  678. a_t::construct(static_cast<A &>(*this), ptr, std::forward<Args>(args)...);
  679. }
  680. };
  681. // Beyond this, we probably should have fixed-size (~std::dynarray), resizeable (~std::vector).
  682. template <class T, rank_t RANK=RANK_ANY> using Big = Container<std::vector<T, default_init_allocator<T>>, RANK>;
  683. template <class T, rank_t RANK=RANK_ANY> using Unique = Container<std::unique_ptr<T []>, RANK>;
  684. template <class T, rank_t RANK=RANK_ANY> using Shared = Container<std::shared_ptr<T>, RANK>;
  685. // -------------
  686. // Used in the Guile wrappers to allow an array parameter to either borrow from Guile storage or convert into a new array (e.g. passing 'f32 into 'f64).
  687. // TODO Can use unique_ptr's deleter for this?
  688. // TODO Shared/Unique should maybe have constructors with unique_ptr/shared_ptr args
  689. // -------------
  690. template <rank_t RANK, class T>
  691. Shared<T, RANK> shared_borrowing(View<T, RANK> & raw)
  692. {
  693. Shared<T, RANK> a;
  694. a.dimv = raw.dimv;
  695. a.p = raw.p;
  696. a.store = std::shared_ptr<T>(raw.data(), [](T *) {});
  697. return a;
  698. }
  699. // --------------------
  700. // Obtain concrete type from array expression.
  701. // --------------------
  702. template <class E>
  703. struct concrete_type_def
  704. {
  705. using type = void;
  706. };
  707. template <class E>
  708. requires (size_s<E>()==DIM_ANY)
  709. struct concrete_type_def<E>
  710. {
  711. using type = Big<value_t<E>, rank_s<E>()>;
  712. };
  713. template <class E>
  714. requires (size_s<E>()!=DIM_ANY)
  715. struct concrete_type_def<E>
  716. {
  717. template <class I> struct T;
  718. template <int ... I> struct T<mp::int_list<I ...>>
  719. {
  720. using type = Small<value_t<E>, E::len_s(I) ...>;
  721. };
  722. using type = typename T<mp::iota<rank_s<E>()>>::type;
  723. };
  724. // Scalars are their own concrete_type. Treat unregistered types as scalars. FIXME (in bootstrap.hh).
  725. template <class E>
  726. using concrete_type = std::decay_t<
  727. std::conditional_t<
  728. (0==rank_s<E>() && !(requires { std::decay_t<E>::rank_s(); })) || is_scalar<E>,
  729. std::decay_t<E>,
  730. typename concrete_type_def<std::decay_t<decltype(start(std::declval<E>()))>>::type>
  731. >;
  732. template <class E>
  733. constexpr auto
  734. concrete(E && e)
  735. {
  736. return concrete_type<E>(std::forward<E>(e));
  737. }
  738. template <class E>
  739. constexpr auto
  740. with_same_shape(E && e)
  741. {
  742. if constexpr (size_s<concrete_type<E>>()!=DIM_ANY) {
  743. return concrete_type<E>();
  744. } else {
  745. return concrete_type<E>(ra::shape(e), ra::none);
  746. }
  747. }
  748. template <class E, class X>
  749. constexpr auto
  750. with_same_shape(E && e, X && x)
  751. {
  752. if constexpr (size_s<concrete_type<E>>()!=DIM_ANY) {
  753. return concrete_type<E>(std::forward<X>(x));
  754. } else {
  755. return concrete_type<E>(ra::shape(e), std::forward<X>(x));
  756. }
  757. }
  758. template <class E, class S, class X>
  759. constexpr auto
  760. with_shape(S && s, X && x)
  761. {
  762. if constexpr (size_s<concrete_type<E>>()!=DIM_ANY) {
  763. return concrete_type<E>(std::forward<X>(x));
  764. } else {
  765. return concrete_type<E>(std::forward<S>(s), std::forward<X>(x));
  766. }
  767. }
  768. template <class E, class S, class X>
  769. constexpr auto
  770. with_shape(std::initializer_list<S> && s, X && x)
  771. {
  772. if constexpr (size_s<concrete_type<E>>()!=DIM_ANY) {
  773. return concrete_type<E>(std::forward<X>(x));
  774. } else {
  775. return concrete_type<E>(s, std::forward<X>(x));
  776. }
  777. }
  778. } // namespace ra