big.H 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. // -*- mode: c++; coding: utf-8 -*-
  2. /// @file big.H
  3. /// @brief Arrays with dynamic size.
  4. // (c) Daniel Llorens - 2013-2014, 2017-2019
  5. // This library is free software; you can redistribute it and/or modify it under
  6. // the terms of the GNU Lesser General Public License as published by the Free
  7. // Software Foundation; either version 3 of the License, or (at your option) any
  8. // later version.
  9. #pragma once
  10. #include "ra/small.H"
  11. #include <memory>
  12. #include <iostream>
  13. #if defined(RA_CHECK_BOUNDS) && RA_CHECK_BOUNDS==0
  14. #define CHECK_BOUNDS( cond )
  15. #else
  16. #define CHECK_BOUNDS( cond ) RA_ASSERT( cond, 0 )
  17. #endif
  18. namespace ra {
  19. // Dope vector element
  20. struct Dim { dim_t size, stride; };
  21. // For debugging
  22. inline std::ostream & operator<<(std::ostream & o, Dim const & dim)
  23. { o << "[Dim " << dim.size << " " << dim.stride << "]"; return o; }
  24. // --------------------
  25. // nested braces for Container initializers
  26. // --------------------
  27. // Avoid clash of T with scalar constructors (for rank 0).
  28. template <class T, rank_t rank, class Enable=void>
  29. struct nested_braces { using list = no_arg; };
  30. template <class T, rank_t rank>
  31. struct nested_braces<T, rank, std::enable_if_t<(rank==1)>>
  32. {
  33. using list = std::initializer_list<T>;
  34. template <size_t N> constexpr static
  35. void shape(list l, std::array<dim_t, N> & s)
  36. {
  37. static_assert(N>0);
  38. s[N-1] = l.size();
  39. }
  40. };
  41. template <class T, rank_t rank>
  42. struct nested_braces<T, rank, std::enable_if_t<(rank>1)>>
  43. {
  44. using sub = nested_braces<T, rank-1>;
  45. using list = std::initializer_list<typename sub::list>;
  46. template <size_t N> constexpr static
  47. void shape(list l, std::array<dim_t, N> & s)
  48. {
  49. s[N-rank] = l.size();
  50. if (l.size()>0) {
  51. sub::template shape(*(l.begin()), s);
  52. } else {
  53. std::fill(s.begin()+N-rank+1, s.end(), 0);
  54. }
  55. }
  56. };
  57. // --------------------
  58. // Develop indices for Big
  59. // --------------------
  60. struct Indexer1
  61. {
  62. template <class Dim, class P>
  63. constexpr static dim_t index_p(Dim const & dim, P && p)
  64. {
  65. CHECK_BOUNDS(dim_t(dim.size())>=start(p).size(0) && "too many indices");
  66. // use dim.data() to skip the size check.
  67. dim_t c = 0;
  68. for_each([&c](auto && d, auto && p) { CHECK_BOUNDS(inside(p, d.size)); c += d.stride*p; },
  69. ptr(dim.data()), p);
  70. return c;
  71. }
  72. // used by cell_iterator::at() for rank matching on rank<driving rank, no slicing. TODO Static check.
  73. template <class Dim, class P>
  74. constexpr static dim_t index_short(rank_t framer, Dim const & dim, P const & p)
  75. {
  76. dim_t c = 0;
  77. for (rank_t k=0; k<framer; ++k) {
  78. CHECK_BOUNDS(inside(p[k], dim[k].size) || (dim[k].size==DIM_BAD && dim[k].stride==0));
  79. c += dim[k].stride * p[k];
  80. }
  81. return c;
  82. }
  83. };
  84. // --------------------
  85. // Big iterator
  86. // --------------------
  87. // TODO Refactor with cell_iterator_small for SmallView?
  88. // V is View. FIXME Parameterize? apparently only for order-of-decl.
  89. template <class V, rank_t cellr_=0>
  90. struct cell_iterator
  91. {
  92. constexpr static rank_t cellr_spec = cellr_;
  93. static_assert(cellr_spec!=RANK_ANY && cellr_spec!=RANK_BAD, "bad cell rank");
  94. constexpr static rank_t fullr = std::decay_t<V>::rank_s();
  95. constexpr static rank_t cellr = dependent_cell_rank(fullr, cellr_spec);
  96. constexpr static rank_t framer = dependent_frame_rank(fullr, cellr_spec);
  97. static_assert(cellr>=0 || cellr==RANK_ANY, "bad cell rank");
  98. static_assert(framer>=0 || framer==RANK_ANY, "bad frame rank");
  99. static_assert(fullr==cellr || gt_rank(fullr, cellr), "bad cell rank");
  100. using Dimv_ = typename std::decay_t<V>::Dimv;
  101. using Dimv = std::conditional_t<std::is_lvalue_reference_v<V>, Dimv_ const &, Dimv_>;
  102. Dimv dim;
  103. constexpr static rank_t rank_s() { return framer; }
  104. constexpr rank_t rank() const { return dependent_frame_rank(rank_t(dim.size()), cellr_spec); }
  105. using shape_type = std::conditional_t<rank_s()==DIM_ANY, std::vector<dim_t>,
  106. Small<dim_t, rank_s()==DIM_ANY ? 0 : rank_s()>>; // still needs protection :-/
  107. using atom_type = typename ra_traits<V>::value_type;
  108. using cell_type = View<atom_type, cellr>;
  109. using value_type = std::conditional_t<0==cellr, atom_type, cell_type>;
  110. cell_type c;
  111. constexpr cell_iterator(cell_iterator const & ci): dim(ci.dim), c { ci.c.dim, ci.c.p } {}
  112. // s_ is array's full shape; split it into dim/i (frame) and c (cell).
  113. constexpr cell_iterator(Dimv const & dim_, atom_type * p_): dim(dim_)
  114. {
  115. rank_t rank = this->rank();
  116. // see stl_iterator for the case of dim_[0]=0, etc. [ra12].
  117. c.p = p_;
  118. rank_t cellr = dependent_cell_rank(rank_t(dim.size()), cellr_spec);
  119. resize(c.dim, cellr);
  120. for (int k=0; k<cellr; ++k) {
  121. c.dim[k] = dim_[k+rank];
  122. }
  123. }
  124. constexpr static dim_t size_s(int i) { /* CHECK_BOUNDS(inside(k, rank())); */return DIM_ANY; }
  125. constexpr dim_t size(int k) const { CHECK_BOUNDS(inside(k, rank())); return dim[k].size; }
  126. constexpr dim_t stride(int k) const { return k<rank() ? dim[k].stride : 0; }
  127. // FIXME handle z or j over rank()? check cell_iterator_small versions.
  128. constexpr bool keep_stride(dim_t step, int z, int j) const { return step*stride(z)==stride(j); }
  129. constexpr void adv(rank_t k, dim_t d) { c.p += stride(k)*d; }
  130. constexpr auto flat() const
  131. {
  132. if constexpr (0==cellr) {
  133. return c.p;
  134. } else {
  135. return CellFlat<cell_type> { c };
  136. }
  137. }
  138. // Return type to allow either View & or View const & verb. Can't set self b/c original p isn't kept. TODO Think this over.
  139. template <class I>
  140. decltype(auto) at(I const & i_)
  141. {
  142. CHECK_BOUNDS(rank()<=dim_t(i_.size()) && "too few indices");
  143. if constexpr (0==cellr) {
  144. return c.p[Indexer1::index_short(rank(), dim, i_)];
  145. } else {
  146. return cell_type { c.dim, c.p+Indexer1::index_short(rank(), dim, i_) };
  147. }
  148. }
  149. #define DEF_ASSIGNOPS(OP) \
  150. template <class X> decltype(auto) operator OP(X && x) \
  151. { for_each([](auto && y, auto && x) { std::forward<decltype(y)>(y) OP x; }, *this, x); return *this; }
  152. FOR_EACH(DEF_ASSIGNOPS, =, *=, +=, -=, /=)
  153. #undef DEF_ASSIGNOPS
  154. };
  155. // --------------------
  156. // Indexing views
  157. // --------------------
  158. // Always C order. If you need another, transpose this.
  159. // Works on dim vector with sizes already assigned, so that I can work from an expr. Not pretty though.
  160. template <class D>
  161. dim_t filldim(int n, D dend)
  162. {
  163. dim_t next = 1;
  164. for (; n>0; --n) {
  165. --dend;
  166. CHECK_BOUNDS((*dend).size>=0 && "bad dim");
  167. (*dend).stride = next;
  168. next *= (*dend).size;
  169. }
  170. return next;
  171. }
  172. template <class D>
  173. dim_t proddim(D d, D dend)
  174. {
  175. dim_t t = 1;
  176. for (; d!=dend; ++d) {
  177. t *= (*d).size;
  178. }
  179. return t;
  180. }
  181. // raw <- shared; raw <- unique; shared <-- unique.
  182. // layout is
  183. // [data] (fixed shape)
  184. // [size] p -> [data...] (fixed rank)
  185. // [rank] [size...] p -> [data...] (var rank)
  186. // TODO size is immutable so that it can be kept together with rank.
  187. #define DEF_ITERATORS(RANK) \
  188. template <rank_t c=0> constexpr auto iter() && { return ra::cell_iterator<View<T, RANK>, c>(std::move(dim), p); } \
  189. template <rank_t c=0> constexpr auto iter() & { return ra::cell_iterator<View<T, RANK> &, c>(dim, p); } \
  190. template <rank_t c=0> constexpr auto iter() const & { return ra::cell_iterator<View<T const, RANK> &, c>(dim, p); } \
  191. constexpr auto begin() const { return stl_iterator(iter()); } \
  192. constexpr auto begin() { return stl_iterator(iter()); } \
  193. /* here dim doesn't matter, but we have to give it if it's a ref. */ \
  194. constexpr auto end() const { return stl_iterator(decltype(iter())(dim, nullptr)); } \
  195. constexpr auto end() { return stl_iterator(decltype(iter())(dim, nullptr)); }
  196. // See same thing for SmallBase.
  197. #define DEF_ASSIGNOPS(OP) \
  198. template <class X> View & operator OP (X && x) { ra::start(*this) OP x; return *this; }
  199. #define DEF_VIEW_COMMON(RANK) \
  200. FOR_EACH(DEF_ASSIGNOPS, =, *=, +=, -=, /=) \
  201. /* Constructors using pointers need extra care */ \
  202. /* constexpr */ /* triggers box/bug83.C in gcc 8.3 */ View(): p(nullptr) {} \
  203. View(Dimv const & dim_, T * p_): dim(dim_), p(p_) {} /* [ra36] */ \
  204. template <class SS> \
  205. View(SS && s, T * p_): p(p_) \
  206. { \
  207. if constexpr (std::is_convertible_v<value_t<SS>, Dim>) { \
  208. ra::resize(View::dim, start(s).size(0)); /* [ra37] */ \
  209. start(View::dim) = s; \
  210. } else { \
  211. auto w = map([](auto && s) { return Dim { ra::dim_t(s), 0 }; }, s); \
  212. ra::resize(View::dim, w.size(0)); /* [ra37] */ \
  213. start(View::dim) = w; \
  214. filldim(View::dim.size(), View::dim.end()); \
  215. } \
  216. } \
  217. View(std::initializer_list<dim_t> s, T * p_): View(start(s), p_) {} \
  218. /* lack of these causes runtime bug [ra38] FIXME why? */ \
  219. View(View && x) = default; \
  220. View(View const & x) = default; \
  221. /* declaring View(View &&) deletes this, so we need to repeat it [ra34] */ \
  222. View & operator=(View const & x) \
  223. { \
  224. ra::start(*this) = x; \
  225. return *this; \
  226. } \
  227. /* array type is not deduced by (X &&) */ \
  228. View & operator=(typename nested_braces<T, RANK>::list x) \
  229. { \
  230. ra::iter<-1>(*this) = x; \
  231. return *this; \
  232. } \
  233. /* braces row-major ravel for rank!=1 */ \
  234. using ravel_arg = std::conditional_t<RANK==1, no_arg, std::initializer_list<T>>; \
  235. View & operator=(ravel_arg const x) \
  236. { \
  237. CHECK_BOUNDS(p && this->size()==ra::dim_t(x.size()) && "bad assignment"); \
  238. std::copy(x.begin(), x.end(), this->begin()); \
  239. return *this; \
  240. } \
  241. bool const empty() const { return 0==size(); } /* TODO Optimize */
  242. inline dim_t select(Dim * dim, Dim const * dim_src, dim_t i)
  243. {
  244. CHECK_BOUNDS(inside(i, dim_src->size));
  245. return dim_src->stride*i;
  246. }
  247. template <class II>
  248. inline dim_t select(Dim * dim, Dim const * dim_src, ra::Iota<II> i)
  249. {
  250. CHECK_BOUNDS((inside(i.i_, dim_src->size) && inside(i.i_+(i.size_-1)*i.stride_, dim_src->size))
  251. || (i.size_==0 && i.i_<=dim_src->size));
  252. dim->size = i.size_;
  253. dim->stride = dim_src->stride * i.stride_;
  254. return dim_src->stride*i.i_;
  255. }
  256. template <class I0, class ... I>
  257. inline dim_t select_loop(Dim * dim, Dim const * dim_src, I0 && i0, I && ... i)
  258. {
  259. return select(dim, dim_src, std::forward<I0>(i0))
  260. + select_loop(dim+is_beatable<I0>::skip, dim_src+is_beatable<I0>::skip_src, std::forward<I>(i) ...);
  261. }
  262. template <int n, class ... I>
  263. inline dim_t select_loop(Dim * dim, Dim const * dim_src, dots_t<n> dots, I && ... i)
  264. {
  265. for (Dim * end = dim+n; dim!=end; ++dim, ++dim_src) {
  266. *dim = *dim_src;
  267. }
  268. return select_loop(dim, dim_src, std::forward<I>(i) ...);
  269. }
  270. template <int n, class ... I>
  271. inline dim_t select_loop(Dim * dim, Dim const * dim_src, insert_t<n> insert, I && ... i)
  272. {
  273. for (Dim * end = dim+n; dim!=end; ++dim) {
  274. dim->size = DIM_BAD;
  275. dim->stride = 0;
  276. }
  277. return select_loop(dim, dim_src, std::forward<I>(i) ...);
  278. }
  279. inline dim_t select_loop(Dim * dim, Dim const * dim_src)
  280. {
  281. return 0;
  282. }
  283. // allow conversion only from T to T const with null type.
  284. template <class T> using const_atom = std::conditional_t<std::is_const_v<T>, no_arg, T const>;
  285. // --------------------
  286. // View for fixed rank
  287. // --------------------
  288. // TODO Parameterize on Child having .data() so that there's only one pointer.
  289. // TODO A constructor, if only for CHECK_BOUNDS (positive sizes, strides inside, etc.)
  290. template <class T, rank_t RANK>
  291. struct View
  292. {
  293. using Dimv = Small<Dim, RANK>;
  294. Dimv dim;
  295. T * p;
  296. constexpr static rank_t rank_s() { return RANK; };
  297. constexpr static rank_t rank() { return RANK; }
  298. constexpr static dim_t size_s(int j) { return DIM_ANY; }
  299. constexpr dim_t size() const { return proddim(dim.begin(), dim.end()); }
  300. constexpr dim_t size(int j) const { return dim[j].size; }
  301. constexpr dim_t stride(int j) const { return dim[j].stride; }
  302. constexpr auto data() { return p; }
  303. constexpr auto data() const { return p; }
  304. // Specialize for rank() integer-args -> scalar, same in ra::SmallBase in small.H.
  305. #define SUBSCRIPTS(CONST) \
  306. template <class ... I, \
  307. std::enable_if_t<((0 + ... + std::is_integral_v<std::decay_t<I>>)<RANK \
  308. && (0 + ... + is_beatable<I>::value)==sizeof...(I)), int> = 0> \
  309. auto operator()(I && ... i) CONST \
  310. { \
  311. constexpr rank_t extended = (0 + ... + (is_beatable<I>::skip-is_beatable<I>::skip_src)); \
  312. constexpr rank_t subrank = rank_sum(RANK, extended); \
  313. static_assert(subrank>=0, "bad subrank"); \
  314. View<T CONST, subrank> sub; \
  315. sub.p = data() + select_loop(sub.dim.data(), this->dim.data(), i ...); \
  316. /* fill the rest of dim, skipping over beatable subscripts */ \
  317. for (int i=(0 + ... + is_beatable<I>::skip); i<subrank; ++i) { \
  318. sub.dim[i] = this->dim[i-extended]; \
  319. } \
  320. return sub; \
  321. } \
  322. /* BUG doesn't handle generic zero-rank indices */ \
  323. template <class ... I, std::enable_if_t<(0 + ... + std::is_integral_v<I>)==RANK, int> = 0> \
  324. decltype(auto) operator()(I const & ... i) CONST \
  325. { \
  326. return data()[select_loop(nullptr, this->dim.data(), i ...)]; \
  327. } \
  328. /* TODO > 1 selector... This still covers (unbeatable, integer) for example, which could be reduced. */ \
  329. template <class ... I, std::enable_if_t<!(is_beatable<I>::value && ...), int> = 0> \
  330. auto operator()(I && ... i) CONST \
  331. { \
  332. return from(*this, std::forward<I>(i) ...); \
  333. } \
  334. template <class I> \
  335. auto at(I && i) CONST \
  336. { \
  337. constexpr rank_t subrank = rank_diff(RANK, ra::size_s<I>()); /* gcc accepts i.size() */ \
  338. using Sub = View<T CONST, subrank>; \
  339. if constexpr (subrank==RANK_ANY) { \
  340. return Sub { typename Sub::Dimv(dim.begin()+ra::size(i), dim.end()), /* Dimv is std::vector */ \
  341. data() + Indexer1::index_p(dim, i) }; \
  342. } else { \
  343. return Sub { typename Sub::Dimv(ptr(dim.begin()+ra::size(i))), /* Dimv is ra::Small */ \
  344. data() + Indexer1::index_p(dim, i) }; \
  345. } \
  346. } \
  347. decltype(auto) operator[](dim_t const i) CONST \
  348. { \
  349. return (*this)(i); \
  350. }
  351. FOR_EACH(SUBSCRIPTS, /*const*/, const)
  352. #undef SUBSCRIPTS
  353. DEF_ITERATORS(RANK)
  354. DEF_VIEW_COMMON(RANK)
  355. // implicit conversions from var rank. The guards are needed against ambiguity in ra-viewconst branch.
  356. template <rank_t R, std::enable_if_t<R==RANK_ANY && R!=RANK, int> =0>
  357. View(View<T const, R> const & x): dim(x.dim), p(x.p) {}
  358. template <rank_t R, std::enable_if_t<R==RANK_ANY && R!=RANK, int> =0>
  359. View(View<std::remove_const_t<T>, R> const & x): dim(x.dim), p(x.p) {}
  360. // conversion to const from non const
  361. operator View<const_atom<T>, RANK> const & () const
  362. {
  363. return *reinterpret_cast<View<const_atom<T>, RANK> const *>(this);
  364. }
  365. // conversions to scalar. The static asserts fail due to a bug in gcc 8.2 [ra43]. Recheck on gcc 9.
  366. operator T & () { /* static_assert(RANK==0, "bad rank"); */ assert(RANK==0); return data()[0]; }
  367. operator T const & () const { /* static_assert(RANK==0, "bad rank"); */ assert(RANK==0); return data()[0]; }
  368. };
  369. template <class T, rank_t RANK>
  370. struct ra_traits_def<View<T, RANK>>
  371. {
  372. using V = View<T, RANK>;
  373. using value_type = T;
  374. static decltype(auto) shape(V const & v) { return ra::shape(v.iter()); }
  375. static dim_t size(V const & v) { return v.size(); }
  376. constexpr static rank_t rank(V const & v) { return v.rank(); }
  377. constexpr static rank_t rank_s() { return RANK; };
  378. constexpr static dim_t size_s() { return RANK==0 ? 1 : DIM_ANY; }
  379. };
  380. // --------------------
  381. // View for var rank
  382. // --------------------
  383. template <class T>
  384. struct View<T, RANK_ANY>
  385. {
  386. using Dimv = std::vector<Dim>; // maybe use Unique<Dim, 1> here.
  387. Dimv dim;
  388. T * p;
  389. constexpr static rank_t rank_s() { return RANK_ANY; }
  390. constexpr rank_t rank() const { return rank_t(dim.size()); }
  391. constexpr static dim_t size_s() { return DIM_ANY; }
  392. constexpr dim_t size() const { return proddim(dim.begin(), dim.end()); }
  393. constexpr dim_t size(int const j) const { return dim[j].size; }
  394. constexpr dim_t stride(int const j) const { return dim[j].stride; }
  395. constexpr auto data() { return p; }
  396. constexpr auto data() const { return p; }
  397. // Contrary to RANK!=RANK_ANY, the scalar case cannot be separated at compile time. So operator() will return a rank 0 view in that case (and rely on conversion if, say, this ends up assigned to a scalar).
  398. #define SUBSCRIPTS(CONST) \
  399. template <class ... I, std::enable_if_t<(is_beatable<I>::value && ...), int> = 0> \
  400. auto operator()(I && ... i) CONST \
  401. { \
  402. constexpr rank_t extended = (0 + ... + (is_beatable<I>::skip-is_beatable<I>::skip_src)); \
  403. assert(this->rank()+extended>=0); \
  404. View<T CONST, RANK_ANY> sub; \
  405. sub.dim.resize(this->rank()+extended); \
  406. sub.p = data() + select_loop(sub.dim.data(), this->dim.data(), i ...); \
  407. for (int i=(0 + ... + is_beatable<I>::skip); i<sub.rank(); ++i) { \
  408. sub.dim[i] = this->dim[i-extended]; \
  409. } \
  410. return sub; \
  411. } \
  412. /* TODO More than one selector... */ \
  413. template <class ... I, std::enable_if_t<!(is_beatable<I>::value && ...), int> = 0> \
  414. auto operator()(I && ... i) CONST \
  415. { \
  416. return from(*this, std::forward<I>(i) ...); \
  417. } \
  418. template <class I> \
  419. auto at(I && i) CONST \
  420. { \
  421. return View<T CONST, RANK_ANY> { Dimv(dim.begin()+i.size(), dim.end()), /* Dimv is std::vector */ \
  422. data() + Indexer1::index_p(dim, i) }; \
  423. } \
  424. constexpr T CONST & operator[](dim_t const i) CONST \
  425. { \
  426. CHECK_BOUNDS(rank()==1 && "bad rank"); \
  427. CHECK_BOUNDS(inside(i, dim[0].size)); \
  428. return data()[i*dim[0].stride]; \
  429. }
  430. FOR_EACH(SUBSCRIPTS, /*const*/, const)
  431. #undef SUBSCRIPTS
  432. DEF_ITERATORS(RANK_ANY)
  433. DEF_VIEW_COMMON(RANK_ANY)
  434. // conversions from fixed rank
  435. template <rank_t R, std::enable_if_t<R!=RANK_ANY, int> =0>
  436. View(View<T const, R> const & x): dim(x.dim.begin(), x.dim.end()), p(x.p) {}
  437. template <rank_t R, std::enable_if_t<R!=RANK_ANY, int> =0>
  438. View(View<std::remove_const_t<T>, R> const & x): dim(x.dim.begin(), x.dim.end()), p(x.p) {}
  439. // conversion to const from non const
  440. operator View<const_atom<T>> const & ()
  441. {
  442. return *reinterpret_cast<View<const_atom<T>> const *>(this);
  443. }
  444. // conversions to scalar
  445. operator T & () { assert(rank()==0); return data()[0]; };
  446. operator T const & () const { assert(rank()==0); return data()[0]; };
  447. };
  448. #undef DEF_ITERATORS
  449. #undef DEF_VIEW_COMMON
  450. #undef DEF_ASSIGNOPS
  451. template <class T>
  452. struct ra_traits_def<View<T, RANK_ANY>>
  453. {
  454. using V = View<T, RANK_ANY>;
  455. using value_type = T;
  456. static decltype(auto) shape(V const & v) { return ra::shape(v.iter()); }
  457. static dim_t size(V const & v) { return v.size(); }
  458. static rank_t rank(V const & v) { return v.rank(); }
  459. constexpr static rank_t rank_s() { return RANK_ANY; };
  460. constexpr static dim_t size_s() { return DIM_ANY; }
  461. };
  462. // --------------------
  463. // Container types
  464. // --------------------
  465. template <class V> struct storage_traits
  466. {
  467. using T = std::decay_t<decltype(*std::declval<V>().get())>;
  468. static V create(dim_t n) { CHECK_BOUNDS(n>=0); return V(new T[n]); }
  469. static T const * data(V const & v) { return v.get(); }
  470. static T * data(V & v) { return v.get(); }
  471. };
  472. template <class T_, class A> struct storage_traits<std::vector<T_, A>>
  473. {
  474. using T = T_;
  475. static std::vector<T, A> create(dim_t n) { return std::vector<T, A>(n); }
  476. static T const * data(std::vector<T, A> const & v) { return v.data(); } // BUG not if T = bool
  477. static T * data(std::vector<T, A> & v) { return v.data(); }
  478. };
  479. template <class T, rank_t RANK> inline
  480. bool is_c_order(View<T, RANK> const & a)
  481. {
  482. dim_t s = 1;
  483. for (int i=a.rank()-1; i>=0; --i) {
  484. if (s!=a.stride(i)) {
  485. return false;
  486. }
  487. s *= a.size(i);
  488. if (s==0) {
  489. return true;
  490. }
  491. }
  492. return true;
  493. }
  494. // TODO be convertible to View only, so that View::p is not duplicated
  495. template <class Store, rank_t RANK>
  496. struct Container: public View<typename storage_traits<Store>::T, RANK>
  497. {
  498. Store store;
  499. using T = typename storage_traits<Store>::T;
  500. using View = ra::View<T, RANK>;
  501. using View::rank_s;
  502. using shape_arg = typename decltype(std::declval<View>().iter())::shape_type;
  503. View & view() { return *this; }
  504. View const & view() const { return *this; }
  505. template <class ... A> decltype(auto) operator()(A && ... a) { return View::operator()(std::forward<A>(a) ...); }
  506. template <class ... A> decltype(auto) operator()(A && ... a) const { return View::operator()(std::forward<A>(a) ...); }
  507. // TODO Explicit definitions are needed only to have View::p set. Remove the duplication as in SmallBase/SmallArray, then remove these, both the constructors and the operator=s.
  508. Container(Container && w): store(std::move(w.store))
  509. {
  510. View::dim = std::move(w.dim);
  511. View::p = storage_traits<Store>::data(store);
  512. }
  513. Container(Container const & w): store(w.store)
  514. {
  515. View::dim = w.dim;
  516. View::p = storage_traits<Store>::data(store);
  517. }
  518. Container(Container & w): store(w.store)
  519. {
  520. View::dim = w.dim;
  521. View::p = storage_traits<Store>::data(store);
  522. }
  523. // 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.C [ra20].
  524. // TODO do this through .set() op.
  525. // TODO don't require copiable T from constructors, see fill1 below. That requires initialization and not update semantics for operator=.
  526. Container & operator=(Container && w)
  527. {
  528. store = std::move(w.store);
  529. View::dim = std::move(w.dim);
  530. View::p = storage_traits<Store>::data(store);
  531. return *this;
  532. }
  533. Container & operator=(Container const & w)
  534. {
  535. store = w.store;
  536. View::dim = w.dim;
  537. View::p = storage_traits<Store>::data(store);
  538. return *this;
  539. }
  540. Container & operator=(Container & w)
  541. {
  542. store = w.store;
  543. View::dim = w.dim;
  544. View::p = storage_traits<Store>::data(store);
  545. return *this;
  546. }
  547. // Provided so that {} calls shape_arg constructor below.
  548. Container()
  549. {
  550. for (Dim & dimi: View::dim) { dimi = {0, 1}; } // 1 so we can push_back()
  551. }
  552. template <class S> void init(S && s)
  553. {
  554. auto w = map([](auto && s) { return Dim { ra::dim_t(s), 0 }; }, s);
  555. static_assert(1==decltype(w)::rank_s(), "rank mismatch for init shape"); // I decided not to accept rank extension here.
  556. // [ra37] Need two parts because Dimv might be STL type. Otherwise I'd just View::dim.set(map(...)). Not being able to traverse backwards hurts here. See other uses of ra::vector (or start) here.
  557. if constexpr (RANK==RANK_ANY) {
  558. ra::resize(View::dim, w.size(0));
  559. }
  560. start(View::dim) = w;
  561. dim_t t = filldim(View::dim.size(), View::dim.end());
  562. store = storage_traits<Store>::create(t);
  563. View::p = storage_traits<Store>::data(store);
  564. }
  565. // FIXME use of fill1 requires T to be copiable, this is unfortunate as it conflicts with the semantics of view_.operator=.
  566. // store(x) avoids it for Big, but doesn't work for Unique. Should construct in place as std::vector does.
  567. template <class Pbegin> void fill1(dim_t xsize, Pbegin xbegin)
  568. {
  569. CHECK_BOUNDS(this->size()==xsize && "mismatched sizes");
  570. std::copy_n(xbegin, xsize, this->begin()); // TODO Use xpr traversal.
  571. }
  572. // shape_arg overloads handle {...} arguments. Size check is courtesy of conversion (if shape_arg is Small) or init().
  573. // explicit shape.
  574. Container(shape_arg const & s, none_t) { init(s); }
  575. template <class XX> Container(shape_arg const & s, XX && x): Container(s, none) { view() = x; }
  576. // shape from data.
  577. template <class XX> Container(XX && x): Container(ra::shape(x), none) { view() = x; }
  578. Container(typename nested_braces<T, RANK>::list x)
  579. {
  580. static_assert(RANK!=RANK_ANY);
  581. std::array<dim_t, RANK> s;
  582. nested_braces<T, RANK>::template shape(x, s);
  583. init(s);
  584. view() = x;
  585. }
  586. // braces row-major ravel for rank!=1
  587. Container(typename View::ravel_arg x)
  588. : Container({dim_t(x.size())}, none) { fill1(x.size(), x.begin()); }
  589. // shape + row-major ravel. // TODO Maybe remove these? See also small.H.
  590. Container(shape_arg const & s, std::initializer_list<T> x)
  591. : Container(s, none) { fill1(x.size(), x.begin()); }
  592. template <class TT>
  593. Container(shape_arg const & s, TT * p)
  594. : Container(s, none) { fill1(this->size(), p); }
  595. template <class P>
  596. Container(shape_arg const & s, P pbegin, P pend)
  597. : Container(s, none) { fill1(this->size(), pbegin); }
  598. // these are needed when shape_arg is std::vector, since that doesn't handle conversions like Small does.
  599. template <class SS> Container(SS && s, none_t) { init(s); }
  600. template <class SS, class XX> Container(SS && s, XX && x): Container(s, none) { view() = x; }
  601. template <class SS> Container(SS const & s, std::initializer_list<T> x)
  602. : Container(s, none) { fill1(x.size(), x.begin()); }
  603. using View::operator=;
  604. // only for some kinds of store.
  605. void resize(dim_t const s)
  606. {
  607. static_assert(RANK==RANK_ANY || RANK>0); CHECK_BOUNDS(this->rank()>0);
  608. store.resize(proddim(View::dim.begin()+1, View::dim.end())*s);
  609. View::dim[0].size = s;
  610. View::p = store.data();
  611. }
  612. void resize(dim_t const s, T const & t)
  613. {
  614. static_assert(RANK==RANK_ANY || RANK>0); CHECK_BOUNDS(this->rank()>0);
  615. store.resize(proddim(View::dim.begin()+1, View::dim.end())*s, t);
  616. View::dim[0].size = s;
  617. View::p = store.data();
  618. }
  619. // lets us move. A template + std::forward wouldn't work for push_back(brace-enclosed-list).
  620. void push_back(T && t)
  621. {
  622. static_assert(RANK==1 || RANK==RANK_ANY); CHECK_BOUNDS(this->rank()==1);
  623. store.push_back(std::move(t));
  624. ++View::dim[0].size;
  625. View::p = store.data();
  626. }
  627. void push_back(T const & t)
  628. {
  629. static_assert(RANK==1 || RANK==RANK_ANY); CHECK_BOUNDS(this->rank()==1);
  630. store.push_back(t);
  631. ++View::dim[0].size;
  632. View::p = store.data();
  633. }
  634. template <class ... A>
  635. void emplace_back(A && ... a)
  636. {
  637. static_assert(RANK==1 || RANK==RANK_ANY); CHECK_BOUNDS(this->rank()==1);
  638. store.emplace_back(std::forward<A>(a) ...);
  639. ++View::dim[0].size;
  640. View::p = store.data();
  641. }
  642. void pop_back()
  643. {
  644. static_assert(RANK==1 || RANK==RANK_ANY); CHECK_BOUNDS(this->rank()==1);
  645. CHECK_BOUNDS(View::dim[0].size>0);
  646. store.pop_back();
  647. --View::dim[0].size;
  648. }
  649. bool empty() const
  650. {
  651. return this->size()==0;
  652. }
  653. T const & back() const { CHECK_BOUNDS(this->rank()==1 && this->size()>0); return store[this->size()-1]; }
  654. T & back() { CHECK_BOUNDS(this->rank()==1 && this->size()>0); return store[this->size()-1]; }
  655. // Container is always compact/row-major. Then the 0-rank 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) or ellidable.
  656. auto begin() { assert(is_c_order(*this)); return this->data(); }
  657. auto begin() const { assert(is_c_order(*this)); return this->data(); }
  658. auto end() { return this->data()+this->size(); }
  659. auto end() const { return this->data()+this->size(); }
  660. };
  661. template <class Store, rank_t RANK>
  662. struct ra_traits_def<Container<Store, RANK>>
  663. : public ra_traits_def<View<typename Container<Store, RANK>::T, RANK>> {};
  664. template <class Store, rank_t RANK>
  665. void swap(Container<Store, RANK> & a, Container<Store, RANK> & b)
  666. {
  667. std::swap(a.dim, b.dim);
  668. std::swap(a.store, b.store);
  669. std::swap(a.p, b.p);
  670. }
  671. // Default storage for Big - see https://stackoverflow.com/a/21028912
  672. // Allocator adaptor that interposes construct() calls to convert value initialization into default initialization.
  673. template <typename T, typename A=std::allocator<T>>
  674. struct default_init_allocator: public A
  675. {
  676. using a_t = std::allocator_traits<A>;
  677. using A::A;
  678. template <typename U>
  679. struct rebind
  680. {
  681. using other = default_init_allocator<U, typename a_t::template rebind_alloc<U>>;
  682. };
  683. template <typename U>
  684. void construct(U * ptr) noexcept(std::is_nothrow_default_constructible<U>::value)
  685. {
  686. ::new(static_cast<void *>(ptr)) U;
  687. }
  688. template <typename U, typename... Args>
  689. void construct(U * ptr, Args &&... args)
  690. {
  691. a_t::construct(static_cast<A &>(*this), ptr, std::forward<Args>(args)...);
  692. }
  693. };
  694. // Beyond this, we probably should have fixed-size (~std::dynarray), resizeable (~std::vector).
  695. template <class T, rank_t RANK=RANK_ANY> using Big = Container<std::vector<T, default_init_allocator<T>>, RANK>;
  696. template <class T, rank_t RANK=RANK_ANY> using Unique = Container<std::unique_ptr<T []>, RANK>;
  697. template <class T, rank_t RANK=RANK_ANY> using Shared = Container<std::shared_ptr<T>, RANK>;
  698. // -------------
  699. // Used in the Guile wrappers to allow an array parameter to either borrow from Guile
  700. // storage or convert into a new array (e.g. passing 'f32 into 'f64).
  701. // TODO Can use unique_ptr's deleter for this?
  702. // TODO Shared/Unique should maybe have constructors with unique_ptr/shared_ptr args
  703. // -------------
  704. struct NullDeleter { template <class T> void operator()(T * p) {} };
  705. struct Deleter { template <class T> void operator()(T * p) { delete[] p; } };
  706. template <rank_t RANK, class T>
  707. Shared<T, RANK> shared_borrowing(View<T, RANK> & raw)
  708. {
  709. Shared<T, RANK> a;
  710. a.dim = raw.dim;
  711. a.p = raw.p;
  712. a.store = std::shared_ptr<T>(raw.data(), NullDeleter());
  713. return a;
  714. }
  715. } // namespace ra
  716. #undef CHECK_BOUNDS