xview.hpp 82 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317
  1. /***************************************************************************
  2. * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
  3. * Copyright (c) QuantStack *
  4. * *
  5. * Distributed under the terms of the BSD 3-Clause License. *
  6. * *
  7. * The full license is in the file LICENSE, distributed with this software. *
  8. ****************************************************************************/
  9. #ifndef XTENSOR_VIEW_HPP
  10. #define XTENSOR_VIEW_HPP
  11. #include <algorithm>
  12. #include <array>
  13. #include <cstddef>
  14. #include <tuple>
  15. #include <type_traits>
  16. #include <utility>
  17. #include <xtl/xclosure.hpp>
  18. #include <xtl/xmeta_utils.hpp>
  19. #include <xtl/xsequence.hpp>
  20. #include <xtl/xtype_traits.hpp>
  21. #include "xaccessible.hpp"
  22. #include "xarray.hpp"
  23. #include "xbroadcast.hpp"
  24. #include "xcontainer.hpp"
  25. #include "xiterable.hpp"
  26. #include "xsemantic.hpp"
  27. #include "xslice.hpp"
  28. #include "xtensor.hpp"
  29. #include "xtensor_config.hpp"
  30. #include "xtensor_forward.hpp"
  31. #include "xview_utils.hpp"
  32. namespace xt
  33. {
  34. /*******************
  35. * xview extension *
  36. *******************/
  37. namespace extension
  38. {
  39. template <class Tag, class CT, class... S>
  40. struct xview_base_impl;
  41. template <class CT, class... S>
  42. struct xview_base_impl<xtensor_expression_tag, CT, S...>
  43. {
  44. using type = xtensor_empty_base;
  45. };
  46. template <class CT, class... S>
  47. struct xview_base : xview_base_impl<xexpression_tag_t<CT>, CT, S...>
  48. {
  49. };
  50. template <class CT, class... S>
  51. using xview_base_t = typename xview_base<CT, S...>::type;
  52. }
  53. /*********************
  54. * xview declaration *
  55. *********************/
  56. template <bool is_const, class CT, class... S>
  57. class xview_stepper;
  58. template <class ST, class... S>
  59. struct xview_shape_type;
  60. namespace detail
  61. {
  62. template <class T>
  63. struct is_xrange : std::false_type
  64. {
  65. };
  66. template <class T>
  67. struct is_xrange<xrange<T>> : std::true_type
  68. {
  69. };
  70. template <class S>
  71. struct is_xall_slice : std::false_type
  72. {
  73. };
  74. template <class T>
  75. struct is_xall_slice<xall<T>> : std::true_type
  76. {
  77. };
  78. template <layout_type L, bool valid, bool all_seen, bool range_seen, class V>
  79. struct is_contiguous_view_impl
  80. {
  81. static constexpr bool value = false;
  82. };
  83. template <class T>
  84. struct static_dimension
  85. {
  86. static constexpr std::ptrdiff_t value = -1;
  87. };
  88. template <class T, std::size_t N>
  89. struct static_dimension<std::array<T, N>>
  90. {
  91. static constexpr std::ptrdiff_t value = static_cast<std::ptrdiff_t>(N);
  92. };
  93. template <class T, std::size_t N>
  94. struct static_dimension<xt::const_array<T, N>>
  95. {
  96. static constexpr std::ptrdiff_t value = static_cast<std::ptrdiff_t>(N);
  97. };
  98. template <std::size_t... I>
  99. struct static_dimension<xt::fixed_shape<I...>>
  100. {
  101. static constexpr std::ptrdiff_t value = sizeof...(I);
  102. };
  103. // if we have the same number of integers as we have static dimensions
  104. // this can be interpreted like a xscalar
  105. template <class CT, class... S>
  106. struct is_xscalar_impl<xview<CT, S...>>
  107. {
  108. static constexpr bool value = static_cast<std::ptrdiff_t>(integral_count<S...>()
  109. ) == static_dimension<typename std::decay_t<CT>::shape_type>::value
  110. ? true
  111. : false;
  112. };
  113. template <class S>
  114. struct is_strided_slice_impl : std::true_type
  115. {
  116. };
  117. template <class T>
  118. struct is_strided_slice_impl<xkeep_slice<T>> : std::false_type
  119. {
  120. };
  121. template <class T>
  122. struct is_strided_slice_impl<xdrop_slice<T>> : std::false_type
  123. {
  124. };
  125. // If we have no discontiguous slices, we can calculate strides for this view.
  126. template <class E, class... S>
  127. struct is_strided_view
  128. : std::integral_constant<
  129. bool,
  130. xtl::conjunction<has_data_interface<E>, is_strided_slice_impl<std::decay_t<S>>...>::value>
  131. {
  132. };
  133. // if row major the view can only be (statically) computed as contiguous if:
  134. // any number of integers is followed by either one or no range which
  135. // are followed by explicit (or implicit) all's
  136. //
  137. // e.g.
  138. // (i, j, all(), all()) == contiguous
  139. // (i, range(0, 2), all()) == contiguous
  140. // (i) == contiguous (implicit all slices)
  141. // (i, all(), j) == *not* contiguous
  142. // (i, range(0, 2), range(0, 2)) == *not* contiguous etc.
  143. template <bool valid, bool all_seen, bool range_seen, class V>
  144. struct is_contiguous_view_impl<layout_type::row_major, valid, all_seen, range_seen, V>
  145. {
  146. using slice = xtl::mpl::front_t<V>;
  147. static constexpr bool is_range_slice = is_xrange<slice>::value;
  148. static constexpr bool is_int_slice = xtl::is_integral<slice>::value;
  149. static constexpr bool is_all_slice = is_xall_slice<slice>::value;
  150. static constexpr bool have_all_seen = all_seen || is_all_slice;
  151. static constexpr bool have_range_seen = is_range_slice;
  152. static constexpr bool is_valid = valid
  153. && (have_all_seen
  154. ? is_all_slice
  155. : (!range_seen && (is_int_slice || is_range_slice)));
  156. static constexpr bool value = is_contiguous_view_impl < layout_type::row_major, is_valid,
  157. have_all_seen, range_seen || is_range_slice,
  158. xtl::mpl::pop_front_t < V >> ::value;
  159. };
  160. template <bool valid, bool all_seen, bool range_seen>
  161. struct is_contiguous_view_impl<layout_type::row_major, valid, all_seen, range_seen, xtl::mpl::vector<>>
  162. {
  163. static constexpr bool value = valid;
  164. };
  165. // For column major the *same* but reverse is true -- with the additional
  166. // constraint that we have to know the dimension at compile time otherwise
  167. // we cannot make the decision as there might be implicit all's following.
  168. template <bool valid, bool int_seen, bool range_seen, class V>
  169. struct is_contiguous_view_impl<layout_type::column_major, valid, int_seen, range_seen, V>
  170. {
  171. using slice = xtl::mpl::front_t<V>;
  172. static constexpr bool is_range_slice = is_xrange<slice>::value;
  173. static constexpr bool is_int_slice = xtl::is_integral<slice>::value;
  174. static constexpr bool is_all_slice = is_xall_slice<slice>::value;
  175. static constexpr bool have_int_seen = int_seen || is_int_slice;
  176. static constexpr bool is_valid = valid
  177. && (have_int_seen
  178. ? is_int_slice
  179. : (!range_seen && (is_all_slice || is_range_slice)));
  180. static constexpr bool value = is_contiguous_view_impl < layout_type::column_major, is_valid,
  181. have_int_seen, is_range_slice || range_seen,
  182. xtl::mpl::pop_front_t < V >> ::value;
  183. };
  184. template <bool valid, bool int_seen, bool range_seen>
  185. struct is_contiguous_view_impl<layout_type::column_major, valid, int_seen, range_seen, xtl::mpl::vector<>>
  186. {
  187. static constexpr bool value = valid;
  188. };
  189. // TODO relax has_data_interface constraint here!
  190. template <class E, class... S>
  191. struct is_contiguous_view
  192. : std::integral_constant<
  193. bool,
  194. has_data_interface<E>::value
  195. && !(
  196. E::static_layout == layout_type::column_major
  197. && static_cast<std::size_t>(static_dimension<typename E::shape_type>::value) != sizeof...(S)
  198. )
  199. && is_contiguous_view_impl<E::static_layout, true, false, false, xtl::mpl::vector<S...>>::value>
  200. {
  201. };
  202. template <layout_type L, class T, std::ptrdiff_t offset>
  203. struct unwrap_offset_container
  204. {
  205. using type = void;
  206. };
  207. template <class T, std::ptrdiff_t offset>
  208. struct unwrap_offset_container<layout_type::row_major, T, offset>
  209. {
  210. using type = sequence_view<T, offset, static_dimension<T>::value>;
  211. };
  212. template <class T, std::ptrdiff_t start, std::ptrdiff_t end, std::ptrdiff_t offset>
  213. struct unwrap_offset_container<layout_type::row_major, sequence_view<T, start, end>, offset>
  214. {
  215. using type = sequence_view<T, start + offset, end>;
  216. };
  217. template <class T, std::ptrdiff_t offset>
  218. struct unwrap_offset_container<layout_type::column_major, T, offset>
  219. {
  220. using type = sequence_view<T, 0, static_dimension<T>::value - offset>;
  221. };
  222. template <class T, std::ptrdiff_t start, std::ptrdiff_t end, std::ptrdiff_t offset>
  223. struct unwrap_offset_container<layout_type::column_major, sequence_view<T, start, end>, offset>
  224. {
  225. using type = sequence_view<T, start, end - offset>;
  226. };
  227. template <class E, class... S>
  228. struct get_contigous_shape_type
  229. {
  230. // if we have no `range` in the slices we can re-use the shape with an offset
  231. using type = std::conditional_t<
  232. xtl::disjunction<is_xrange<S>...>::value,
  233. typename xview_shape_type<typename E::shape_type, S...>::type,
  234. // In the false branch we know that we have only integers at the front OR end, and NO range
  235. typename unwrap_offset_container<E::static_layout, typename E::inner_shape_type, integral_count<S...>()>::type>;
  236. };
  237. template <class T>
  238. struct is_sequence_view : std::integral_constant<bool, false>
  239. {
  240. };
  241. template <class T, std::ptrdiff_t S, std::ptrdiff_t E>
  242. struct is_sequence_view<sequence_view<T, S, E>> : std::integral_constant<bool, true>
  243. {
  244. };
  245. }
  246. template <class CT, class... S>
  247. struct xcontainer_inner_types<xview<CT, S...>>
  248. {
  249. using xexpression_type = std::decay_t<CT>;
  250. using reference = inner_reference_t<CT>;
  251. using const_reference = typename xexpression_type::const_reference;
  252. using size_type = typename xexpression_type::size_type;
  253. using temporary_type = view_temporary_type_t<xexpression_type, S...>;
  254. static constexpr layout_type layout = detail::is_contiguous_view<xexpression_type, S...>::value
  255. ? xexpression_type::static_layout
  256. : layout_type::dynamic;
  257. static constexpr bool is_const = std::is_const<std::remove_reference_t<CT>>::value;
  258. using extract_storage_type = xtl::mpl::eval_if_t<
  259. has_data_interface<xexpression_type>,
  260. detail::expr_storage_type<xexpression_type>,
  261. make_invalid_type<>>;
  262. using storage_type = std::conditional_t<is_const, const extract_storage_type, extract_storage_type>;
  263. };
  264. template <class CT, class... S>
  265. struct xiterable_inner_types<xview<CT, S...>>
  266. {
  267. using xexpression_type = std::decay_t<CT>;
  268. static constexpr bool is_strided_view = detail::is_strided_view<xexpression_type, S...>::value;
  269. static constexpr bool is_contiguous_view = detail::is_contiguous_view<xexpression_type, S...>::value;
  270. using inner_shape_type = std::conditional_t<
  271. is_contiguous_view,
  272. typename detail::get_contigous_shape_type<xexpression_type, S...>::type,
  273. typename xview_shape_type<typename xexpression_type::shape_type, S...>::type>;
  274. using stepper = std::conditional_t<
  275. is_strided_view,
  276. xstepper<xview<CT, S...>>,
  277. xview_stepper<std::is_const<std::remove_reference_t<CT>>::value, CT, S...>>;
  278. using const_stepper = std::conditional_t<
  279. is_strided_view,
  280. xstepper<const xview<CT, S...>>,
  281. xview_stepper<true, std::remove_cv_t<CT>, S...>>;
  282. };
  283. /**
  284. * @class xview
  285. * @brief Multidimensional view with tensor semantic.
  286. *
  287. * The xview class implements a multidimensional view with tensor
  288. * semantic. It is used to adapt the shape of an xexpression without
  289. * changing it. xview is not meant to be used directly, but
  290. * only with the \ref view helper functions.
  291. *
  292. * @tparam CT the closure type of the \ref xexpression to adapt
  293. * @tparam S the slices type describing the shape adaptation
  294. *
  295. * @sa view, range, all, newaxis, keep, drop
  296. */
  297. template <class CT, class... S>
  298. class xview : public xview_semantic<xview<CT, S...>>,
  299. public std::conditional_t<
  300. detail::is_contiguous_view<std::decay_t<CT>, S...>::value,
  301. xcontiguous_iterable<xview<CT, S...>>,
  302. xiterable<xview<CT, S...>>>,
  303. public xaccessible<xview<CT, S...>>,
  304. public extension::xview_base_t<CT, S...>
  305. {
  306. public:
  307. using self_type = xview<CT, S...>;
  308. using inner_types = xcontainer_inner_types<self_type>;
  309. using xexpression_type = std::decay_t<CT>;
  310. using semantic_base = xview_semantic<self_type>;
  311. using temporary_type = typename xcontainer_inner_types<self_type>::temporary_type;
  312. using accessible_base = xaccessible<self_type>;
  313. using extension_base = extension::xview_base_t<CT, S...>;
  314. using expression_tag = typename extension_base::expression_tag;
  315. static constexpr bool is_const = std::is_const<std::remove_reference_t<CT>>::value;
  316. using value_type = typename xexpression_type::value_type;
  317. using simd_value_type = xt_simd::simd_type<value_type>;
  318. using bool_load_type = typename xexpression_type::bool_load_type;
  319. using reference = typename inner_types::reference;
  320. using const_reference = typename inner_types::const_reference;
  321. using pointer = std::
  322. conditional_t<is_const, typename xexpression_type::const_pointer, typename xexpression_type::pointer>;
  323. using const_pointer = typename xexpression_type::const_pointer;
  324. using size_type = typename inner_types::size_type;
  325. using difference_type = typename xexpression_type::difference_type;
  326. static constexpr layout_type static_layout = inner_types::layout;
  327. static constexpr bool contiguous_layout = static_layout != layout_type::dynamic;
  328. static constexpr bool is_strided_view = detail::is_strided_view<xexpression_type, S...>::value;
  329. static constexpr bool is_contiguous_view = contiguous_layout;
  330. using iterable_base = xiterable<self_type>;
  331. using inner_shape_type = typename iterable_base::inner_shape_type;
  332. using shape_type = typename xview_shape_type<typename xexpression_type::shape_type, S...>::type;
  333. using xexpression_inner_strides_type = xtl::mpl::eval_if_t<
  334. has_strides<xexpression_type>,
  335. detail::expr_inner_strides_type<xexpression_type>,
  336. get_strides_type<shape_type>>;
  337. using xexpression_inner_backstrides_type = xtl::mpl::eval_if_t<
  338. has_strides<xexpression_type>,
  339. detail::expr_inner_backstrides_type<xexpression_type>,
  340. get_strides_type<shape_type>>;
  341. using storage_type = typename inner_types::storage_type;
  342. static constexpr bool has_trivial_strides = is_contiguous_view
  343. && !xtl::disjunction<detail::is_xrange<S>...>::value;
  344. using inner_strides_type = std::conditional_t<
  345. has_trivial_strides,
  346. typename detail::unwrap_offset_container<
  347. xexpression_type::static_layout,
  348. xexpression_inner_strides_type,
  349. integral_count<S...>()>::type,
  350. get_strides_t<shape_type>>;
  351. using inner_backstrides_type = std::conditional_t<
  352. has_trivial_strides,
  353. typename detail::unwrap_offset_container<
  354. xexpression_type::static_layout,
  355. xexpression_inner_backstrides_type,
  356. integral_count<S...>()>::type,
  357. get_strides_t<shape_type>>;
  358. using strides_type = get_strides_t<shape_type>;
  359. using backstrides_type = strides_type;
  360. using slice_type = std::tuple<S...>;
  361. using stepper = typename iterable_base::stepper;
  362. using const_stepper = typename iterable_base::const_stepper;
  363. using linear_iterator = std::conditional_t<
  364. has_data_interface<xexpression_type>::value && is_strided_view,
  365. std::conditional_t<is_const, typename xexpression_type::const_linear_iterator, typename xexpression_type::linear_iterator>,
  366. typename iterable_base::linear_iterator>;
  367. using const_linear_iterator = std::conditional_t<
  368. has_data_interface<xexpression_type>::value && is_strided_view,
  369. typename xexpression_type::const_linear_iterator,
  370. typename iterable_base::const_linear_iterator>;
  371. using reverse_linear_iterator = std::reverse_iterator<linear_iterator>;
  372. using const_reverse_linear_iterator = std::reverse_iterator<const_linear_iterator>;
  373. using container_iterator = pointer;
  374. using const_container_iterator = const_pointer;
  375. static constexpr std::size_t rank = SIZE_MAX;
  376. // The FSL argument prevents the compiler from calling this constructor
  377. // instead of the copy constructor when sizeof...(SL) == 0.
  378. template <class CTA, class FSL, class... SL>
  379. explicit xview(CTA&& e, FSL&& first_slice, SL&&... slices) noexcept;
  380. xview(const xview&) = default;
  381. self_type& operator=(const xview& rhs);
  382. template <class E>
  383. self_type& operator=(const xexpression<E>& e);
  384. template <class E>
  385. disable_xexpression<E, self_type>& operator=(const E& e);
  386. const inner_shape_type& shape() const noexcept;
  387. const slice_type& slices() const noexcept;
  388. layout_type layout() const noexcept;
  389. bool is_contiguous() const noexcept;
  390. using accessible_base::shape;
  391. template <class T>
  392. void fill(const T& value);
  393. template <class... Args>
  394. reference operator()(Args... args);
  395. template <class... Args>
  396. reference unchecked(Args... args);
  397. template <class It>
  398. reference element(It first, It last);
  399. template <class... Args>
  400. const_reference operator()(Args... args) const;
  401. template <class... Args>
  402. const_reference unchecked(Args... args) const;
  403. template <class It>
  404. const_reference element(It first, It last) const;
  405. xexpression_type& expression() noexcept;
  406. const xexpression_type& expression() const noexcept;
  407. template <class ST>
  408. bool broadcast_shape(ST& shape, bool reuse_cache = false) const;
  409. template <class ST>
  410. bool has_linear_assign(const ST& strides) const;
  411. template <class ST, bool Enable = is_strided_view>
  412. std::enable_if_t<!Enable, stepper> stepper_begin(const ST& shape);
  413. template <class ST, bool Enable = is_strided_view>
  414. std::enable_if_t<!Enable, stepper> stepper_end(const ST& shape, layout_type l);
  415. template <class ST, bool Enable = is_strided_view>
  416. std::enable_if_t<!Enable, const_stepper> stepper_begin(const ST& shape) const;
  417. template <class ST, bool Enable = is_strided_view>
  418. std::enable_if_t<!Enable, const_stepper> stepper_end(const ST& shape, layout_type l) const;
  419. template <class ST, bool Enable = is_strided_view>
  420. std::enable_if_t<Enable, stepper> stepper_begin(const ST& shape);
  421. template <class ST, bool Enable = is_strided_view>
  422. std::enable_if_t<Enable, stepper> stepper_end(const ST& shape, layout_type l);
  423. template <class ST, bool Enable = is_strided_view>
  424. std::enable_if_t<Enable, const_stepper> stepper_begin(const ST& shape) const;
  425. template <class ST, bool Enable = is_strided_view>
  426. std::enable_if_t<Enable, const_stepper> stepper_end(const ST& shape, layout_type l) const;
  427. template <class T = xexpression_type>
  428. std::enable_if_t<has_data_interface<T>::value, storage_type&> storage();
  429. template <class T = xexpression_type>
  430. std::enable_if_t<has_data_interface<T>::value, const storage_type&> storage() const;
  431. template <class T = xexpression_type>
  432. std::enable_if_t<has_data_interface<T>::value && is_strided_view, linear_iterator> linear_begin();
  433. template <class T = xexpression_type>
  434. std::enable_if_t<has_data_interface<T>::value && is_strided_view, linear_iterator> linear_end();
  435. template <class T = xexpression_type>
  436. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
  437. linear_begin() const;
  438. template <class T = xexpression_type>
  439. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
  440. linear_end() const;
  441. template <class T = xexpression_type>
  442. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
  443. linear_cbegin() const;
  444. template <class T = xexpression_type>
  445. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
  446. linear_cend() const;
  447. template <class T = xexpression_type>
  448. std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_linear_iterator>
  449. linear_rbegin();
  450. template <class T = xexpression_type>
  451. std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_linear_iterator>
  452. linear_rend();
  453. template <class T = xexpression_type>
  454. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
  455. linear_rbegin() const;
  456. template <class T = xexpression_type>
  457. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
  458. linear_rend() const;
  459. template <class T = xexpression_type>
  460. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
  461. linear_crbegin() const;
  462. template <class T = xexpression_type>
  463. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
  464. linear_crend() const;
  465. template <class T = xexpression_type>
  466. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const inner_strides_type&>
  467. strides() const;
  468. template <class T = xexpression_type>
  469. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const inner_strides_type&>
  470. backstrides() const;
  471. template <class T = xexpression_type>
  472. std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_pointer> data() const;
  473. template <class T = xexpression_type>
  474. std::enable_if_t<has_data_interface<T>::value && is_strided_view, pointer> data();
  475. template <class T = xexpression_type>
  476. std::enable_if_t<has_data_interface<T>::value && is_strided_view, std::size_t>
  477. data_offset() const noexcept;
  478. template <class It>
  479. inline It data_xbegin_impl(It begin) const noexcept;
  480. template <class It>
  481. inline It data_xend_impl(It begin, layout_type l, size_type offset) const noexcept;
  482. inline container_iterator data_xbegin() noexcept;
  483. inline const_container_iterator data_xbegin() const noexcept;
  484. inline container_iterator data_xend(layout_type l, size_type offset) noexcept;
  485. inline const_container_iterator data_xend(layout_type l, size_type offset) const noexcept;
  486. // Conversion operator enabled for statically "scalar" views
  487. template <class ST = self_type, class = std::enable_if_t<is_xscalar<std::decay_t<ST>>::value, int>>
  488. operator reference()
  489. {
  490. return (*this)();
  491. }
  492. template <class ST = self_type, class = std::enable_if_t<is_xscalar<std::decay_t<ST>>::value, int>>
  493. operator const_reference() const
  494. {
  495. return (*this)();
  496. }
  497. size_type underlying_size(size_type dim) const;
  498. xtl::xclosure_pointer<self_type&> operator&() &;
  499. xtl::xclosure_pointer<const self_type&> operator&() const&;
  500. xtl::xclosure_pointer<self_type> operator&() &&;
  501. template <
  502. class E,
  503. class T = xexpression_type,
  504. class = std::enable_if_t<has_data_interface<T>::value && is_contiguous_view, int>>
  505. void assign_to(xexpression<E>& e, bool force_resize) const;
  506. template <class E>
  507. using rebind_t = xview<E, S...>;
  508. template <class E>
  509. rebind_t<E> build_view(E&& e) const;
  510. //
  511. // SIMD interface
  512. //
  513. template <class requested_type>
  514. using simd_return_type = xt_simd::simd_return_type<value_type, requested_type>;
  515. template <class T, class R>
  516. using enable_simd_interface = std::enable_if_t<has_simd_interface<T>::value && is_strided_view, R>;
  517. template <class align, class simd, class T = xexpression_type>
  518. enable_simd_interface<T, void> store_simd(size_type i, const simd& e);
  519. template <
  520. class align,
  521. class requested_type = value_type,
  522. std::size_t N = xt_simd::simd_traits<requested_type>::size,
  523. class T = xexpression_type>
  524. enable_simd_interface<T, simd_return_type<requested_type>> load_simd(size_type i) const;
  525. template <class T = xexpression_type>
  526. enable_simd_interface<T, reference> data_element(size_type i);
  527. template <class T = xexpression_type>
  528. enable_simd_interface<T, const_reference> data_element(size_type i) const;
  529. template <class T = xexpression_type>
  530. enable_simd_interface<T, reference> flat(size_type i);
  531. template <class T = xexpression_type>
  532. enable_simd_interface<T, const_reference> flat(size_type i) const;
  533. private:
  534. // VS 2015 workaround (yes, really)
  535. template <std::size_t I>
  536. struct lesser_condition
  537. {
  538. static constexpr bool value = (I + newaxis_count_before<S...>(I + 1) < sizeof...(S));
  539. };
  540. CT m_e;
  541. slice_type m_slices;
  542. inner_shape_type m_shape;
  543. mutable inner_strides_type m_strides;
  544. mutable inner_backstrides_type m_backstrides;
  545. mutable std::size_t m_data_offset;
  546. mutable bool m_strides_computed;
  547. template <class CTA, class FSL, class... SL>
  548. explicit xview(std::true_type, CTA&& e, FSL&& first_slice, SL&&... slices) noexcept;
  549. template <class CTA, class FSL, class... SL>
  550. explicit xview(std::false_type, CTA&& e, FSL&& first_slice, SL&&... slices) noexcept;
  551. template <class... Args>
  552. auto make_index_sequence(Args... args) const noexcept;
  553. void compute_strides(std::true_type) const;
  554. void compute_strides(std::false_type) const;
  555. reference access();
  556. template <class Arg, class... Args>
  557. reference access(Arg arg, Args... args);
  558. const_reference access() const;
  559. template <class Arg, class... Args>
  560. const_reference access(Arg arg, Args... args) const;
  561. template <typename std::decay_t<CT>::size_type... I, class... Args>
  562. reference unchecked_impl(std::index_sequence<I...>, Args... args);
  563. template <typename std::decay_t<CT>::size_type... I, class... Args>
  564. const_reference unchecked_impl(std::index_sequence<I...>, Args... args) const;
  565. template <typename std::decay_t<CT>::size_type... I, class... Args>
  566. reference access_impl(std::index_sequence<I...>, Args... args);
  567. template <typename std::decay_t<CT>::size_type... I, class... Args>
  568. const_reference access_impl(std::index_sequence<I...>, Args... args) const;
  569. template <typename std::decay_t<CT>::size_type I, class... Args>
  570. std::enable_if_t<lesser_condition<I>::value, size_type> index(Args... args) const;
  571. template <typename std::decay_t<CT>::size_type I, class... Args>
  572. std::enable_if_t<!lesser_condition<I>::value, size_type> index(Args... args) const;
  573. template <typename std::decay_t<CT>::size_type, class T>
  574. size_type sliced_access(const xslice<T>& slice) const;
  575. template <typename std::decay_t<CT>::size_type I, class T, class Arg, class... Args>
  576. size_type sliced_access(const xslice<T>& slice, Arg arg, Args... args) const;
  577. template <typename std::decay_t<CT>::size_type I, class T, class... Args>
  578. disable_xslice<T, size_type> sliced_access(const T& squeeze, Args...) const;
  579. using base_index_type = xindex_type_t<typename xexpression_type::shape_type>;
  580. template <class It>
  581. base_index_type make_index(It first, It last) const;
  582. void assign_temporary_impl(temporary_type&& tmp);
  583. template <std::size_t... I>
  584. std::size_t data_offset_impl(std::index_sequence<I...>) const noexcept;
  585. template <std::size_t... I>
  586. auto compute_strides_impl(std::index_sequence<I...>) const noexcept;
  587. inner_shape_type compute_shape(std::true_type) const;
  588. inner_shape_type compute_shape(std::false_type) const;
  589. template <class E, std::size_t... I>
  590. rebind_t<E> build_view_impl(E&& e, std::index_sequence<I...>) const;
  591. friend class xview_semantic<xview<CT, S...>>;
  592. };
  593. template <class E, class... S>
  594. auto view(E&& e, S&&... slices);
  595. template <class E>
  596. auto row(E&& e, std::ptrdiff_t index);
  597. template <class E>
  598. auto col(E&& e, std::ptrdiff_t index);
  599. /*****************************
  600. * xview_stepper declaration *
  601. *****************************/
  602. namespace detail
  603. {
  604. template <class V>
  605. struct get_stepper_impl
  606. {
  607. using xexpression_type = typename V::xexpression_type;
  608. using type = typename xexpression_type::stepper;
  609. };
  610. template <class V>
  611. struct get_stepper_impl<const V>
  612. {
  613. using xexpression_type = typename V::xexpression_type;
  614. using type = typename xexpression_type::const_stepper;
  615. };
  616. }
  617. template <class V>
  618. using get_stepper = typename detail::get_stepper_impl<V>::type;
  619. template <bool is_const, class CT, class... S>
  620. class xview_stepper
  621. {
  622. public:
  623. using view_type = std::conditional_t<is_const, const xview<CT, S...>, xview<CT, S...>>;
  624. using substepper_type = get_stepper<view_type>;
  625. using value_type = typename substepper_type::value_type;
  626. using reference = typename substepper_type::reference;
  627. using pointer = typename substepper_type::pointer;
  628. using difference_type = typename substepper_type::difference_type;
  629. using size_type = typename view_type::size_type;
  630. using shape_type = typename substepper_type::shape_type;
  631. xview_stepper() = default;
  632. xview_stepper(
  633. view_type* view,
  634. substepper_type it,
  635. size_type offset,
  636. bool end = false,
  637. layout_type l = XTENSOR_DEFAULT_TRAVERSAL
  638. );
  639. reference operator*() const;
  640. void step(size_type dim);
  641. void step_back(size_type dim);
  642. void step(size_type dim, size_type n);
  643. void step_back(size_type dim, size_type n);
  644. void reset(size_type dim);
  645. void reset_back(size_type dim);
  646. void to_begin();
  647. void to_end(layout_type l);
  648. private:
  649. bool is_newaxis_slice(size_type index) const noexcept;
  650. void to_end_impl(layout_type l);
  651. template <class F>
  652. void common_step_forward(size_type dim, F f);
  653. template <class F>
  654. void common_step_backward(size_type dim, F f);
  655. template <class F>
  656. void common_step_forward(size_type dim, size_type n, F f);
  657. template <class F>
  658. void common_step_backward(size_type dim, size_type n, F f);
  659. template <class F>
  660. void common_reset(size_type dim, F f, bool backwards);
  661. view_type* p_view;
  662. substepper_type m_it;
  663. size_type m_offset;
  664. std::array<std::size_t, sizeof...(S)> m_index_keeper;
  665. };
  666. // meta-function returning the shape type for an xview
  667. template <class ST, class... S>
  668. struct xview_shape_type
  669. {
  670. using type = ST;
  671. };
  672. template <class I, std::size_t L, class... S>
  673. struct xview_shape_type<std::array<I, L>, S...>
  674. {
  675. using type = std::array<I, L - integral_count<S...>() + newaxis_count<S...>()>;
  676. };
  677. template <std::size_t... I, class... S>
  678. struct xview_shape_type<fixed_shape<I...>, S...>
  679. {
  680. using type = typename xview_shape_type<std::array<std::size_t, sizeof...(I)>, S...>::type;
  681. };
  682. /************************
  683. * xview implementation *
  684. ************************/
  685. /**
  686. * @name Constructor
  687. */
  688. //@{
  689. /**
  690. * Constructs a view on the specified xexpression.
  691. * Users should not call directly this constructor but
  692. * use the view function instead.
  693. * @param e the xexpression to adapt
  694. * @param first_slice the first slice describing the view
  695. * @param slices the slices list describing the view
  696. * @sa view
  697. */
  698. template <class CT, class... S>
  699. template <class CTA, class FSL, class... SL>
  700. xview<CT, S...>::xview(CTA&& e, FSL&& first_slice, SL&&... slices) noexcept
  701. : xview(
  702. std::integral_constant<bool, has_trivial_strides>{},
  703. std::forward<CTA>(e),
  704. std::forward<FSL>(first_slice),
  705. std::forward<SL>(slices)...
  706. )
  707. {
  708. }
  709. // trivial strides initializer
  710. template <class CT, class... S>
  711. template <class CTA, class FSL, class... SL>
  712. xview<CT, S...>::xview(std::true_type, CTA&& e, FSL&& first_slice, SL&&... slices) noexcept
  713. : m_e(std::forward<CTA>(e))
  714. , m_slices(std::forward<FSL>(first_slice), std::forward<SL>(slices)...)
  715. , m_shape(compute_shape(detail::is_sequence_view<inner_shape_type>{}))
  716. , m_strides(m_e.strides())
  717. , m_backstrides(m_e.backstrides())
  718. , m_data_offset(data_offset_impl(std::make_index_sequence<sizeof...(S)>()))
  719. , m_strides_computed(true)
  720. {
  721. }
  722. template <class CT, class... S>
  723. template <class CTA, class FSL, class... SL>
  724. xview<CT, S...>::xview(std::false_type, CTA&& e, FSL&& first_slice, SL&&... slices) noexcept
  725. : m_e(std::forward<CTA>(e))
  726. , m_slices(std::forward<FSL>(first_slice), std::forward<SL>(slices)...)
  727. , m_shape(compute_shape(std::false_type{}))
  728. , m_strides_computed(false)
  729. {
  730. }
  731. //@}
  732. template <class CT, class... S>
  733. inline auto xview<CT, S...>::operator=(const xview& rhs) -> self_type&
  734. {
  735. temporary_type tmp(rhs);
  736. return this->assign_temporary(std::move(tmp));
  737. }
  738. /**
  739. * @name Extended copy semantic
  740. */
  741. //@{
  742. /**
  743. * The extended assignment operator.
  744. */
  745. template <class CT, class... S>
  746. template <class E>
  747. inline auto xview<CT, S...>::operator=(const xexpression<E>& e) -> self_type&
  748. {
  749. return semantic_base::operator=(e);
  750. }
  751. //@}
  752. template <class CT, class... S>
  753. template <class E>
  754. inline auto xview<CT, S...>::operator=(const E& e) -> disable_xexpression<E, self_type>&
  755. {
  756. this->fill(e);
  757. return *this;
  758. }
  759. /**
  760. * @name Size and shape
  761. */
  762. //@{
  763. /**
  764. * Returns the shape of the view.
  765. */
  766. template <class CT, class... S>
  767. inline auto xview<CT, S...>::shape() const noexcept -> const inner_shape_type&
  768. {
  769. return m_shape;
  770. }
  771. /**
  772. * Returns the slices of the view.
  773. */
  774. template <class CT, class... S>
  775. inline auto xview<CT, S...>::slices() const noexcept -> const slice_type&
  776. {
  777. return m_slices;
  778. }
  779. /**
  780. * Returns the slices of the view.
  781. */
  782. template <class CT, class... S>
  783. inline layout_type xview<CT, S...>::layout() const noexcept
  784. {
  785. return xtl::mpl::static_if<is_strided_view>(
  786. [&](auto self)
  787. {
  788. if (static_layout != layout_type::dynamic)
  789. {
  790. return static_layout;
  791. }
  792. else
  793. {
  794. bool strides_match = do_strides_match(
  795. self(this)->shape(),
  796. self(this)->strides(),
  797. self(this)->m_e.layout(),
  798. true
  799. );
  800. return strides_match ? self(this)->m_e.layout() : layout_type::dynamic;
  801. }
  802. },
  803. /* else */
  804. [&](auto /*self*/)
  805. {
  806. return layout_type::dynamic;
  807. }
  808. );
  809. }
  810. template <class CT, class... S>
  811. inline bool xview<CT, S...>::is_contiguous() const noexcept
  812. {
  813. return layout() != layout_type::dynamic;
  814. }
  815. //@}
  816. /**
  817. * @name Data
  818. */
  819. //@{
  820. /**
  821. * Fills the view with the given value.
  822. * @param value the value to fill the view with.
  823. */
  824. template <class CT, class... S>
  825. template <class T>
  826. inline void xview<CT, S...>::fill(const T& value)
  827. {
  828. xtl::mpl::static_if<static_layout != layout_type::dynamic>(
  829. [&](auto self)
  830. {
  831. std::fill(self(this)->linear_begin(), self(this)->linear_end(), value);
  832. },
  833. /*else*/
  834. [&](auto self)
  835. {
  836. std::fill(self(this)->begin(), self(this)->end(), value);
  837. }
  838. );
  839. }
  840. /**
  841. * Returns a reference to the element at the specified position in the view.
  842. * @param args a list of indices specifying the position in the view. Indices
  843. * must be unsigned integers, the number of indices should be equal or greater
  844. * than the number of dimensions of the view.
  845. */
  846. template <class CT, class... S>
  847. template <class... Args>
  848. inline auto xview<CT, S...>::operator()(Args... args) -> reference
  849. {
  850. XTENSOR_TRY(check_index(shape(), args...));
  851. XTENSOR_CHECK_DIMENSION(shape(), args...);
  852. // The static cast prevents the compiler from instantiating the template methods with signed integers,
  853. // leading to warning about signed/unsigned conversions in the deeper layers of the access methods
  854. return access(static_cast<size_type>(args)...);
  855. }
  856. /**
  857. * Returns a reference to the element at the specified position in the view.
  858. * @param args a list of indices specifying the position in the view. Indices
  859. * must be unsigned integers, the number of indices must be equal to the number of
  860. * dimensions of the view, else the behavior is undefined.
  861. *
  862. * @warning This method is meant for performance, for expressions with a dynamic
  863. * number of dimensions (i.e. not known at compile time). Since it may have
  864. * undefined behavior (see parameters), operator() should be preferred whenever
  865. * it is possible.
  866. * @warning This method is NOT compatible with broadcasting, meaning the following
  867. * code has undefined behavior:
  868. * @code{.cpp}
  869. * xt::xarray<double> a = {{0, 1}, {2, 3}};
  870. * xt::xarray<double> b = {0, 1};
  871. * auto fd = a + b;
  872. * double res = fd.unchecked(0, 1);
  873. * @endcode
  874. */
  875. template <class CT, class... S>
  876. template <class... Args>
  877. inline auto xview<CT, S...>::unchecked(Args... args) -> reference
  878. {
  879. return unchecked_impl(make_index_sequence(args...), static_cast<size_type>(args)...);
  880. }
  881. template <class CT, class... S>
  882. template <class It>
  883. inline auto xview<CT, S...>::element(It first, It last) -> reference
  884. {
  885. XTENSOR_TRY(check_element_index(shape(), first, last));
  886. // TODO: avoid memory allocation
  887. auto index = make_index(first, last);
  888. return m_e.element(index.cbegin(), index.cend());
  889. }
  890. /**
  891. * Returns a constant reference to the element at the specified position in the view.
  892. * @param args a list of indices specifying the position in the view. Indices must be
  893. * unsigned integers, the number of indices should be equal or greater than the number
  894. * of dimensions of the view.
  895. */
  896. template <class CT, class... S>
  897. template <class... Args>
  898. inline auto xview<CT, S...>::operator()(Args... args) const -> const_reference
  899. {
  900. XTENSOR_TRY(check_index(shape(), args...));
  901. XTENSOR_CHECK_DIMENSION(shape(), args...);
  902. // The static cast prevents the compiler from instantiating the template methods with signed integers,
  903. // leading to warning about signed/unsigned conversions in the deeper layers of the access methods
  904. return access(static_cast<size_type>(args)...);
  905. }
  906. /**
  907. * Returns a constant reference to the element at the specified position in the view.
  908. * @param args a list of indices specifying the position in the view. Indices
  909. * must be unsigned integers, the number of indices must be equal to the number of
  910. * dimensions of the view, else the behavior is undefined.
  911. *
  912. * @warning This method is meant for performance, for expressions with a dynamic
  913. * number of dimensions (i.e. not known at compile time). Since it may have
  914. * undefined behavior (see parameters), operator() should be preferred whenever
  915. * it is possible.
  916. * @warning This method is NOT compatible with broadcasting, meaning the following
  917. * code has undefined behavior:
  918. * @code{.cpp}
  919. * xt::xarray<double> a = {{0, 1}, {2, 3}};
  920. * xt::xarray<double> b = {0, 1};
  921. * auto fd = a + b;
  922. * double res = fd.unchecked(0, 1);
  923. * @endcode
  924. */
  925. template <class CT, class... S>
  926. template <class... Args>
  927. inline auto xview<CT, S...>::unchecked(Args... args) const -> const_reference
  928. {
  929. return unchecked_impl(make_index_sequence(args...), static_cast<size_type>(args)...);
  930. }
  931. template <class CT, class... S>
  932. template <class It>
  933. inline auto xview<CT, S...>::element(It first, It last) const -> const_reference
  934. {
  935. // TODO: avoid memory allocation
  936. auto index = make_index(first, last);
  937. return m_e.element(index.cbegin(), index.cend());
  938. }
  939. /**
  940. * Returns a reference to the underlying expression of the view.
  941. */
  942. template <class CT, class... S>
  943. inline auto xview<CT, S...>::expression() noexcept -> xexpression_type&
  944. {
  945. return m_e;
  946. }
  947. /**
  948. * Returns a const reference to the underlying expression of the view.
  949. */
  950. template <class CT, class... S>
  951. inline auto xview<CT, S...>::expression() const noexcept -> const xexpression_type&
  952. {
  953. return m_e;
  954. }
  955. /**
  956. * Returns the data holder of the underlying container (only if the view is on a realized
  957. * container). ``xt::eval`` will make sure that the underlying xexpression is
  958. * on a realized container.
  959. */
  960. template <class CT, class... S>
  961. template <class T>
  962. inline auto xview<CT, S...>::storage() -> std::enable_if_t<has_data_interface<T>::value, storage_type&>
  963. {
  964. return m_e.storage();
  965. }
  966. template <class CT, class... S>
  967. template <class T>
  968. inline auto xview<CT, S...>::storage() const
  969. -> std::enable_if_t<has_data_interface<T>::value, const storage_type&>
  970. {
  971. return m_e.storage();
  972. }
  973. template <class CT, class... S>
  974. template <class T>
  975. auto xview<CT, S...>::linear_begin()
  976. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, linear_iterator>
  977. {
  978. return m_e.storage().begin() + data_offset();
  979. }
  980. template <class CT, class... S>
  981. template <class T>
  982. auto xview<CT, S...>::linear_end()
  983. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, linear_iterator>
  984. {
  985. return m_e.storage().begin() + data_offset() + this->size();
  986. }
  987. template <class CT, class... S>
  988. template <class T>
  989. auto xview<CT, S...>::linear_begin() const
  990. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
  991. {
  992. return linear_cbegin();
  993. }
  994. template <class CT, class... S>
  995. template <class T>
  996. auto xview<CT, S...>::linear_end() const
  997. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
  998. {
  999. return linear_cend();
  1000. }
  1001. template <class CT, class... S>
  1002. template <class T>
  1003. auto xview<CT, S...>::linear_cbegin() const
  1004. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
  1005. {
  1006. return m_e.storage().cbegin() + data_offset();
  1007. }
  1008. template <class CT, class... S>
  1009. template <class T>
  1010. auto xview<CT, S...>::linear_cend() const
  1011. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
  1012. {
  1013. return m_e.storage().cbegin() + data_offset() + this->size();
  1014. }
  1015. template <class CT, class... S>
  1016. template <class T>
  1017. auto xview<CT, S...>::linear_rbegin()
  1018. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_linear_iterator>
  1019. {
  1020. return reverse_linear_iterator(linear_end());
  1021. }
  1022. template <class CT, class... S>
  1023. template <class T>
  1024. auto xview<CT, S...>::linear_rend()
  1025. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_linear_iterator>
  1026. {
  1027. return reverse_linear_iterator(linear_begin());
  1028. }
  1029. template <class CT, class... S>
  1030. template <class T>
  1031. auto xview<CT, S...>::linear_rbegin() const
  1032. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
  1033. {
  1034. return linear_crbegin();
  1035. }
  1036. template <class CT, class... S>
  1037. template <class T>
  1038. auto xview<CT, S...>::linear_rend() const
  1039. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
  1040. {
  1041. return linear_crend();
  1042. }
  1043. template <class CT, class... S>
  1044. template <class T>
  1045. auto xview<CT, S...>::linear_crbegin() const
  1046. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
  1047. {
  1048. return const_reverse_linear_iterator(linear_end());
  1049. }
  1050. template <class CT, class... S>
  1051. template <class T>
  1052. auto xview<CT, S...>::linear_crend() const
  1053. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
  1054. {
  1055. return const_reverse_linear_iterator(linear_begin());
  1056. }
  1057. /**
  1058. * Return the strides for the underlying container of the view.
  1059. */
  1060. template <class CT, class... S>
  1061. template <class T>
  1062. inline auto xview<CT, S...>::strides() const
  1063. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const inner_strides_type&>
  1064. {
  1065. if (!m_strides_computed)
  1066. {
  1067. compute_strides(std::integral_constant<bool, has_trivial_strides>{});
  1068. m_strides_computed = true;
  1069. }
  1070. return m_strides;
  1071. }
  1072. template <class CT, class... S>
  1073. template <class T>
  1074. inline auto xview<CT, S...>::backstrides() const
  1075. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const inner_strides_type&>
  1076. {
  1077. if (!m_strides_computed)
  1078. {
  1079. compute_strides(std::integral_constant<bool, has_trivial_strides>{});
  1080. m_strides_computed = true;
  1081. }
  1082. return m_backstrides;
  1083. }
  1084. /**
  1085. * Return the pointer to the underlying buffer.
  1086. */
  1087. template <class CT, class... S>
  1088. template <class T>
  1089. inline auto xview<CT, S...>::data() const
  1090. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_pointer>
  1091. {
  1092. return m_e.data();
  1093. }
  1094. template <class CT, class... S>
  1095. template <class T>
  1096. inline auto xview<CT, S...>::data()
  1097. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, pointer>
  1098. {
  1099. return m_e.data();
  1100. }
  1101. template <class CT, class... S>
  1102. template <std::size_t... I>
  1103. inline std::size_t xview<CT, S...>::data_offset_impl(std::index_sequence<I...>) const noexcept
  1104. {
  1105. auto temp = std::array<std::ptrdiff_t, sizeof...(S)>(
  1106. {(static_cast<ptrdiff_t>(xt::value(std::get<I>(m_slices), 0)))...}
  1107. );
  1108. std::ptrdiff_t result = 0;
  1109. std::size_t i = 0;
  1110. for (; i < std::min(sizeof...(S), m_e.strides().size()); ++i)
  1111. {
  1112. result += temp[i] * m_e.strides()[i - newaxis_count_before<S...>(i)];
  1113. }
  1114. for (; i < sizeof...(S); ++i)
  1115. {
  1116. result += temp[i];
  1117. }
  1118. return static_cast<std::size_t>(result) + m_e.data_offset();
  1119. }
  1120. /**
  1121. * Return the offset to the first element of the view in the underlying container.
  1122. */
  1123. template <class CT, class... S>
  1124. template <class T>
  1125. inline auto xview<CT, S...>::data_offset() const noexcept
  1126. -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, std::size_t>
  1127. {
  1128. if (!m_strides_computed)
  1129. {
  1130. compute_strides(std::integral_constant<bool, has_trivial_strides>{});
  1131. m_strides_computed = true;
  1132. }
  1133. return m_data_offset;
  1134. }
  1135. //@}
  1136. template <class CT, class... S>
  1137. inline auto xview<CT, S...>::underlying_size(size_type dim) const -> size_type
  1138. {
  1139. return m_e.shape()[dim];
  1140. }
  1141. template <class CT, class... S>
  1142. inline auto xview<CT, S...>::operator&() & -> xtl::xclosure_pointer<self_type&>
  1143. {
  1144. return xtl::closure_pointer(*this);
  1145. }
  1146. template <class CT, class... S>
  1147. inline auto xview<CT, S...>::operator&() const& -> xtl::xclosure_pointer<const self_type&>
  1148. {
  1149. return xtl::closure_pointer(*this);
  1150. }
  1151. template <class CT, class... S>
  1152. inline auto xview<CT, S...>::operator&() && -> xtl::xclosure_pointer<self_type>
  1153. {
  1154. return xtl::closure_pointer(std::move(*this));
  1155. }
  1156. /**
  1157. * @name Broadcasting
  1158. */
  1159. //@{
  1160. /**
  1161. * Broadcast the shape of the view to the specified parameter.
  1162. * @param shape the result shape
  1163. * @param reuse_cache parameter for internal optimization
  1164. * @return a boolean indicating whether the broadcasting is trivial
  1165. */
  1166. template <class CT, class... S>
  1167. template <class ST>
  1168. inline bool xview<CT, S...>::broadcast_shape(ST& shape, bool) const
  1169. {
  1170. return xt::broadcast_shape(m_shape, shape);
  1171. }
  1172. /**
  1173. * Checks whether the xview can be linearly assigned to an expression
  1174. * with the specified strides.
  1175. * @return a boolean indicating whether a linear assign is possible
  1176. */
  1177. template <class CT, class... S>
  1178. template <class ST>
  1179. inline bool xview<CT, S...>::has_linear_assign(const ST& str) const
  1180. {
  1181. return xtl::mpl::static_if<is_strided_view>(
  1182. [&](auto self)
  1183. {
  1184. return str.size() == self(this)->strides().size()
  1185. && std::equal(str.cbegin(), str.cend(), self(this)->strides().begin());
  1186. },
  1187. /*else*/
  1188. [](auto /*self*/)
  1189. {
  1190. return false;
  1191. }
  1192. );
  1193. }
  1194. //@}
  1195. template <class CT, class... S>
  1196. template <class It>
  1197. inline It xview<CT, S...>::data_xbegin_impl(It begin) const noexcept
  1198. {
  1199. return begin + data_offset();
  1200. }
  1201. template <class CT, class... S>
  1202. template <class It>
  1203. inline It xview<CT, S...>::data_xend_impl(It begin, layout_type l, size_type offset) const noexcept
  1204. {
  1205. return strided_data_end(*this, begin, l, offset);
  1206. }
  1207. template <class CT, class... S>
  1208. inline auto xview<CT, S...>::data_xbegin() noexcept -> container_iterator
  1209. {
  1210. return data_xbegin_impl(data());
  1211. }
  1212. template <class CT, class... S>
  1213. inline auto xview<CT, S...>::data_xbegin() const noexcept -> const_container_iterator
  1214. {
  1215. return data_xbegin_impl(data());
  1216. }
  1217. template <class CT, class... S>
  1218. inline auto xview<CT, S...>::data_xend(layout_type l, size_type offset) noexcept -> container_iterator
  1219. {
  1220. return data_xend_impl(data() + data_offset(), l, offset);
  1221. }
  1222. template <class CT, class... S>
  1223. inline auto xview<CT, S...>::data_xend(layout_type l, size_type offset) const noexcept
  1224. -> const_container_iterator
  1225. {
  1226. return data_xend_impl(data() + data_offset(), l, offset);
  1227. }
  1228. // Assign to operator enabled for contigous views
  1229. template <class CT, class... S>
  1230. template <class E, class T, class>
  1231. void xview<CT, S...>::assign_to(xexpression<E>& e, bool force_resize) const
  1232. {
  1233. auto& de = e.derived_cast();
  1234. de.resize(shape(), force_resize);
  1235. std::copy(data() + data_offset(), data() + data_offset() + de.size(), de.template begin<static_layout>());
  1236. }
  1237. template <class CT, class... S>
  1238. template <class E, std::size_t... I>
  1239. inline auto xview<CT, S...>::build_view_impl(E&& e, std::index_sequence<I...>) const -> rebind_t<E>
  1240. {
  1241. return rebind_t<E>(std::forward<E>(e), std::get<I>(m_slices)...);
  1242. }
  1243. template <class CT, class... S>
  1244. template <class E>
  1245. inline auto xview<CT, S...>::build_view(E&& e) const -> rebind_t<E>
  1246. {
  1247. return build_view_impl(std::forward<E>(e), std::make_index_sequence<sizeof...(S)>());
  1248. }
  1249. template <class CT, class... S>
  1250. template <class align, class simd, class T>
  1251. inline auto xview<CT, S...>::store_simd(size_type i, const simd& e) -> enable_simd_interface<T, void>
  1252. {
  1253. return m_e.template store_simd<xt_simd::unaligned_mode>(data_offset() + i, e);
  1254. }
  1255. template <class CT, class... S>
  1256. template <class align, class requested_type, std::size_t N, class T>
  1257. inline auto xview<CT, S...>::load_simd(size_type i) const
  1258. -> enable_simd_interface<T, simd_return_type<requested_type>>
  1259. {
  1260. return m_e.template load_simd<xt_simd::unaligned_mode, requested_type>(data_offset() + i);
  1261. }
  1262. template <class CT, class... S>
  1263. template <class T>
  1264. inline auto xview<CT, S...>::data_element(size_type i) -> enable_simd_interface<T, reference>
  1265. {
  1266. return m_e.data_element(data_offset() + i);
  1267. }
  1268. template <class CT, class... S>
  1269. template <class T>
  1270. inline auto xview<CT, S...>::data_element(size_type i) const -> enable_simd_interface<T, const_reference>
  1271. {
  1272. return m_e.data_element(data_offset() + i);
  1273. }
  1274. template <class CT, class... S>
  1275. template <class T>
  1276. inline auto xview<CT, S...>::flat(size_type i) -> enable_simd_interface<T, reference>
  1277. {
  1278. XTENSOR_ASSERT(is_contiguous());
  1279. return m_e.flat(data_offset() + i);
  1280. }
  1281. template <class CT, class... S>
  1282. template <class T>
  1283. inline auto xview<CT, S...>::flat(size_type i) const -> enable_simd_interface<T, const_reference>
  1284. {
  1285. XTENSOR_ASSERT(is_contiguous());
  1286. return m_e.flat(data_offset() + i);
  1287. }
  1288. template <class CT, class... S>
  1289. template <class... Args>
  1290. inline auto xview<CT, S...>::make_index_sequence(Args...) const noexcept
  1291. {
  1292. return std::make_index_sequence<
  1293. (sizeof...(Args) + integral_count<S...>() > newaxis_count<S...>()
  1294. ? sizeof...(Args) + integral_count<S...>() - newaxis_count<S...>()
  1295. : 0)>();
  1296. }
  1297. template <class CT, class... S>
  1298. template <std::size_t... I>
  1299. inline auto xview<CT, S...>::compute_strides_impl(std::index_sequence<I...>) const noexcept
  1300. {
  1301. std::size_t original_dim = m_e.dimension();
  1302. return std::array<std::ptrdiff_t, sizeof...(I)>(
  1303. {(static_cast<std::ptrdiff_t>(xt::step_size(std::get<integral_skip<S...>(I)>(m_slices), 1))
  1304. * ((integral_skip<S...>(I) - newaxis_count_before<S...>(integral_skip<S...>(I))) < original_dim
  1305. ? m_e.strides()[integral_skip<S...>(I) - newaxis_count_before<S...>(integral_skip<S...>(I))]
  1306. : 1))...}
  1307. );
  1308. }
  1309. template <class CT, class... S>
  1310. inline void xview<CT, S...>::compute_strides(std::false_type) const
  1311. {
  1312. m_strides = xtl::make_sequence<inner_strides_type>(this->dimension(), 0);
  1313. m_backstrides = xtl::make_sequence<inner_strides_type>(this->dimension(), 0);
  1314. constexpr std::size_t n_strides = sizeof...(S) - integral_count<S...>();
  1315. auto slice_strides = compute_strides_impl(std::make_index_sequence<n_strides>());
  1316. for (std::size_t i = 0; i < n_strides; ++i)
  1317. {
  1318. m_strides[i] = slice_strides[i];
  1319. // adapt strides for shape[i] == 1 to make consistent with rest of xtensor
  1320. detail::adapt_strides(shape(), m_strides, &m_backstrides, i);
  1321. }
  1322. for (std::size_t i = n_strides; i < this->dimension(); ++i)
  1323. {
  1324. m_strides[i] = m_e.strides()[i + integral_count<S...>() - newaxis_count<S...>()];
  1325. detail::adapt_strides(shape(), m_strides, &m_backstrides, i);
  1326. }
  1327. m_data_offset = data_offset_impl(std::make_index_sequence<sizeof...(S)>());
  1328. }
  1329. template <class CT, class... S>
  1330. inline void xview<CT, S...>::compute_strides(std::true_type) const
  1331. {
  1332. }
  1333. template <class CT, class... S>
  1334. inline auto xview<CT, S...>::access() -> reference
  1335. {
  1336. return access_impl(make_index_sequence());
  1337. }
  1338. template <class CT, class... S>
  1339. template <class Arg, class... Args>
  1340. inline auto xview<CT, S...>::access(Arg arg, Args... args) -> reference
  1341. {
  1342. if (sizeof...(Args) >= this->dimension())
  1343. {
  1344. return access(args...);
  1345. }
  1346. return access_impl(make_index_sequence(arg, args...), arg, args...);
  1347. }
  1348. template <class CT, class... S>
  1349. inline auto xview<CT, S...>::access() const -> const_reference
  1350. {
  1351. return access_impl(make_index_sequence());
  1352. }
  1353. template <class CT, class... S>
  1354. template <class Arg, class... Args>
  1355. inline auto xview<CT, S...>::access(Arg arg, Args... args) const -> const_reference
  1356. {
  1357. if (sizeof...(Args) >= this->dimension())
  1358. {
  1359. return access(args...);
  1360. }
  1361. return access_impl(make_index_sequence(arg, args...), arg, args...);
  1362. }
  1363. template <class CT, class... S>
  1364. template <typename std::decay_t<CT>::size_type... I, class... Args>
  1365. inline auto xview<CT, S...>::unchecked_impl(std::index_sequence<I...>, Args... args) -> reference
  1366. {
  1367. return m_e.unchecked(index<I>(args...)...);
  1368. }
  1369. template <class CT, class... S>
  1370. template <typename std::decay_t<CT>::size_type... I, class... Args>
  1371. inline auto xview<CT, S...>::unchecked_impl(std::index_sequence<I...>, Args... args) const
  1372. -> const_reference
  1373. {
  1374. return m_e.unchecked(index<I>(args...)...);
  1375. }
  1376. template <class CT, class... S>
  1377. template <typename std::decay_t<CT>::size_type... I, class... Args>
  1378. inline auto xview<CT, S...>::access_impl(std::index_sequence<I...>, Args... args) -> reference
  1379. {
  1380. return m_e(index<I>(args...)...);
  1381. }
  1382. template <class CT, class... S>
  1383. template <typename std::decay_t<CT>::size_type... I, class... Args>
  1384. inline auto xview<CT, S...>::access_impl(std::index_sequence<I...>, Args... args) const -> const_reference
  1385. {
  1386. return m_e(index<I>(args...)...);
  1387. }
  1388. template <class CT, class... S>
  1389. template <typename std::decay_t<CT>::size_type I, class... Args>
  1390. inline auto xview<CT, S...>::index(Args... args) const
  1391. -> std::enable_if_t<lesser_condition<I>::value, size_type>
  1392. {
  1393. return sliced_access<I - integral_count_before<S...>(I) + newaxis_count_before<S...>(I + 1)>(
  1394. std::get<I + newaxis_count_before<S...>(I + 1)>(m_slices),
  1395. args...
  1396. );
  1397. }
  1398. template <class CT, class... S>
  1399. template <typename std::decay_t<CT>::size_type I, class... Args>
  1400. inline auto xview<CT, S...>::index(Args... args) const
  1401. -> std::enable_if_t<!lesser_condition<I>::value, size_type>
  1402. {
  1403. return argument<I - integral_count<S...>() + newaxis_count<S...>()>(args...);
  1404. }
  1405. template <class CT, class... S>
  1406. template <typename std::decay_t<CT>::size_type I, class T>
  1407. inline auto xview<CT, S...>::sliced_access(const xslice<T>& slice) const -> size_type
  1408. {
  1409. return static_cast<size_type>(slice.derived_cast()(0));
  1410. }
  1411. template <class CT, class... S>
  1412. template <typename std::decay_t<CT>::size_type I, class T, class Arg, class... Args>
  1413. inline auto xview<CT, S...>::sliced_access(const xslice<T>& slice, Arg arg, Args... args) const -> size_type
  1414. {
  1415. using ST = typename T::size_type;
  1416. return static_cast<size_type>(
  1417. slice.derived_cast()(argument<I>(static_cast<ST>(arg), static_cast<ST>(args)...))
  1418. );
  1419. }
  1420. template <class CT, class... S>
  1421. template <typename std::decay_t<CT>::size_type I, class T, class... Args>
  1422. inline auto xview<CT, S...>::sliced_access(const T& squeeze, Args...) const -> disable_xslice<T, size_type>
  1423. {
  1424. return static_cast<size_type>(squeeze);
  1425. }
  1426. template <class CT, class... S>
  1427. template <class It>
  1428. inline auto xview<CT, S...>::make_index(It first, It last) const -> base_index_type
  1429. {
  1430. auto index = xtl::make_sequence<base_index_type>(m_e.dimension(), 0);
  1431. using diff_type = typename std::iterator_traits<It>::difference_type;
  1432. using ivalue_type = typename base_index_type::value_type;
  1433. auto func1 = [&first](const auto& s) noexcept
  1434. {
  1435. return get_slice_value(s, first);
  1436. };
  1437. auto func2 = [](const auto& s) noexcept
  1438. {
  1439. return xt::value(s, 0);
  1440. };
  1441. auto s = static_cast<diff_type>(
  1442. (std::min)(static_cast<size_type>(std::distance(first, last)), this->dimension())
  1443. );
  1444. auto first_copy = last - s;
  1445. for (size_type i = 0; i != m_e.dimension(); ++i)
  1446. {
  1447. size_type k = newaxis_skip<S...>(i);
  1448. // need to advance captured `first`
  1449. first = first_copy;
  1450. std::advance(first, static_cast<diff_type>(k - xt::integral_count_before<S...>(i)));
  1451. if (first < last)
  1452. {
  1453. index[i] = k < sizeof...(S) ? apply<size_type>(k, func1, m_slices)
  1454. : static_cast<ivalue_type>(*first);
  1455. }
  1456. else
  1457. {
  1458. index[i] = k < sizeof...(S) ? apply<size_type>(k, func2, m_slices) : ivalue_type(0);
  1459. }
  1460. }
  1461. return index;
  1462. }
  1463. template <class CT, class... S>
  1464. inline auto xview<CT, S...>::compute_shape(std::true_type) const -> inner_shape_type
  1465. {
  1466. return inner_shape_type(m_e.shape());
  1467. }
  1468. template <class CT, class... S>
  1469. inline auto xview<CT, S...>::compute_shape(std::false_type) const -> inner_shape_type
  1470. {
  1471. std::size_t dim = m_e.dimension() - integral_count<S...>() + newaxis_count<S...>();
  1472. auto shape = xtl::make_sequence<inner_shape_type>(dim, 0);
  1473. auto func = [](const auto& s) noexcept
  1474. {
  1475. return get_size(s);
  1476. };
  1477. for (size_type i = 0; i != dim; ++i)
  1478. {
  1479. size_type index = integral_skip<S...>(i);
  1480. shape[i] = index < sizeof...(S) ? apply<size_type>(index, func, m_slices)
  1481. : m_e.shape()[index - newaxis_count_before<S...>(index)];
  1482. }
  1483. return shape;
  1484. }
  1485. namespace xview_detail
  1486. {
  1487. template <class V, class T>
  1488. inline void run_assign_temporary_impl(V& v, const T& t, std::true_type /* enable strided assign */)
  1489. {
  1490. strided_loop_assigner<true>::run(v, t);
  1491. }
  1492. template <class V, class T>
  1493. inline void
  1494. run_assign_temporary_impl(V& v, const T& t, std::false_type /* fallback to iterator assign */)
  1495. {
  1496. std::copy(t.cbegin(), t.cend(), v.begin());
  1497. }
  1498. }
  1499. template <class CT, class... S>
  1500. inline void xview<CT, S...>::assign_temporary_impl(temporary_type&& tmp)
  1501. {
  1502. constexpr bool fast_assign = detail::is_strided_view<xexpression_type, S...>::value
  1503. && xassign_traits<xview<CT, S...>, temporary_type>::simd_strided_assign();
  1504. xview_detail::run_assign_temporary_impl(*this, tmp, std::integral_constant<bool, fast_assign>{});
  1505. }
  1506. namespace detail
  1507. {
  1508. template <class E, class... S>
  1509. inline std::size_t get_underlying_shape_index(std::size_t I)
  1510. {
  1511. return I - newaxis_count_before<get_slice_type<E, S>...>(I);
  1512. }
  1513. template <class... S>
  1514. struct check_slice;
  1515. template <>
  1516. struct check_slice<>
  1517. {
  1518. using type = void_t<>;
  1519. };
  1520. template <class S, class... SL>
  1521. struct check_slice<S, SL...>
  1522. {
  1523. static_assert(!std::is_same<S, xellipsis_tag>::value, "ellipsis not supported vith xview");
  1524. using type = typename check_slice<SL...>::type;
  1525. };
  1526. template <class E, std::size_t... I, class... S>
  1527. inline auto make_view_impl(E&& e, std::index_sequence<I...>, S&&... slices)
  1528. {
  1529. // Checks that no ellipsis slice is used
  1530. using view_type = xview<xtl::closure_type_t<E>, get_slice_type<std::decay_t<E>, S>...>;
  1531. return view_type(
  1532. std::forward<E>(e),
  1533. get_slice_implementation(
  1534. e,
  1535. std::forward<S>(slices),
  1536. get_underlying_shape_index<std::decay_t<E>, S...>(I)
  1537. )...
  1538. );
  1539. }
  1540. }
  1541. /**
  1542. * Constructs and returns a view on the specified xexpression. Users
  1543. * should not directly construct the slices but call helper functions
  1544. * instead.
  1545. * @param e the xexpression to adapt
  1546. * @param slices the slices list describing the view. \c view accepts negative
  1547. * indices, in that case indexing is done in reverse order.
  1548. * @sa range, all, newaxis
  1549. */
  1550. template <class E, class... S>
  1551. inline auto view(E&& e, S&&... slices)
  1552. {
  1553. return detail::make_view_impl(
  1554. std::forward<E>(e),
  1555. std::make_index_sequence<sizeof...(S)>(),
  1556. std::forward<S>(slices)...
  1557. );
  1558. }
  1559. namespace detail
  1560. {
  1561. class row_impl
  1562. {
  1563. public:
  1564. template <class E>
  1565. inline static auto make(E&& e, const std::ptrdiff_t index)
  1566. {
  1567. const auto shape = e.shape();
  1568. check_dimension(shape);
  1569. return view(e, index, xt::all());
  1570. }
  1571. private:
  1572. template <class S>
  1573. inline static void check_dimension(const S& shape)
  1574. {
  1575. if (shape.size() != 2)
  1576. {
  1577. XTENSOR_THROW(
  1578. std::invalid_argument,
  1579. "A row can only be accessed on an expression with exact two dimensions"
  1580. );
  1581. }
  1582. }
  1583. template <class T, std::size_t N>
  1584. inline static void check_dimension(const std::array<T, N>&)
  1585. {
  1586. static_assert(N == 2, "A row can only be accessed on an expression with exact two dimensions");
  1587. }
  1588. };
  1589. class column_impl
  1590. {
  1591. public:
  1592. template <class E>
  1593. inline static auto make(E&& e, const std::ptrdiff_t index)
  1594. {
  1595. const auto shape = e.shape();
  1596. check_dimension(shape);
  1597. return view(e, xt::all(), index);
  1598. }
  1599. private:
  1600. template <class S>
  1601. inline static void check_dimension(const S& shape)
  1602. {
  1603. if (shape.size() != 2)
  1604. {
  1605. XTENSOR_THROW(
  1606. std::invalid_argument,
  1607. "A column can only be accessed on an expression with exact two dimensions"
  1608. );
  1609. }
  1610. }
  1611. template <class T, std::size_t N>
  1612. inline static void check_dimension(const std::array<T, N>&)
  1613. {
  1614. static_assert(N == 2, "A column can only be accessed on an expression with exact two dimensions");
  1615. }
  1616. };
  1617. }
  1618. /**
  1619. * Constructs and returns a row (sliced view) on the specified expression.
  1620. * Users should not directly construct the slices but call helper functions
  1621. * instead. This function is only allowed on expressions with two dimensions.
  1622. * @param e the xexpression to adapt
  1623. * @param index 0-based index of the row, negative indices will return the
  1624. * last rows in reverse order.
  1625. * @throws std::invalid_argument if the expression has more than 2 dimensions.
  1626. */
  1627. template <class E>
  1628. inline auto row(E&& e, std::ptrdiff_t index)
  1629. {
  1630. return detail::row_impl::make(e, index);
  1631. }
  1632. /**
  1633. * Constructs and returns a column (sliced view) on the specified expression.
  1634. * Users should not directly construct the slices but call helper functions
  1635. * instead. This function is only allowed on expressions with two dimensions.
  1636. * @param e the xexpression to adapt
  1637. * @param index 0-based index of the column, negative indices will return the
  1638. * last columns in reverse order.
  1639. * @throws std::invalid_argument if the expression has more than 2 dimensions.
  1640. */
  1641. template <class E>
  1642. inline auto col(E&& e, std::ptrdiff_t index)
  1643. {
  1644. return detail::column_impl::make(e, index);
  1645. }
  1646. /***************
  1647. * stepper api *
  1648. ***************/
  1649. template <class CT, class... S>
  1650. template <class ST, bool Enable>
  1651. inline auto xview<CT, S...>::stepper_begin(const ST& shape) -> std::enable_if_t<!Enable, stepper>
  1652. {
  1653. size_type offset = shape.size() - this->dimension();
  1654. return stepper(this, m_e.stepper_begin(m_e.shape()), offset);
  1655. }
  1656. template <class CT, class... S>
  1657. template <class ST, bool Enable>
  1658. inline auto xview<CT, S...>::stepper_end(const ST& shape, layout_type l)
  1659. -> std::enable_if_t<!Enable, stepper>
  1660. {
  1661. size_type offset = shape.size() - this->dimension();
  1662. return stepper(this, m_e.stepper_end(m_e.shape(), l), offset, true, l);
  1663. }
  1664. template <class CT, class... S>
  1665. template <class ST, bool Enable>
  1666. inline auto xview<CT, S...>::stepper_begin(const ST& shape) const
  1667. -> std::enable_if_t<!Enable, const_stepper>
  1668. {
  1669. size_type offset = shape.size() - this->dimension();
  1670. const xexpression_type& e = m_e;
  1671. return const_stepper(this, e.stepper_begin(m_e.shape()), offset);
  1672. }
  1673. template <class CT, class... S>
  1674. template <class ST, bool Enable>
  1675. inline auto xview<CT, S...>::stepper_end(const ST& shape, layout_type l) const
  1676. -> std::enable_if_t<!Enable, const_stepper>
  1677. {
  1678. size_type offset = shape.size() - this->dimension();
  1679. const xexpression_type& e = m_e;
  1680. return const_stepper(this, e.stepper_end(m_e.shape(), l), offset, true, l);
  1681. }
  1682. template <class CT, class... S>
  1683. template <class ST, bool Enable>
  1684. inline auto xview<CT, S...>::stepper_begin(const ST& shape) -> std::enable_if_t<Enable, stepper>
  1685. {
  1686. size_type offset = shape.size() - this->dimension();
  1687. return stepper(this, data_xbegin(), offset);
  1688. }
  1689. template <class CT, class... S>
  1690. template <class ST, bool Enable>
  1691. inline auto xview<CT, S...>::stepper_end(const ST& shape, layout_type l)
  1692. -> std::enable_if_t<Enable, stepper>
  1693. {
  1694. size_type offset = shape.size() - this->dimension();
  1695. return stepper(this, data_xend(l, offset), offset);
  1696. }
  1697. template <class CT, class... S>
  1698. template <class ST, bool Enable>
  1699. inline auto xview<CT, S...>::stepper_begin(const ST& shape) const
  1700. -> std::enable_if_t<Enable, const_stepper>
  1701. {
  1702. size_type offset = shape.size() - this->dimension();
  1703. return const_stepper(this, data_xbegin(), offset);
  1704. }
  1705. template <class CT, class... S>
  1706. template <class ST, bool Enable>
  1707. inline auto xview<CT, S...>::stepper_end(const ST& shape, layout_type l) const
  1708. -> std::enable_if_t<Enable, const_stepper>
  1709. {
  1710. size_type offset = shape.size() - this->dimension();
  1711. return const_stepper(this, data_xend(l, offset), offset);
  1712. }
  1713. /********************************
  1714. * xview_stepper implementation *
  1715. ********************************/
  1716. template <bool is_const, class CT, class... S>
  1717. inline xview_stepper<is_const, CT, S...>::xview_stepper(
  1718. view_type* view,
  1719. substepper_type it,
  1720. size_type offset,
  1721. bool end,
  1722. layout_type l
  1723. )
  1724. : p_view(view)
  1725. , m_it(it)
  1726. , m_offset(offset)
  1727. {
  1728. if (!end)
  1729. {
  1730. std::fill(m_index_keeper.begin(), m_index_keeper.end(), 0);
  1731. auto func = [](const auto& s) noexcept
  1732. {
  1733. return xt::value(s, 0);
  1734. };
  1735. for (size_type i = 0; i < sizeof...(S); ++i)
  1736. {
  1737. if (!is_newaxis_slice(i))
  1738. {
  1739. size_type s = apply<size_type>(i, func, p_view->slices());
  1740. size_type index = i - newaxis_count_before<S...>(i);
  1741. m_it.step(index, s);
  1742. }
  1743. }
  1744. }
  1745. else
  1746. {
  1747. to_end_impl(l);
  1748. }
  1749. }
  1750. template <bool is_const, class CT, class... S>
  1751. inline auto xview_stepper<is_const, CT, S...>::operator*() const -> reference
  1752. {
  1753. return *m_it;
  1754. }
  1755. template <bool is_const, class CT, class... S>
  1756. inline void xview_stepper<is_const, CT, S...>::step(size_type dim)
  1757. {
  1758. auto func = [this](size_type index, size_type offset)
  1759. {
  1760. m_it.step(index, offset);
  1761. };
  1762. common_step_forward(dim, func);
  1763. }
  1764. template <bool is_const, class CT, class... S>
  1765. inline void xview_stepper<is_const, CT, S...>::step_back(size_type dim)
  1766. {
  1767. auto func = [this](size_type index, size_type offset)
  1768. {
  1769. m_it.step_back(index, offset);
  1770. };
  1771. common_step_backward(dim, func);
  1772. }
  1773. template <bool is_const, class CT, class... S>
  1774. inline void xview_stepper<is_const, CT, S...>::step(size_type dim, size_type n)
  1775. {
  1776. auto func = [this](size_type index, size_type offset)
  1777. {
  1778. m_it.step(index, offset);
  1779. };
  1780. common_step_forward(dim, n, func);
  1781. }
  1782. template <bool is_const, class CT, class... S>
  1783. inline void xview_stepper<is_const, CT, S...>::step_back(size_type dim, size_type n)
  1784. {
  1785. auto func = [this](size_type index, size_type offset)
  1786. {
  1787. m_it.step_back(index, offset);
  1788. };
  1789. common_step_backward(dim, n, func);
  1790. }
  1791. template <bool is_const, class CT, class... S>
  1792. inline void xview_stepper<is_const, CT, S...>::reset(size_type dim)
  1793. {
  1794. auto func = [this](size_type index, size_type offset)
  1795. {
  1796. m_it.step_back(index, offset);
  1797. };
  1798. common_reset(dim, func, false);
  1799. }
  1800. template <bool is_const, class CT, class... S>
  1801. inline void xview_stepper<is_const, CT, S...>::reset_back(size_type dim)
  1802. {
  1803. auto func = [this](size_type index, size_type offset)
  1804. {
  1805. m_it.step(index, offset);
  1806. };
  1807. common_reset(dim, func, true);
  1808. }
  1809. template <bool is_const, class CT, class... S>
  1810. inline void xview_stepper<is_const, CT, S...>::to_begin()
  1811. {
  1812. std::fill(m_index_keeper.begin(), m_index_keeper.end(), 0);
  1813. m_it.to_begin();
  1814. }
  1815. template <bool is_const, class CT, class... S>
  1816. inline void xview_stepper<is_const, CT, S...>::to_end(layout_type l)
  1817. {
  1818. m_it.to_end(l);
  1819. to_end_impl(l);
  1820. }
  1821. template <bool is_const, class CT, class... S>
  1822. inline bool xview_stepper<is_const, CT, S...>::is_newaxis_slice(size_type index) const noexcept
  1823. {
  1824. // A bit tricky but avoids a lot of template instantiations
  1825. return newaxis_count_before<S...>(index + 1) != newaxis_count_before<S...>(index);
  1826. }
  1827. template <bool is_const, class CT, class... S>
  1828. inline void xview_stepper<is_const, CT, S...>::to_end_impl(layout_type l)
  1829. {
  1830. auto func = [](const auto& s) noexcept
  1831. {
  1832. return xt::value(s, get_size(s) - 1);
  1833. };
  1834. auto size_func = [](const auto& s) noexcept
  1835. {
  1836. return get_size(s);
  1837. };
  1838. for (size_type i = 0; i < sizeof...(S); ++i)
  1839. {
  1840. if (!is_newaxis_slice(i))
  1841. {
  1842. size_type s = apply<size_type>(i, func, p_view->slices());
  1843. size_type ix = apply<size_type>(i, size_func, p_view->slices());
  1844. m_index_keeper[i] = ix - size_type(1);
  1845. size_type index = i - newaxis_count_before<S...>(i);
  1846. s = p_view->underlying_size(index) - 1 - s;
  1847. m_it.step_back(index, s);
  1848. }
  1849. }
  1850. if (l == layout_type::row_major)
  1851. {
  1852. for (size_type i = sizeof...(S); i > 0; --i)
  1853. {
  1854. if (!is_newaxis_slice(i - 1))
  1855. {
  1856. m_index_keeper[i - 1]++;
  1857. break;
  1858. }
  1859. }
  1860. }
  1861. else if (l == layout_type::column_major)
  1862. {
  1863. for (size_type i = 0; i < sizeof...(S); ++i)
  1864. {
  1865. if (!is_newaxis_slice(i))
  1866. {
  1867. m_index_keeper[i]++;
  1868. break;
  1869. }
  1870. }
  1871. }
  1872. else
  1873. {
  1874. XTENSOR_THROW(std::runtime_error, "Iteration only allowed in row or column major.");
  1875. }
  1876. }
  1877. template <bool is_const, class CT, class... S>
  1878. template <class F>
  1879. void xview_stepper<is_const, CT, S...>::common_step_forward(size_type dim, F f)
  1880. {
  1881. if (dim >= m_offset)
  1882. {
  1883. auto func = [&dim, this](const auto& s) noexcept
  1884. {
  1885. return step_size(s, this->m_index_keeper[dim]++, 1);
  1886. };
  1887. size_type index = integral_skip<S...>(dim);
  1888. if (!is_newaxis_slice(index))
  1889. {
  1890. size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
  1891. : 1;
  1892. index -= newaxis_count_before<S...>(index);
  1893. f(index, step_size);
  1894. }
  1895. }
  1896. }
  1897. template <bool is_const, class CT, class... S>
  1898. template <class F>
  1899. void xview_stepper<is_const, CT, S...>::common_step_forward(size_type dim, size_type n, F f)
  1900. {
  1901. if (dim >= m_offset)
  1902. {
  1903. auto func = [&dim, &n, this](const auto& s) noexcept
  1904. {
  1905. auto st_size = step_size(s, this->m_index_keeper[dim], n);
  1906. this->m_index_keeper[dim] += n;
  1907. return size_type(st_size);
  1908. };
  1909. size_type index = integral_skip<S...>(dim);
  1910. if (!is_newaxis_slice(index))
  1911. {
  1912. size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
  1913. : n;
  1914. index -= newaxis_count_before<S...>(index);
  1915. f(index, step_size);
  1916. }
  1917. }
  1918. }
  1919. template <bool is_const, class CT, class... S>
  1920. template <class F>
  1921. void xview_stepper<is_const, CT, S...>::common_step_backward(size_type dim, F f)
  1922. {
  1923. if (dim >= m_offset)
  1924. {
  1925. auto func = [&dim, this](const auto& s) noexcept
  1926. {
  1927. this->m_index_keeper[dim]--;
  1928. return step_size(s, this->m_index_keeper[dim], 1);
  1929. };
  1930. size_type index = integral_skip<S...>(dim);
  1931. if (!is_newaxis_slice(index))
  1932. {
  1933. size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
  1934. : 1;
  1935. index -= newaxis_count_before<S...>(index);
  1936. f(index, step_size);
  1937. }
  1938. }
  1939. }
  1940. template <bool is_const, class CT, class... S>
  1941. template <class F>
  1942. void xview_stepper<is_const, CT, S...>::common_step_backward(size_type dim, size_type n, F f)
  1943. {
  1944. if (dim >= m_offset)
  1945. {
  1946. auto func = [&dim, &n, this](const auto& s) noexcept
  1947. {
  1948. this->m_index_keeper[dim] -= n;
  1949. return step_size(s, this->m_index_keeper[dim], n);
  1950. };
  1951. size_type index = integral_skip<S...>(dim);
  1952. if (!is_newaxis_slice(index))
  1953. {
  1954. size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
  1955. : n;
  1956. index -= newaxis_count_before<S...>(index);
  1957. f(index, step_size);
  1958. }
  1959. }
  1960. }
  1961. template <bool is_const, class CT, class... S>
  1962. template <class F>
  1963. void xview_stepper<is_const, CT, S...>::common_reset(size_type dim, F f, bool backwards)
  1964. {
  1965. auto size_func = [](const auto& s) noexcept
  1966. {
  1967. return get_size(s);
  1968. };
  1969. auto end_func = [](const auto& s) noexcept
  1970. {
  1971. return xt::value(s, get_size(s) - 1) - xt::value(s, 0);
  1972. };
  1973. size_type index = integral_skip<S...>(dim);
  1974. if (!is_newaxis_slice(index))
  1975. {
  1976. if (dim < m_index_keeper.size())
  1977. {
  1978. size_type size = index < sizeof...(S) ? apply<size_type>(index, size_func, p_view->slices())
  1979. : p_view->shape()[dim];
  1980. m_index_keeper[dim] = backwards ? size - 1 : 0;
  1981. }
  1982. size_type reset_n = index < sizeof...(S) ? apply<size_type>(index, end_func, p_view->slices())
  1983. : p_view->shape()[dim] - 1;
  1984. index -= newaxis_count_before<S...>(index);
  1985. f(index, reset_n);
  1986. }
  1987. }
  1988. }
  1989. #endif