big.hh 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  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 <complex> // for View ops
  12. namespace ra {
  13. // --------------------
  14. // Big iterator
  15. // --------------------
  16. template <class T, rank_t RANK=ANY> struct View;
  17. // TODO Refactor with CellSmall. Clear up Dimv's type. Should I use span/Ptr?
  18. // TODO Take iterator like Ptr does and View should, not raw pointers
  19. template <class T, class Dimv, class Spec=ic_t<0>>
  20. struct CellBig
  21. {
  22. constexpr static rank_t spec = maybe_any<Spec>;
  23. constexpr static rank_t fullr = size_s<Dimv>();
  24. constexpr static rank_t cellr = is_constant<Spec> ? rank_cell(fullr, spec) : ANY;
  25. constexpr static rank_t framer = is_constant<Spec> ? rank_frame(fullr, spec) : ANY;
  26. static_assert(cellr>=0 || cellr==ANY, "Bad cell rank.");
  27. static_assert(framer>=0 || framer==ANY, "Bad frame rank.");
  28. using ctype = View<T, cellr>;
  29. using value_type = std::conditional_t<0==cellr, T, ctype>;
  30. ctype c;
  31. Dimv dimv;
  32. [[no_unique_address]] Spec const dspec = {};
  33. consteval static rank_t rank() requires (ANY!=framer) { return framer; }
  34. constexpr rank_t rank() const requires (ANY==framer) { return rank_frame(std::ssize(dimv), dspec); }
  35. #pragma GCC diagnostic push // gcc 12.2 and 13.2 with RA_DO_CHECK=0 and -fno-sanitize=all
  36. #pragma GCC diagnostic warning "-Warray-bounds"
  37. constexpr dim_t len(int k) const { return dimv[k].len; } // len(0<=k<rank) or step(0<=k)
  38. #pragma GCC diagnostic pop
  39. constexpr static dim_t len_s(int k) { return ANY; }
  40. constexpr dim_t step(int k) const { return k<rank() ? dimv[k].step : 0; }
  41. constexpr void adv(rank_t k, dim_t d) { c.cp += step(k)*d; }
  42. constexpr bool keep_step(dim_t st, int z, int j) const { return st*step(z)==step(j); }
  43. constexpr CellBig(T * cp, Dimv const & dimv_, Spec dspec_ = Spec {})
  44. : dimv(dimv_), dspec(dspec_)
  45. {
  46. // see STLIterator for the case of dimv_[0]=0, etc. [ra12].
  47. c.cp = cp;
  48. rank_t dcellr = rank_cell(std::ssize(dimv), dspec);
  49. rank_t dframer = this->rank();
  50. RA_CHECK(0<=dframer && 0<=dcellr, "Bad cell rank ", dcellr, " for array rank ", ssize(dimv), ").");
  51. resize(c.dimv, dcellr);
  52. for (int k=0; k<dcellr; ++k) {
  53. c.dimv[k] = dimv[dframer+k];
  54. }
  55. }
  56. constexpr CellBig(CellBig const & ci) = default;
  57. RA_DEF_ASSIGNOPS_DEFAULT_SET
  58. constexpr decltype(auto)
  59. at(auto const & i) const
  60. {
  61. auto d = longer(*this, i);
  62. if constexpr (0==cellr) {
  63. return c.cp[d];
  64. } else {
  65. ctype cc(c); cc.cp += d;
  66. return cc;
  67. }
  68. }
  69. constexpr decltype(auto) operator*() const requires (0==cellr) { return *(c.cp); }
  70. constexpr ctype const & operator*() const requires (0!=cellr) { return c; }
  71. constexpr auto save() const{ return c.cp; }
  72. constexpr void load(decltype(c.cp) cp) { c.cp = cp; }
  73. constexpr void mov(dim_t d) { c.cp += d; }
  74. };
  75. // --------------------
  76. // nested braces for Container initializers. Cf nested_arg for Small.
  77. // --------------------
  78. template <class T, rank_t rank>
  79. struct braces_def { using type = noarg; };
  80. template <class T, rank_t rank>
  81. using braces = braces_def<T, rank>::type;
  82. template <class T, rank_t rank> requires (rank==1)
  83. struct braces_def<T, rank> { using type = std::initializer_list<T>; };
  84. template <class T, rank_t rank> requires (rank>1)
  85. struct braces_def<T, rank> { using type = std::initializer_list<braces<T, rank-1>>; };
  86. template <int i, class T, rank_t rank>
  87. constexpr dim_t
  88. braces_len(braces<T, rank> const & l)
  89. {
  90. if constexpr (i>=rank) {
  91. return 0;
  92. } else if constexpr (i==0) {
  93. return l.size();
  94. } else {
  95. return braces_len<i-1, T, rank-1>(*(l.begin()));
  96. }
  97. }
  98. template <class T, rank_t rank, class S = std::array<dim_t, rank>>
  99. constexpr S
  100. braces_shape(braces<T, rank> const & l)
  101. {
  102. return std::apply([&l](auto ... i) { return S { braces_len<decltype(i)::value, T, rank>(l) ... }; },
  103. mp::iota<rank> {});
  104. }
  105. // --------------------
  106. // View
  107. // --------------------
  108. // FIXME size is immutable so that it can be kept together with rank.
  109. // TODO Parameterize on Child having .data() so that there's only one pointer.
  110. // TODO Parameterize on iterator type not on value type.
  111. // TODO Constructor, if only for RA_CHECK (nonnegative lens, steps inside, etc.)
  112. template <class T, rank_t RANK>
  113. struct View
  114. {
  115. using Dimv = std::conditional_t<ANY==RANK, vector_default_init<Dim>, Small<Dim, ANY==RANK ? 0 : RANK>>;
  116. Dimv dimv;
  117. T * cp;
  118. consteval static rank_t rank() requires (RANK!=ANY) { return RANK; }
  119. constexpr rank_t rank() const requires (RANK==ANY) { return rank_t(dimv.size()); }
  120. constexpr static dim_t len_s(int k) { return ANY; }
  121. constexpr dim_t len(int k) const { return dimv[k].len; }
  122. constexpr dim_t step(int k) const { return dimv[k].step; }
  123. constexpr auto data() const { return cp; }
  124. constexpr dim_t size() const { return prod(map(&Dim::len, dimv)); }
  125. constexpr bool empty() const { return any(0==map(&Dim::len, dimv)); }
  126. constexpr View(): cp() {} // FIXME used by Container constructors
  127. constexpr View(Dimv const & dimv_, T * cp_): dimv(dimv_), cp(cp_) {} // [ra36]
  128. template <class SS>
  129. constexpr View(SS && s, T * cp_): cp(cp_)
  130. {
  131. ra::resize(dimv, ra::size(s)); // [ra37]
  132. if constexpr (std::is_convertible_v<value_t<SS>, Dim>) {
  133. start(dimv) = s;
  134. } else {
  135. filldim(dimv, s);
  136. }
  137. }
  138. constexpr View(std::initializer_list<dim_t> s, T * cp_): View(start(s), cp_) {}
  139. constexpr View(View const & x) = default;
  140. // the non-template is required, and to avoid ambiguity the template must then be constrained [ra38] [ra34]
  141. View const & operator=(View const & x) const { start(*this) = x; return *this; }
  142. template <class X> View const &
  143. operator=(X && x) const requires (!std::is_same_v<View, std::decay_t<X>>) { start(*this) = x; return *this; }
  144. #define DEF_ASSIGNOPS(OP) \
  145. template <class X> View const & operator OP (X && x) const { start(*this) OP x; return *this; }
  146. FOR_EACH(DEF_ASSIGNOPS, *=, +=, -=, /=)
  147. #undef DEF_ASSIGNOPS
  148. // braces row-major ravel for rank!=1. See Container::fill1
  149. using ravel_arg = std::conditional_t<RANK==1, noarg, std::initializer_list<T>>;
  150. View const & operator=(ravel_arg const x) const
  151. {
  152. auto xsize = ssize(x);
  153. RA_CHECK(size()==xsize, "Mismatched sizes ", View::size(), " ", xsize, ".");
  154. std::copy_n(x.begin(), xsize, begin());
  155. return *this;
  156. }
  157. constexpr View const & operator=(braces<T, RANK> x) const requires (RANK!=ANY) { ra::iter<-1>(*this) = x; return *this; }
  158. #define RA_BRACES_ANY(N) \
  159. constexpr View const & operator=(braces<T, N> x) const requires (RANK==ANY) { ra::iter<-1>(*this) = x; return *this; }
  160. FOR_EACH(RA_BRACES_ANY, 2, 3, 4);
  161. #undef RA_BRACES_ANY
  162. template <rank_t c=0> constexpr auto iter() const && { return CellBig<T, Dimv, ic_t<c>>(cp, std::move(dimv)); }
  163. template <rank_t c=0> constexpr auto iter() const & { return CellBig<T, Dimv const &, ic_t<c>>(cp, dimv); }
  164. constexpr auto iter(rank_t c) const && { return CellBig<T, Dimv, dim_t>(cp, std::move(dimv), c); }
  165. constexpr auto iter(rank_t c) const & { return CellBig<T, Dimv const &, dim_t>(cp, dimv, c); }
  166. constexpr auto begin() const { return STLIterator(iter<0>()); }
  167. constexpr decltype(auto) static end() { return std::default_sentinel; }
  168. constexpr dim_t
  169. select(Dim * dim, int k, dim_t i) const
  170. {
  171. RA_CHECK(inside(i, dimv[k].len),
  172. "Out of range for len[", k, "]=", dimv[k].len, ": ", i, ".");
  173. return dimv[k].step*i;
  174. }
  175. template <class I> requires (is_iota<I>)
  176. constexpr dim_t
  177. select(Dim * dim, int k, I i) const
  178. {
  179. RA_CHECK(inside(i, dimv[k].len),
  180. "Out of range for len[", k, "]=", dimv[k].len, ": iota [", i.n, " ", i.i, " ", i.s, "].");
  181. *dim = { .len = i.n, .step = dimv[k].step * i.s };
  182. return dimv[k].step*i.i;
  183. }
  184. template <class I0, class ... I>
  185. constexpr dim_t
  186. select_loop(Dim * dim, int k, I0 && i0, I && ... i) const
  187. {
  188. return select(dim, k, with_len(len(k), RA_FWD(i0)))
  189. + select_loop(dim + beatable<I0>.dst, k + beatable<I0>.src, RA_FWD(i) ...);
  190. }
  191. template <int n, class ... I>
  192. constexpr dim_t
  193. select_loop(Dim * dim, int k, dots_t<n> i0, I && ... i) const
  194. {
  195. int nn = (BAD==n) ? (rank() - k - (0 + ... + beatable<I>.src)) : n;
  196. for (Dim * end = dim+nn; dim!=end; ++dim, ++k) {
  197. *dim = dimv[k];
  198. }
  199. return select_loop(dim, k, RA_FWD(i) ...);
  200. }
  201. template <int n, class ... I>
  202. constexpr dim_t
  203. select_loop(Dim * dim, int k, insert_t<n> i0, I && ... i) const
  204. {
  205. for (Dim * end = dim+n; dim!=end; ++dim) {
  206. *dim = { .len = BAD, .step = 0 };
  207. }
  208. return select_loop(dim, k, RA_FWD(i) ...);
  209. }
  210. constexpr static dim_t
  211. select_loop(Dim * dim, int k)
  212. {
  213. return 0;
  214. }
  215. // Specialize for rank() integer-args -> scalar, same in ra::SmallBase in small.hh.
  216. template <class ... I>
  217. constexpr decltype(auto)
  218. operator()(I && ... i) const
  219. {
  220. constexpr int stretch = (0 + ... + (beatable<I>.dst==BAD));
  221. static_assert(stretch<=1, "Cannot repeat stretch index.");
  222. if constexpr ((0 + ... + is_scalar_index<I>)==RANK) {
  223. return data()[select_loop(nullptr, 0, i ...)];
  224. } else if constexpr ((beatable<I>.rt && ...)) {
  225. constexpr rank_t extended = (0 + ... + beatable<I>.add);
  226. View<T, rank_sum(RANK, extended)> sub;
  227. rank_t subrank = rank()+extended;
  228. if constexpr (RANK==ANY) {
  229. RA_CHECK(subrank>=0, "Bad rank.");
  230. sub.dimv.resize(subrank);
  231. }
  232. sub.cp = data() + select_loop(sub.dimv.data(), 0, i ...);
  233. // fill the rest of dim, skipping over beatable subscripts.
  234. for (int k = (0==stretch ? (0 + ... + beatable<I>.dst) : subrank); k<subrank; ++k) {
  235. sub.dimv[k] = dimv[k-extended];
  236. }
  237. // if RANK==ANY then rank may be 0
  238. return sub;
  239. // TODO partial beating. FIXME forward this? cf unbeat
  240. } else {
  241. return unbeat<sizeof...(I)>::op(*this, RA_FWD(i) ...);
  242. }
  243. }
  244. template <class ... I>
  245. constexpr decltype(auto)
  246. operator[](I && ... i) const { return (*this)(RA_FWD(i) ...); }
  247. template <class I>
  248. constexpr decltype(auto)
  249. at(I && i) const
  250. {
  251. // FIXME no way to say 'frame rank 0' so -size wouldn't work.
  252. constexpr rank_t crank = rank_diff(RANK, ra::size_s<I>());
  253. if constexpr (ANY==crank) {
  254. return iter(rank()-ra::size(i)).at(RA_FWD(i));
  255. } else {
  256. return iter<crank>().at(RA_FWD(i));
  257. }
  258. }
  259. // conversion to scalar
  260. constexpr
  261. operator T & () const
  262. {
  263. static_assert(ANY==RANK || 0==RANK, "Bad rank for conversion to scalar.");
  264. if constexpr (ANY==RANK) {
  265. RA_CHECK(0==rank(), "Error converting rank ", rank(), " to scalar.");
  266. }
  267. return data()[0];
  268. }
  269. // necessary here per [ra15] (?)
  270. constexpr operator T & () { return std::as_const(*this); }
  271. // conversions from var rank to fixed rank
  272. template <rank_t R> requires (R==ANY && R!=RANK)
  273. constexpr View(View<T, R> const & x): dimv(x.dimv), cp(x.cp) {}
  274. template <rank_t R> requires (R==ANY && R!=RANK && std::is_const_v<T>)
  275. constexpr View(View<std::remove_const_t<T>, R> const & x): dimv(x.dimv), cp(x.cp) {}
  276. // conversion from fixed rank to var rank
  277. template <rank_t R> requires (R!=ANY && RANK==ANY)
  278. constexpr View(View<T, R> const & x): dimv(x.dimv.begin(), x.dimv.end()), cp(x.cp) {}
  279. template <rank_t R> requires (R!=ANY && RANK==ANY && std::is_const_v<T>)
  280. constexpr View(View<std::remove_const_t<T>, R> const & x): dimv(x.dimv.begin(), x.dimv.end()), cp(x.cp) {}
  281. // conversion to const. We rely on it for Container::view(). FIXME iffy? not constexpr, and doesn't work for SmallBase
  282. constexpr
  283. operator View<T const, RANK> const & () const requires (!std::is_const_v<T>)
  284. {
  285. return *reinterpret_cast<View<T const, RANK> const *>(this);
  286. }
  287. };
  288. // --------------------
  289. // Container types
  290. // --------------------
  291. template <class V>
  292. struct storage_traits
  293. {
  294. using T = V::value_type;
  295. static_assert(!std::is_same_v<std::remove_const_t<T>, bool>, "No pointers to bool in std::vector<bool>.");
  296. constexpr static auto create(dim_t n) { RA_CHECK(n>=0); return V(n); }
  297. template <class VV> constexpr static auto data(VV & v) { return v.data(); }
  298. };
  299. template <class P>
  300. struct storage_traits<std::unique_ptr<P>>
  301. {
  302. using V = std::unique_ptr<P>;
  303. using T = std::decay_t<decltype(*std::declval<V>().get())>;
  304. constexpr static auto create(dim_t n) { RA_CHECK(n>=0); return V(new T[n]); }
  305. template <class VV> constexpr static auto data(VV & v) { return v.get(); }
  306. };
  307. template <class P>
  308. struct storage_traits<std::shared_ptr<P>>
  309. {
  310. using V = std::shared_ptr<P>;
  311. using T = std::decay_t<decltype(*std::declval<V>().get())>;
  312. constexpr static auto create(dim_t n) { RA_CHECK(n>=0); return V(new T[n], std::default_delete<T[]>()); }
  313. template <class VV> constexpr static auto data(VV & v) { return v.get(); }
  314. };
  315. // FIXME avoid duplicating View::p. Avoid overhead with rank 1.
  316. template <class Store, rank_t RANK>
  317. struct Container: public View<typename storage_traits<Store>::T, RANK>
  318. {
  319. Store store;
  320. using T = typename storage_traits<Store>::T;
  321. using View = ra::View<T, RANK>;
  322. using ViewConst = ra::View<T const, RANK>;
  323. using View::size, View::rank;
  324. using shape_arg = decltype(shape(std::declval<View>().iter()));
  325. constexpr ViewConst const & view() const { return static_cast<View const &>(*this); }
  326. constexpr View & view() { return *this; }
  327. // Needed to set View::cp. FIXME Remove duplication as in SmallBase/SmallArray.
  328. Container(Container && w): store(std::move(w.store))
  329. {
  330. View::dimv = std::move(w.dimv);
  331. View::cp = storage_traits<Store>::data(store);
  332. }
  333. Container(Container const & w): store(w.store)
  334. {
  335. View::dimv = w.dimv;
  336. View::cp = storage_traits<Store>::data(store);
  337. }
  338. Container(Container & w): Container(std::as_const(w)) {}
  339. // because of these operator=s, 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 uses View::operator= and frame match. This is used by operator>>(std::istream &, Container &). See test/ownership.cc [ra20].
  340. // TODO don't require copiable T from constructors, see fill1 below. That requires initialization and not update semantics for operator=.
  341. Container & operator=(Container && w)
  342. {
  343. store = std::move(w.store);
  344. View::dimv = std::move(w.dimv);
  345. View::cp = storage_traits<Store>::data(store);
  346. return *this;
  347. }
  348. Container & operator=(Container const & w)
  349. {
  350. store = w.store;
  351. View::dimv = w.dimv;
  352. View::cp = storage_traits<Store>::data(store);
  353. return *this;
  354. }
  355. Container & operator=(Container & w) { return *this = std::as_const(w); }
  356. // non-copy assignment operators follow View, but cannot be just using'd because of constness.
  357. #define DEF_ASSIGNOPS(OP) \
  358. template <class X> Container & operator OP (X && x) { view() OP x; return *this; }
  359. FOR_EACH(DEF_ASSIGNOPS, =, *=, +=, -=, /=)
  360. #undef DEF_ASSIGNOPS
  361. using ravel_arg = std::conditional_t<RANK==1, noarg, std::initializer_list<T>>;
  362. Container & operator=(ravel_arg const x) { view() = x; return *this; }
  363. constexpr Container & operator=(braces<T, RANK> x) requires (RANK!=ANY) { view() = x; return *this; }
  364. #define RA_BRACES_ANY(N) \
  365. constexpr Container & operator=(braces<T, N> x) requires (RANK==ANY) { view() = x; return *this; }
  366. FOR_EACH(RA_BRACES_ANY, 2, 3, 4);
  367. #undef RA_BRACES_ANY
  368. template <class S> requires (1==rank_s<S>() || ANY==rank_s<S>())
  369. void
  370. init(S && s)
  371. {
  372. static_assert(!std::is_convertible_v<value_t<S>, Dim>);
  373. RA_CHECK(1==ra::rank(s), "Rank mismatch for init shape.");
  374. static_assert(ANY==RANK || ANY==size_s<S>() || RANK==size_s<S>() || BAD==size_s<S>(), "Bad shape for rank.");
  375. ra::resize(View::dimv, ra::size(s)); // [ra37]
  376. store = storage_traits<Store>::create(filldim(View::dimv, s));
  377. View::cp = storage_traits<Store>::data(store);
  378. }
  379. void init(dim_t s) { init(std::array {s}); } // scalar allowed as shape if rank is 1.
  380. // provided so that {} calls shape_arg constructor below.
  381. Container() requires (ANY==RANK): View({ Dim {0, 1} }, nullptr) {}
  382. Container() requires (ANY!=RANK && 0!=RANK): View(typename View::Dimv(Dim {0, 1}), nullptr) {}
  383. Container() requires (0==RANK): Container({}, ra::none) {}
  384. // shape_arg overloads handle {...} arguments. Size check is at conversion (if shape_arg is Small) or init().
  385. Container(shape_arg const & s, none_t) { init(s); }
  386. template <class XX>
  387. Container(shape_arg const & s, XX && x): Container(s, none) { view() = x; }
  388. Container(shape_arg const & s, braces<T, RANK> x) requires (RANK==1)
  389. : Container(s, none) { view() = x; }
  390. template <class XX>
  391. Container(XX && x): Container(ra::shape(x), none) { view() = x; }
  392. Container(braces<T, RANK> x) requires (RANK!=ANY)
  393. : Container(braces_shape<T, RANK>(x), none) { view() = x; }
  394. #define RA_BRACES_ANY(N) \
  395. Container(braces<T, N> x) requires (RANK==ANY) \
  396. : Container(braces_shape<T, N>(x), none) { view() = x; }
  397. FOR_EACH(RA_BRACES_ANY, 1, 2, 3, 4)
  398. #undef RA_BRACES_ANY
  399. // FIXME requires T to be copiable, which conflicts with the semantics of view_.operator=. store(x) avoids it for Big, but doesn't work for Unique. Should construct in place like std::vector does.
  400. template <class Xbegin>
  401. constexpr void
  402. fill1(Xbegin xbegin, dim_t xsize)
  403. {
  404. RA_CHECK(size()==xsize, "Mismatched sizes ", size(), " ", xsize, ".");
  405. std::ranges::copy_n(xbegin, xsize, begin());
  406. }
  407. // shape + row-major ravel.
  408. // FIXME explicit it-is-ravel mark. Also iter<n> initializers.
  409. // FIXME regular (no need for fill1) for ANY if rank is 1.
  410. Container(shape_arg const & s, typename View::ravel_arg x)
  411. : Container(s, none) { fill1(x.begin(), x.size()); }
  412. // FIXME remove
  413. template <class TT>
  414. Container(shape_arg const & s, TT * p)
  415. : Container(s, none) { fill1(p, size()); } // FIXME fake check
  416. // FIXME remove
  417. template <class P>
  418. Container(shape_arg const & s, P pbegin, dim_t psize)
  419. : Container(s, none) { fill1(pbegin, psize); }
  420. // for SS that doesn't convert implicitly to shape_arg
  421. template <class SS>
  422. Container(SS && s, none_t) { init(RA_FWD(s)); }
  423. template <class SS, class XX>
  424. Container(SS && s, XX && x)
  425. : Container(RA_FWD(s), none) { view() = x; }
  426. template <class SS>
  427. Container(SS && s, std::initializer_list<T> x)
  428. : Container(RA_FWD(s), none) { fill1(x.begin(), x.size()); }
  429. // resize first axis or full shape. Only for some kinds of store.
  430. void resize(dim_t const s)
  431. {
  432. static_assert(RANK==ANY || RANK>0); RA_CHECK(0<rank());
  433. View::dimv[0].len = s;
  434. store.resize(size());
  435. View::cp = store.data();
  436. }
  437. void resize(dim_t const s, T const & t)
  438. {
  439. static_assert(RANK==ANY || RANK>0); RA_CHECK(0<rank());
  440. View::dimv[0].len = s;
  441. store.resize(size(), t);
  442. View::cp = store.data();
  443. }
  444. template <class S> requires (rank_s<S>() > 0)
  445. void resize(S const & s)
  446. {
  447. ra::resize(View::dimv, start(s).len(0)); // [ra37] FIXME is View constructor
  448. store.resize(filldim(View::dimv, s));
  449. View::cp = store.data();
  450. }
  451. // lets us move. A template + RA_FWD wouldn't work for push_back(brace-enclosed-list).
  452. void push_back(T && t)
  453. {
  454. static_assert(RANK==1 || RANK==ANY); RA_CHECK(1==rank());
  455. store.push_back(std::move(t));
  456. ++View::dimv[0].len;
  457. View::cp = store.data();
  458. }
  459. void push_back(T const & t)
  460. {
  461. static_assert(RANK==1 || RANK==ANY); RA_CHECK(1==rank());
  462. store.push_back(t);
  463. ++View::dimv[0].len;
  464. View::cp = store.data();
  465. }
  466. template <class ... A>
  467. void emplace_back(A && ... a)
  468. {
  469. static_assert(RANK==1 || RANK==ANY); RA_CHECK(1==rank());
  470. store.emplace_back(RA_FWD(a) ...);
  471. ++View::dimv[0].len;
  472. View::cp = store.data();
  473. }
  474. void pop_back()
  475. {
  476. static_assert(RANK==1 || RANK==ANY); RA_CHECK(1==rank());
  477. RA_CHECK(View::dimv[0].len>0);
  478. store.pop_back();
  479. --View::dimv[0].len;
  480. }
  481. // const/nonconst shims over View's methods. FIXME > gcc13 ? __cpp_explicit_this_parameter
  482. constexpr T const & back() const { RA_CHECK(1==rank() && this->size()>0); return store[this->size()-1]; }
  483. constexpr T & back() { RA_CHECK(1==rank() && this->size()>0); return store[this->size()-1]; }
  484. constexpr auto data() { return view().data(); }
  485. constexpr auto data() const { return view().data(); }
  486. template <class ... A> constexpr decltype(auto) operator()(A && ... a) { return view()(RA_FWD(a) ...); }
  487. template <class ... A> constexpr decltype(auto) operator()(A && ... a) const { return view()(RA_FWD(a) ...); }
  488. template <class ... A> constexpr decltype(auto) operator[](A && ... a) { return view()(RA_FWD(a) ...); }
  489. template <class ... A> constexpr decltype(auto) operator[](A && ... a) const { return view()(RA_FWD(a) ...); }
  490. template <class I> constexpr decltype(auto) at(I && i) { return view().at(RA_FWD(i)); }
  491. template <class I> constexpr decltype(auto) at(I && i) const { return view().at(RA_FWD(i)); }
  492. // container is always compact/row-major, so STL-like iterators can be raw pointers.
  493. constexpr auto begin() const { assert(is_c_order(view())); return view().data(); }
  494. constexpr auto begin() { assert(is_c_order(view())); return view().data(); }
  495. constexpr auto end() const { return view().data()+this->size(); }
  496. constexpr auto end() { return view().data()+this->size(); }
  497. template <rank_t c=0> constexpr auto iter() const { return view().template iter<c>(); }
  498. template <rank_t c=0> constexpr auto iter() { return view().template iter<c>(); }
  499. constexpr operator T const & () const { return view(); }
  500. constexpr operator T & () { return view(); }
  501. };
  502. template <class Store, rank_t RANKA, rank_t RANKB>
  503. requires (RANKA!=RANKB) // rely on std::swap; else ambiguous
  504. void
  505. swap(Container<Store, RANKA> & a, Container<Store, RANKB> & b)
  506. {
  507. if constexpr (ANY==RANKA) {
  508. RA_CHECK(rank(a)==rank(b));
  509. decltype(b.dimv) c = a.dimv;
  510. start(a.dimv) = b.dimv;
  511. std::swap(b.dimv, c);
  512. } else if constexpr (ANY==RANKB) {
  513. RA_CHECK(rank(a)==rank(b));
  514. decltype(a.dimv) c = b.dimv;
  515. start(b.dimv) = a.dimv;
  516. std::swap(a.dimv, c);
  517. } else {
  518. static_assert(RANKA==RANKB);
  519. std::swap(a.dimv, b.dimv);
  520. }
  521. std::swap(a.store, b.store);
  522. std::swap(a.cp, b.cp);
  523. }
  524. template <class T, rank_t RANK=ANY> using Big = Container<vector_default_init<T>, RANK>;
  525. template <class T, rank_t RANK=ANY> using Unique = Container<std::unique_ptr<T []>, RANK>;
  526. template <class T, rank_t RANK=ANY> using Shared = Container<std::shared_ptr<T>, RANK>;
  527. // -------------
  528. // Used in Guile wrappers to let array parameter either borrow from Guile storage or convert into new array (eg 'f32 into 'f64).
  529. // TODO Can use unique_ptr's deleter for this?
  530. // TODO Shared/Unique should maybe have constructors with unique_ptr/shared_ptr args
  531. // -------------
  532. template <rank_t RANK, class T>
  533. Shared<T, RANK>
  534. shared_borrowing(View<T, RANK> & raw)
  535. {
  536. Shared<T, RANK> a;
  537. a.dimv = raw.dimv;
  538. a.cp = raw.cp;
  539. a.store = std::shared_ptr<T>(raw.data(), [](T *) {});
  540. return a;
  541. }
  542. // --------------------
  543. // Concrete (container) type from array expression.
  544. // --------------------
  545. template <class E>
  546. struct concrete_type_def
  547. {
  548. using type = void;
  549. };
  550. template <class E> requires (size_s<E>()==ANY)
  551. struct concrete_type_def<E>
  552. {
  553. using type = Big<value_t<E>, rank_s<E>()>;
  554. };
  555. template <class E> requires (size_s<E>()!=ANY)
  556. struct concrete_type_def<E>
  557. {
  558. using type = decltype(std::apply([](auto ... i) { return Small<value_t<E>, E::len_s(i) ...> {}; }, mp::iota<rank_s<E>()> {}));
  559. };
  560. // Scalars are their own concrete_type. Treat unregistered types as scalars.
  561. template <class E>
  562. using concrete_type = std::decay_t<
  563. std::conditional_t<(0==rank_s<E>() && !is_ra<E>) || is_scalar<E>,
  564. std::decay_t<E>,
  565. typename concrete_type_def<std::decay_t<decltype(start(std::declval<E>()))>>::type>>;
  566. template <class E>
  567. constexpr auto
  568. concrete(E && e)
  569. {
  570. // FIXME gcc 11.3 on GH workflows (?)
  571. #pragma GCC diagnostic push
  572. #pragma GCC diagnostic warning "-Wmaybe-uninitialized"
  573. return concrete_type<E>(RA_FWD(e));
  574. #pragma GCC diagnostic pop
  575. }
  576. template <class E>
  577. constexpr auto
  578. with_same_shape(E && e)
  579. {
  580. if constexpr (ANY!=size_s<concrete_type<E>>()) {
  581. return concrete_type<E>();
  582. } else {
  583. return concrete_type<E>(ra::shape(e), ra::none);
  584. }
  585. }
  586. template <class E, class X>
  587. constexpr auto
  588. with_same_shape(E && e, X && x)
  589. {
  590. // FIXME gcc 11.3 on GH workflows (?)
  591. #pragma GCC diagnostic push
  592. #pragma GCC diagnostic warning "-Wmaybe-uninitialized"
  593. if constexpr (ANY!=size_s<concrete_type<E>>()) {
  594. return concrete_type<E>(RA_FWD(x));
  595. } else {
  596. return concrete_type<E>(ra::shape(e), RA_FWD(x));
  597. }
  598. #pragma GCC diagnostic pop
  599. }
  600. template <class E, class S, class X>
  601. constexpr auto
  602. with_shape(S && s, X && x)
  603. {
  604. if constexpr (ANY!=size_s<concrete_type<E>>()) {
  605. return concrete_type<E>(RA_FWD(x));
  606. } else {
  607. return concrete_type<E>(RA_FWD(s), RA_FWD(x));
  608. }
  609. }
  610. template <class E, class S, class X>
  611. constexpr auto
  612. with_shape(std::initializer_list<S> && s, X && x)
  613. {
  614. if constexpr (ANY!=size_s<concrete_type<E>>()) {
  615. return concrete_type<E>(RA_FWD(x));
  616. } else {
  617. return concrete_type<E>(s, RA_FWD(x));
  618. }
  619. }
  620. // --------------------
  621. // Operations specific to View.
  622. // --------------------
  623. template <class T, rank_t RANK>
  624. inline View<T, RANK>
  625. reverse(View<T, RANK> const & view, int k=0)
  626. {
  627. RA_CHECK(inside(k, view.rank()), "Bad reverse axis ", k, " for view of rank ", view.rank(), ".");
  628. View<T, RANK> r = view;
  629. if (auto & dim=r.dimv[k]; dim.len!=0) {
  630. r.cp += dim.step*(dim.len-1);
  631. dim.step *= -1;
  632. }
  633. return r;
  634. }
  635. // dynamic transposed axes list.
  636. template <class T, rank_t RANK, class S>
  637. inline View<T, ANY>
  638. transpose_(S && s, View<T, RANK> const & view)
  639. {
  640. RA_CHECK(view.rank()==ra::size(s));
  641. auto rp = std::max_element(s.begin(), s.end());
  642. rank_t dstrank = (rp==s.end() ? 0 : *rp+1);
  643. View<T, ANY> r { decltype(r.dimv)(dstrank, Dim { BAD, 0 }), view.data() };
  644. for (int k=0; int sk: s) {
  645. Dim & dest = r.dimv[sk];
  646. dest.step += view.dimv[k].step;
  647. dest.len = dest.len>=0 ? std::min(dest.len, view.dimv[k].len) : view.dimv[k].len;
  648. ++k;
  649. }
  650. return r;
  651. }
  652. template <class T, rank_t RANK, class S>
  653. inline View<T, ANY>
  654. transpose(S && s, View<T, RANK> const & view)
  655. {
  656. return transpose_(RA_FWD(s), view);
  657. }
  658. // Need compile time values and not sizes to deduce the output rank, so a builtin array shim (as for reshape()) would be useless.
  659. template <class T, rank_t RANK>
  660. inline View<T, ANY>
  661. transpose(std::initializer_list<ra::rank_t> s, View<T, RANK> const & view)
  662. {
  663. return transpose_(s, view);
  664. }
  665. // Static transposed axes list.
  666. template <int ... Iarg, class T, rank_t RANK>
  667. inline auto
  668. transpose(View<T, RANK> const & view)
  669. {
  670. static_assert(RANK==ANY || RANK==sizeof...(Iarg), "Bad output rank.");
  671. RA_CHECK(view.rank()==sizeof...(Iarg), "Bad output rank: ", view.rank(), "should be ", (sizeof...(Iarg)), ".");
  672. using dummy_s = mp::makelist<sizeof...(Iarg), ic_t<0>>;
  673. using ti = axes_list_indices<mp::int_list<Iarg ...>, dummy_s, dummy_s>;
  674. constexpr rank_t DSTRANK = mp::len<typename ti::dst>;
  675. View<T, DSTRANK> r { decltype(r.dimv)(Dim { BAD, 0 }), view.data() };
  676. std::array<int, sizeof...(Iarg)> s {{ Iarg ... }};
  677. for (int k=0; int sk: s) {
  678. Dim & dest = r.dimv[sk];
  679. dest.step += view.dimv[k].step;
  680. dest.len = dest.len>=0 ? std::min(dest.len, view.dimv[k].len) : view.dimv[k].len;
  681. ++k;
  682. }
  683. return r;
  684. }
  685. template <class T, rank_t RANK>
  686. inline auto
  687. diag(View<T, RANK> const & view)
  688. {
  689. return transpose<0, 0>(view);
  690. }
  691. template <class T, rank_t RANK>
  692. inline View<T, 1>
  693. ravel_free(View<T, RANK> const & a)
  694. {
  695. RA_CHECK(is_c_order(a, false));
  696. int r = a.rank()-1;
  697. for (; r>=0 && a.len(r)==1; --r) {}
  698. ra::dim_t s = r<0 ? 1 : a.step(r);
  699. return ra::View<T, 1>({{size(a), s}}, a.cp);
  700. }
  701. template <class T, rank_t RANK, class S>
  702. inline auto
  703. reshape_(View<T, RANK> const & a, S && sb_)
  704. {
  705. auto sb = concrete(RA_FWD(sb_));
  706. // FIXME when we need to copy, accept/return Shared
  707. dim_t la = ra::size(a);
  708. dim_t lb = 1;
  709. for (int i=0; i<ra::size(sb); ++i) {
  710. if (sb[i]==-1) {
  711. dim_t quot = lb;
  712. for (int j=i+1; j<ra::size(sb); ++j) {
  713. quot *= sb[j];
  714. RA_CHECK(quot>0, "Cannot deduce dimensions.");
  715. }
  716. auto pv = la/quot;
  717. RA_CHECK((la%quot==0 && pv>=0), "Bad placeholder.");
  718. sb[i] = pv;
  719. lb = la;
  720. break;
  721. } else {
  722. lb *= sb[i];
  723. }
  724. }
  725. auto sa = shape(a);
  726. // FIXME should be able to reshape Scalar etc.
  727. View<T, ra::size_s(sb)> b(map([](auto i) { return Dim { BAD, 0 }; }, ra::iota(ra::size(sb))), a.data());
  728. rank_t i = 0;
  729. for (; i<a.rank() && i<b.rank(); ++i) {
  730. if (sa[a.rank()-i-1]!=sb[b.rank()-i-1]) {
  731. assert(is_c_order(a, false) && "reshape w/copy not implemented"); // FIXME bad abort [ra17]
  732. if (la>=lb) {
  733. // FIXME View(SS const & s, T * p). Cf [ra37].
  734. filldim(b.dimv, sb);
  735. for (int j=0; j!=b.rank(); ++j) {
  736. b.dimv[j].step *= a.step(a.rank()-1);
  737. }
  738. return b;
  739. } else {
  740. assert(0 && "reshape case not implemented"); // FIXME bad abort [ra17]
  741. }
  742. } else {
  743. // select
  744. b.dimv[b.rank()-i-1] = a.dimv[a.rank()-i-1];
  745. }
  746. }
  747. if (i==a.rank()) {
  748. // tile & return
  749. for (rank_t j=i; j<b.rank(); ++j) {
  750. b.dimv[b.rank()-j-1] = { sb[b.rank()-j-1], 0 };
  751. }
  752. }
  753. return b;
  754. }
  755. template <class T, rank_t RANK, class S>
  756. inline auto
  757. reshape(View<T, RANK> const & a, S && sb_)
  758. {
  759. return reshape_(a, RA_FWD(sb_));
  760. }
  761. // We need dimtype bc {1, ...} deduces to int and that fails to match ra::dim_t. initializer_list could handle the general case, but the result would have var rank and would override this one (?).
  762. template <class T, rank_t RANK, class dimtype, int N>
  763. inline auto
  764. reshape(View<T, RANK> const & a, dimtype const (&sb_)[N])
  765. {
  766. return reshape_(a, sb_);
  767. }
  768. // lo: lower bounds, hi: upper bounds. The stencil indices are in [0 lo+1+hi] = [-lo +hi].
  769. template <class LO, class HI, class T, rank_t N>
  770. inline View<T, rank_sum(N, N)>
  771. stencil(View<T, N> const & a, LO && lo, HI && hi)
  772. {
  773. View<T, rank_sum(N, N)> s;
  774. s.cp = a.data();
  775. ra::resize(s.dimv, 2*a.rank());
  776. RA_CHECK(every(lo>=0) && every(hi>=0), "Bad stencil bounds lo ", noshape, lo, " hi ", noshape, hi, ".");
  777. for_each([](auto & dims, auto && dima, auto && lo, auto && hi)
  778. {
  779. RA_CHECK(dima.len>=lo+hi, "Stencil is too large for array.");
  780. dims = {dima.len-lo-hi, dima.step};
  781. },
  782. ptr(s.dimv.data()), a.dimv, lo, hi);
  783. for_each([](auto & dims, auto && dima, auto && lo, auto && hi)
  784. { dims = {lo+hi+1, dima.step}; },
  785. ptr(s.dimv.data()+a.rank()), a.dimv, lo, hi);
  786. return s;
  787. }
  788. // Make last sizes of View<> be compile-time constants.
  789. template <class super_t, rank_t SUPERR, class T, rank_t RANK>
  790. inline auto
  791. explode_(View<T, RANK> const & a)
  792. {
  793. // TODO Reduce to single check, either the first or the second.
  794. static_assert(RANK>=SUPERR || RANK==ANY, "rank of a is too low");
  795. RA_CHECK(a.rank()>=SUPERR, "Rank of a ", a.rank(), " should be at least ", SUPERR, ".");
  796. View<super_t, rank_sum(RANK, -SUPERR)> b;
  797. ra::resize(b.dimv, a.rank()-SUPERR);
  798. dim_t r = 1;
  799. for (int i=0; i<SUPERR; ++i) {
  800. r *= a.len(i+b.rank());
  801. }
  802. RA_CHECK(r*sizeof(T)==sizeof(super_t), "Length of axes ", r*sizeof(T), " doesn't match type ", sizeof(super_t), ".");
  803. for (int i=0; i<b.rank(); ++i) {
  804. RA_CHECK(a.step(i) % r==0, "Step of axes ", a.step(i), " doesn't match type ", r, " on axis ", i, ".");
  805. b.dimv[i] = { .len = a.len(i), .step = a.step(i) / r };
  806. }
  807. RA_CHECK((b.rank()==0 || a.step(b.rank()-1)==r), "Super type is not compact in array.");
  808. b.cp = reinterpret_cast<super_t *>(a.data());
  809. return b;
  810. }
  811. template <class super_t, class T, rank_t RANK>
  812. inline auto
  813. explode(View<T, RANK> const & a)
  814. {
  815. return explode_<super_t, (std::is_same_v<super_t, std::complex<T>> ? 1 : rank_s<super_t>())>(a);
  816. }
  817. // FIXME Maybe namespace level generics in atom.hh
  818. template <class T> inline int gstep(int i) { if constexpr (is_scalar<T>) return 1; else return T::step(i); }
  819. template <class T> inline int glen(int i) { if constexpr (is_scalar<T>) return 1; else return T::len(i); }
  820. // TODO The ranks below SUBR must be compact, which is not checked.
  821. template <class sub_t, class super_t, rank_t RANK>
  822. inline auto
  823. collapse(View<super_t, RANK> const & a)
  824. {
  825. using super_v = value_t<super_t>;
  826. using sub_v = value_t<sub_t>;
  827. constexpr int subtype = sizeof(super_v)/sizeof(sub_t);
  828. constexpr int SUBR = rank_s<super_t>() - rank_s<sub_t>();
  829. View<sub_t, rank_sum(RANK, SUBR+int(subtype>1))> b;
  830. resize(b.dimv, a.rank()+SUBR+int(subtype>1));
  831. constexpr dim_t r = sizeof(super_t)/sizeof(sub_t);
  832. static_assert(sizeof(super_t)==r*sizeof(sub_t), "Cannot make axis of super_t from sub_t.");
  833. for (int i=0; i<a.rank(); ++i) {
  834. b.dimv[i] = { .len = a.len(i), .step = a.step(i) * r };
  835. }
  836. constexpr int t = sizeof(super_v)/sizeof(sub_v);
  837. constexpr int s = sizeof(sub_t)/sizeof(sub_v);
  838. static_assert(t*sizeof(sub_v)>=1, "Bad subtype.");
  839. for (int i=0; i<SUBR; ++i) {
  840. RA_CHECK(((gstep<super_t>(i)/s)*s==gstep<super_t>(i)), "Bad steps."); // TODO actually static
  841. b.dimv[a.rank()+i] = { .len = glen<super_t>(i), .step = gstep<super_t>(i) / s * t };
  842. }
  843. if (subtype>1) {
  844. b.dimv[a.rank()+SUBR] = { .len = t, .step = 1 };
  845. }
  846. b.cp = reinterpret_cast<sub_t *>(a.data());
  847. return b;
  848. }
  849. } // namespace ra