ra-operators.H 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. // (c) Daniel Llorens - 2014-2015
  2. // This library is free software; you can redistribute it and/or modify it under
  3. // the terms of the GNU Lesser General Public License as published by the Free
  4. // Software Foundation; either version 3 of the License, or (at your option) any
  5. // later version.
  6. #ifndef RA_OPERATORS_H
  7. #define RA_OPERATORS_H
  8. /// @file ra-operators.H
  9. /// @brief Sugar for ra:: expression templates.
  10. #include "ra/ra-wrank.H"
  11. // @TODO These (dependence on specific ra:: types) should be elsewhere.
  12. #include "ra/ra-small.H"
  13. #include "ra/ra-large.H"
  14. #include "ra/complex.H"
  15. #include "ra/wedge.H"
  16. #ifdef RA_CHECK_BOUNDS
  17. #define RA_CHECK_BOUNDS_RA_OPERATORS RA_CHECK_BOUNDS
  18. #else
  19. #ifndef RA_CHECK_BOUNDS_RA_OPERATORS
  20. #define RA_CHECK_BOUNDS_RA_OPERATORS 1
  21. #endif
  22. #endif
  23. #if RA_CHECK_BOUNDS_RA_OPERATORS==0
  24. #define CHECK_BOUNDS( cond )
  25. #else
  26. #define CHECK_BOUNDS( cond ) assert( cond )
  27. #endif
  28. #include "ra/ra-optimize.H"
  29. #ifndef RA_OPTIMIZE
  30. #define RA_OPTIMIZE 1 // enabled by default
  31. #endif
  32. #if RA_OPTIMIZE==1
  33. #define OPTIMIZE optimize
  34. #else
  35. #define OPTIMIZE
  36. #endif
  37. #define START(a) *(ra::start(a).flat())
  38. // See ::wedge() in ra/wedge.H, need ra::is_scalar<> to define.
  39. // These ra::start are needed b/c rank 0 converts to and from scalar, so ? can't pick the right (-> scalar) conversion.
  40. template <class T, class F,
  41. enableif_<mp::And<ra::is_zero_or_scalar<T>, ra::is_zero_or_scalar<F> >, int> =0>
  42. inline decltype(auto) where(bool const w, T && t, F && f) { return w ? START(t) : START(f); }
  43. namespace ra {
  44. // Wrappers over expr & ply_either.
  45. template <class F, class ... A>
  46. inline auto map(F && f, A && ... a) -> decltype(expr(std::forward<F>(f), start(std::forward<A>(a)) ...))
  47. {
  48. return expr(std::forward<F>(f), start(std::forward<A>(a)) ...);
  49. }
  50. template <class F, class ... A>
  51. inline void for_each(F && f, A && ... a)
  52. {
  53. ply_either(expr(std::forward<F>(f), start(std::forward<A>(a)) ...));
  54. }
  55. // I considered three options for lookup.
  56. // 1. define these in a class that ArrayIterator or Container or Slice types derive from. This was done for an old library I had (vector-ops.H). It results in the narrowest scope, but since those types are used in the definition (ra::Expr is an ArrayIterator), it requires lots of forwarding and traits:: .
  57. // 2. raw ADL doesn't work because some ra:: types use ! != etc for different things (e.g. FlatIterator). Possible solution: don't ever use + != == for FlatIterator.
  58. // 3. enable_if'd ADL is what you see here.
  59. // --------------------------------
  60. // Array versions of operators and functions
  61. // --------------------------------
  62. // We need the zero/scalar specializations because the scalar/scalar operators
  63. // maybe be templated (e.g. complex<>), so they won't be found when an implicit
  64. // conversion from zero->scalar is also needed. That is, without those
  65. // specializations, ra::Raw<complex, 0> * complex will fail.
  66. // These depend on OPNAME defined in ra-optimize.H and used there to match ET patterns.
  67. #define DEFINE_NAMED_BINARY_OP(OPERATOR, OP, OPNAME) \
  68. template <class A, class B, enableif_<ra_pos_and_any<A, B>, int> =0> \
  69. inline auto OPERATOR(A && a, B && b) \
  70. { \
  71. return OPTIMIZE(map(OPNAME(), std::forward<A>(a), std::forward<B>(b))); \
  72. } \
  73. template <class A, class B, enableif_<ra_zero<A, B>, int> =0> \
  74. inline auto OPERATOR(A && a, B && b) \
  75. { \
  76. return START(a) OP START(b); \
  77. }
  78. DEFINE_NAMED_BINARY_OP(operator+, +, plus)
  79. DEFINE_NAMED_BINARY_OP(operator-, -, minus)
  80. DEFINE_NAMED_BINARY_OP(operator*, *, times)
  81. DEFINE_NAMED_BINARY_OP(operator/, /, slash)
  82. #undef DEFINE_NAMED_BINARY_OP
  83. #define DEFINE_BINARY_OP(OPERATOR, OP) \
  84. template <class A, class B, enableif_<ra_pos_and_any<A, B>, int> =0> \
  85. inline auto OPERATOR(A && a, B && b) \
  86. { \
  87. return map([](auto && a, auto && b) { return a OP b; }, \
  88. std::forward<A>(a), std::forward<B>(b)); \
  89. } \
  90. template <class A, class B, enableif_<ra_zero<A, B>, int> =0> \
  91. inline auto OPERATOR(A && a, B && b) \
  92. { \
  93. return START(a) OP START(b); \
  94. }
  95. DEFINE_BINARY_OP(operator&&, &&)
  96. DEFINE_BINARY_OP(operator||, ||)
  97. DEFINE_BINARY_OP(operator>, >)
  98. DEFINE_BINARY_OP(operator<, <)
  99. DEFINE_BINARY_OP(operator>=, >=)
  100. DEFINE_BINARY_OP(operator<=, <=)
  101. DEFINE_BINARY_OP(operator==, ==)
  102. DEFINE_BINARY_OP(operator!=, !=)
  103. #undef DEFINE_BINARY_OP
  104. #define DEFINE_UNARY_OP(OPNAME, OP) \
  105. template <class A, enableif_<is_ra_pos_rank<A>, int> = 0> \
  106. inline auto OPNAME(A && a) \
  107. { \
  108. return map([](auto && a) { return OP a; }, std::forward<A>(a)); \
  109. }
  110. DEFINE_UNARY_OP(operator!, !)
  111. DEFINE_UNARY_OP(operator+, +) // @TODO Make into nop.
  112. DEFINE_UNARY_OP(operator-, -)
  113. #undef DEFINE_UNARY_OP
  114. // When OP(a) isn't found from ra::, the deduction from rank(0) -> scalar doesn't work.
  115. // @TODO Cf [ref:examples/useret.C:0] for examples.
  116. #define DEFINE_NAME_OP(OPNAME, OP) \
  117. using ::OP; \
  118. template <class ... A, enableif_<ra_pos_and_any<A ...>, int> =0> \
  119. inline auto OPNAME(A && ... a) \
  120. { \
  121. return map([](auto && ... a) { return OP(a ...); }, std::forward<A>(a) ...); \
  122. } \
  123. template <class ... A, enableif_<ra_zero<A ...>, int> =0> \
  124. inline auto OPNAME(A && ... a) \
  125. { \
  126. return OP(START(a) ...); \
  127. }
  128. DEFINE_NAME_OP(rel_error, rel_error)
  129. DEFINE_NAME_OP(pow, pow)
  130. DEFINE_NAME_OP(xI, xI)
  131. DEFINE_NAME_OP(conj, conj)
  132. DEFINE_NAME_OP(sqr, sqr)
  133. DEFINE_NAME_OP(sqrm, sqrm)
  134. DEFINE_NAME_OP(abs, abs)
  135. DEFINE_NAME_OP(real_part, real_part)
  136. DEFINE_NAME_OP(imag_part, imag_part)
  137. DEFINE_NAME_OP(cos, cos)
  138. DEFINE_NAME_OP(sin, sin)
  139. DEFINE_NAME_OP(exp, exp)
  140. DEFINE_NAME_OP(sqrt, sqrt)
  141. DEFINE_NAME_OP(log, log)
  142. DEFINE_NAME_OP(log1p, log1p)
  143. DEFINE_NAME_OP(isfinite, isfinite)
  144. DEFINE_NAME_OP(isnan, isnan)
  145. DEFINE_NAME_OP(isinf, isinf)
  146. #undef DEFINE_NAME_OP
  147. template <class T, class A>
  148. inline auto cast(A && a)
  149. {
  150. return map([](auto && a) { return T(a); }, std::forward<A>(a));
  151. }
  152. // --------------------------------
  153. // Ternary op
  154. // --------------------------------
  155. // needed when ? returns rvalue reference.
  156. template <class T>
  157. inline auto safe_rvalue(T & t) -> decltype(auto)
  158. {
  159. return t;
  160. }
  161. template <class T>
  162. inline auto safe_rvalue(T && t) -> T
  163. {
  164. return t;
  165. }
  166. // @TODO use instead
  167. // typename safe_rvalue<decltype(t_), decltype(f_), decltype(w_ ? std::forward<decltype(t_)>(t_) : std::forward<decltype(f_)>(f_))>::type
  168. // template <class T, class F, class R, class Enable=void>
  169. // struct safe_rvalue
  170. // {
  171. // using type = R;
  172. // };
  173. // template <class T, class F, class R>
  174. // struct safe_rvalue<T, F, R, enableif_<mp::And<std::is_rvalue_reference<T>, std::is_rvalue_reference<F> > > >
  175. // {
  176. // using type = std::decay_t<R>;
  177. // };
  178. // http://scottmeyers.blogspot.ch/2013/05/c14-lambdas-and-perfect-forwarding.html
  179. // @TODO only one of t or f should be evaluated. But that probably requires where() to be a different type from Expr.
  180. template <class W, class T, class F, enableif_<mp::Or<is_ra_pos_rank<W>, is_ra_pos_rank<T>, is_ra_pos_rank<F> >, int> = 0>
  181. inline auto where(W && w, T && t, F && f)
  182. {
  183. return map([](auto && w_, auto && t_, auto && f_) -> decltype(auto)
  184. {
  185. return safe_rvalue(w_ ? std::forward<decltype(t_)>(t_) : std::forward<decltype(f_)>(f_));
  186. },
  187. std::forward<W>(w), std::forward<T>(t), std::forward<F>(f));
  188. }
  189. // --------------------------------
  190. // Some whole-array reductions.
  191. // --------------------------------
  192. // @TODO First rank reductions? Variable rank reductions?
  193. // @TODO Give return type once. gcc gives trouble.
  194. template <class A>
  195. inline auto reduce_sqrm(A && a) -> std::decay_t<decltype(sqrm(START(a)))>
  196. {
  197. std::decay_t<decltype(sqrm(START(a)))> c(0.);
  198. for_each([&c](auto a) { c += sqrm(a); }, a);
  199. return c;
  200. }
  201. template <class A>
  202. inline auto norm2(A && a)
  203. {
  204. return sqrt(reduce_sqrm(a));
  205. }
  206. using std::min;
  207. using std::max;
  208. template <class A>
  209. inline auto amin(A && a) -> std::decay_t<decltype(START(a))>
  210. {
  211. using T = std::decay_t<decltype(START(a))>;
  212. T c(std::numeric_limits<T>::max());
  213. for_each([&c](auto && a) { c = min(c, a); }, a);
  214. return c;
  215. }
  216. template <class A>
  217. inline auto amax(A && a) -> std::decay_t<decltype(START(a))>
  218. {
  219. using T = std::decay_t<decltype(START(a))>;
  220. T c(std::numeric_limits<T>::lowest());
  221. for_each([&c](auto && a) { c = max(c, a); }, a);
  222. return c;
  223. }
  224. template <class A>
  225. inline auto sum(A && a) -> std::decay_t<decltype(START(a))>
  226. {
  227. std::decay_t<decltype(START(a))> c(0.);
  228. for_each([&c](auto && a) { c += a; }, a);
  229. return c;
  230. }
  231. template <class A>
  232. inline auto prod(A && a) -> std::decay_t<decltype(START(a))>
  233. {
  234. std::decay_t<decltype(START(a))> c(1.);
  235. for_each([&c](auto && a) { c *= a; }, a);
  236. return c;
  237. }
  238. template <class A, class B>
  239. inline auto dot(A && a, B && b) -> std::decay_t<decltype(START(a) * START(b))>
  240. {
  241. std::decay_t<decltype(START(a) * START(b))> c(0.);
  242. for_each([&c](auto && a, auto && b) { c = fma(a, b, c); }, a, b);
  243. return c;
  244. }
  245. template <class A, class B>
  246. inline auto cdot(A && a, B && b) -> std::decay_t<decltype(conj(START(a)) * START(b))>
  247. {
  248. std::decay_t<decltype(conj(START(a)) * START(b))> c(0.);
  249. for_each([&c](auto && a, auto && b) { c = fma_conj(a, b, c); }, a, b);
  250. return c;
  251. }
  252. // --------------------
  253. // Wedge product
  254. // @TODO Handle the simplifications dot_plus, yields_scalar, etc. just as vec::wedge does.
  255. // --------------------
  256. template <class A>
  257. struct torank1
  258. {
  259. using type = mp::If_<is_scalar<A>::value, Small<std::decay_t<A>, 1>, A>;
  260. };
  261. template <class Wedge, class Va, class Vb, class Enable=void>
  262. struct fromrank1
  263. {
  264. using valtype = typename Wedge::template valtype<Va, Vb>;
  265. using type = mp::If_<Wedge::Nr==1, valtype, Small<valtype, Wedge::Nr> >;
  266. };
  267. #define DECL_WEDGE(condition) \
  268. template <int D, int Oa, int Ob, class Va, class Vb, \
  269. enableif_<mp::Not<mp::And<is_scalar<Va>, is_scalar<Vb>>>, int> =0> \
  270. decltype(auto) wedge(Va const & a, Vb const & b)
  271. DECL_WEDGE(general_case)
  272. {
  273. Small<std::decay_t<decltype(START(a))>, decltype(start(a))::size_s()> aa = a;
  274. Small<std::decay_t<decltype(START(b))>, decltype(start(b))::size_s()> bb = b;
  275. using Ua = decltype(aa);
  276. using Ub = decltype(bb);
  277. typename fromrank1<fun::Wedge<D, Oa, Ob>, Ua, Ub>::type r;
  278. auto & r1 = reinterpret_cast<typename torank1<decltype(r)>::type &>(r);
  279. auto & a1 = reinterpret_cast<typename torank1<Ua>::type const &>(aa);
  280. auto & b1 = reinterpret_cast<typename torank1<Ub>::type const &>(bb);
  281. fun::Wedge<D, Oa, Ob>::product(a1, b1, r1);
  282. return r;
  283. }
  284. #undef DECL_WEDGE
  285. #define DECL_WEDGE(condition) \
  286. template <int D, int Oa, int Ob, class Va, class Vb, class Vr, \
  287. enableif_<mp::Not<mp::And<is_scalar<Va>, is_scalar<Vb>>>, int> =0> \
  288. void wedge(Va const & a, Vb const & b, Vr & r)
  289. DECL_WEDGE(general_case)
  290. {
  291. Small<std::decay_t<decltype(START(a))>, decltype(start(a))::size_s()> aa = a;
  292. Small<std::decay_t<decltype(START(b))>, decltype(start(b))::size_s()> bb = b;
  293. using Ua = decltype(aa);
  294. using Ub = decltype(bb);
  295. auto & r1 = reinterpret_cast<typename torank1<decltype(r)>::type &>(r);
  296. auto & a1 = reinterpret_cast<typename torank1<Ua>::type const &>(aa);
  297. auto & b1 = reinterpret_cast<typename torank1<Ub>::type const &>(bb);
  298. fun::Wedge<D, Oa, Ob>::product(a1, b1, r1);
  299. }
  300. #undef DECL_WEDGE
  301. template <class A, class B, std::enable_if_t<std::decay_t<A>::size_s()==2 && std::decay_t<B>::size_s()==2, int> =0>
  302. inline auto cross(A const & a_, B const & b_)
  303. {
  304. Small<std::decay_t<decltype(START(a_))>, 2> a = a_;
  305. Small<std::decay_t<decltype(START(b_))>, 2> b = b_;
  306. Small<std::decay_t<decltype(START(a_) * START(b_))>, 1> r;
  307. fun::Wedge<2, 1, 1>::product(a, b, r);
  308. return r[0];
  309. }
  310. template <class A, class B, std::enable_if_t<std::decay_t<A>::size_s()==3 && std::decay_t<B>::size_s()==3, int> =0>
  311. inline auto cross(A const & a_, B const & b_)
  312. {
  313. Small<std::decay_t<decltype(START(a_))>, 3> a = a_;
  314. Small<std::decay_t<decltype(START(b_))>, 3> b = b_;
  315. Small<std::decay_t<decltype(START(a_) * START(b_))>, 3> r;
  316. fun::Wedge<3, 1, 1>::product(a, b, r);
  317. return r;
  318. }
  319. template <class V>
  320. inline auto perp(V const & v)
  321. {
  322. static_assert(v.size()==2, "dimension error");
  323. return Small<std::decay_t<decltype(START(v))>, 2> {v[1], -v[0]};
  324. }
  325. template <class V, class U, enableif_<is_scalar<U>, int> =0>
  326. inline auto perp(V const & v, U const & n)
  327. {
  328. static_assert(v.size()==2, "dimension error");
  329. return Small<std::decay_t<decltype(START(v) * n)>, 2> {v[1]*n, -v[0]*n};
  330. }
  331. template <class V, class U, std::enable_if_t<!is_scalar<U>::value, int> =0>
  332. inline auto perp(V const & v, U const & n)
  333. {
  334. static_assert(v.size()==3, "dimension error");
  335. return cross(v, n);
  336. }
  337. // --------------------
  338. // Other whole-array ops. @TODO Cleaner way to get concrete types from maybe-exprs. (expr:: had resolve()).
  339. // --------------------
  340. // @TODO Would like to be able to return just a/norm2(a) without temp-ref errors.
  341. template <class A, enableif_<is_slice<A>, int> =0>
  342. inline auto normv(A const & a)
  343. {
  344. static_assert(A::size_s()!=DIM_ANY, "waiting for ra::resolve or some such"); // gcc accepts a.size_s()
  345. using V = Small<std::decay_t<decltype(START(a))>, A::size_s()>;
  346. return V(a/norm2(a));
  347. }
  348. template <class A, std::enable_if_t<!is_slice<A>::value && is_ra<A>::value, int> =0>
  349. inline auto normv(A const & a)
  350. {
  351. static_assert(A::size_s()!=DIM_ANY, "waiting for ra::resolve or some such"); // gcc accepts a.size_s()
  352. using V = Small<std::decay_t<decltype(START(a))>, A::size_s()>;
  353. V b = a;
  354. b /= norm2(b);
  355. return b;
  356. }
  357. #undef START
  358. // @TODO Define within generalization...
  359. // @TODO Plain auto causes problems witn transform() in mat-fun.H:transform().
  360. template <class A, class B>
  361. inline ra::Small<decltype(std::declval<A>()(0, 0)*std::declval<B>()(0, 0)), A::size(0), B::size(1)>
  362. gemm(A const & a, B const & b)
  363. {
  364. constexpr int M = a.size(0);
  365. constexpr int N = b.size(1);
  366. ra::Small<decltype(a(0, 0)*b(0, 0)), M, N> c;
  367. for (int i=0; i<M; ++i) {
  368. for (int j=0; j<N; ++j) {
  369. c(i, j) = dot(a(i), b(ra::all, j));
  370. }
  371. }
  372. return c;
  373. }
  374. // the default for row-major x row-major. See bench-ra-mmul.C for variants.
  375. template <class S, class T>
  376. inline auto
  377. gemm(ra::Raw<S, 2> const & a, ra::Raw<T, 2> const & b)
  378. {
  379. int const M = a.size(0);
  380. int const N = b.size(1);
  381. int const K = a.size(1);
  382. ra::Owned<decltype(a(0, 0)*b(0, 0)), 2> c({M, N}, 0.);
  383. for (int k=0; k<K; ++k) {
  384. c += from(times(), a(ra::all, k), b(k, ra::all));
  385. }
  386. return c;
  387. }
  388. template <class A, class B>
  389. inline ra::Small<decltype(std::declval<A>()(0)*std::declval<B>()(0, 0)), B::size(1)>
  390. gevm(A const & a, B const & b)
  391. {
  392. constexpr int N = b.size(1);
  393. ra::Small<decltype(a(0)*b(0, 0)), N> c;
  394. for (int j=0; j<N; ++j) {
  395. c(j) = dot(a, b(ra::all, j));
  396. }
  397. return c;
  398. }
  399. template <class S, class T>
  400. inline auto
  401. gevm(ra::Raw<S, 1> const & a, ra::Raw<T, 2> const & b)
  402. {
  403. int N = b.size(1);
  404. ra::Owned<decltype(a(0)*b(0, 0))> c({N}, ra::unspecified);
  405. for (int j=0; j<N; ++j) {
  406. c(j) = dot(a, b(ra::all, j));
  407. }
  408. return c;
  409. }
  410. template <class A, class B>
  411. inline ra::Small<decltype(std::declval<A>()(0, 0)*std::declval<B>()(0)), A::size(0)>
  412. gemv(A const & a, B const & b)
  413. {
  414. constexpr int M = a.size(0);
  415. ra::Small<decltype(a(0, 0)*b(0)), M> c;
  416. for (int i=0; i<M; ++i) {
  417. c(i) = dot(a(i), b);
  418. }
  419. return c;
  420. }
  421. template <class S, class T>
  422. inline auto
  423. gemv(ra::Raw<S, 2> const & a, ra::Raw<T, 1> const & b)
  424. {
  425. int M = a.size(0);
  426. ra::Owned<decltype(a(0, 0)*b(0)), 1> c({M}, ra::unspecified);
  427. for (int i=0; i<M; ++i) {
  428. c(i) = dot(a(i), b);
  429. }
  430. return c;
  431. }
  432. // --------------------
  433. // I/O operators.
  434. // --------------------
  435. // a version of ply_index(). @TODO Eventually try to merge with that.
  436. // is_foreign_vector is included b/c std::vector or std::array may be used as shape_type.
  437. template <class A> inline
  438. enableif_<mp::Or<is_ra<A>, is_foreign_vector<A> >, std::ostream &>
  439. operator<<(std::ostream & o, A && a_)
  440. {
  441. // work with ArrayIterator
  442. auto a = ra::start(std::forward<A>(a_));
  443. static_assert(decltype(a)::size_s()!=DIM_BAD, "cannot print type");
  444. rank_t const rank = a.rank();
  445. auto sha(a.shape());
  446. if (a.size_s()==DIM_ANY) {
  447. o << start(sha) << '\n';
  448. }
  449. // @TODO Scalar doesn't have done(), so avoid that. Concepts aren't well specified...
  450. if (any(start(sha)==0)) {
  451. return o;
  452. }
  453. auto ind = ra_traits<decltype(sha)>::make(rank, 0);
  454. // unlike in ply_index(), order here is row-major on purpose.
  455. for (;;) {
  456. next: ;
  457. o << a.at(ind) << " ";
  458. for (int k=0; k<rank; ++k) {
  459. if (++ind[rank-1-k]<sha[rank-1-k]) {
  460. std::fill_n(std::ostream_iterator<char>(o, ""), k, '\n');
  461. goto next;
  462. } else {
  463. ind[rank-1-k] = 0;
  464. }
  465. }
  466. return o;
  467. }
  468. }
  469. // Static size.
  470. template <class C> inline
  471. std::enable_if_t<ra_traits<C>::size_s()!=DIM_ANY, std::istream &>
  472. operator>>(std::istream & i, C & c)
  473. {
  474. using T = typename ra_traits<C>::value_type;
  475. std::copy_n(std::istream_iterator<T>(i), c.size(), c.begin());
  476. return i;
  477. }
  478. // Special case for std::vector, to handle create-new / resize() difference.
  479. template <class T, class A> inline
  480. std::istream &
  481. operator>>(std::istream & i, std::vector<T, A> & c)
  482. {
  483. dim_t n;
  484. i >> n;
  485. assert(n>=0);
  486. if (i) {
  487. c.resize(n);
  488. std::copy_n(std::istream_iterator<T>(i), c.size(), c.begin());
  489. }
  490. return i;
  491. }
  492. // Expr size, so read shape and possibly allocate (@TODO try to avoid).
  493. template <class C> inline
  494. std::enable_if_t<ra_traits<C>::size_s()==DIM_ANY, std::istream &>
  495. operator>>(std::istream & i, C & c)
  496. {
  497. using T = typename ra_traits<C>::value_type;
  498. typename ra_traits<C>::shape_type s;
  499. i >> s;
  500. if (i) {
  501. c = std::decay_t<C>(s, ra::unspecified);
  502. if (c.size()>0) { // I'd say a bug in copy_n; see failing case in test-ra-nested.C.
  503. std::copy_n(std::istream_iterator<T>(i), c.size(), c.begin());
  504. }
  505. }
  506. return i;
  507. }
  508. } // namespace ra
  509. #undef CHECK_BOUNDS
  510. #undef RA_CHECK_BOUNDS_RA_OPERATORS
  511. #endif // RA_OPERATORS_H