xbuffer_adaptor.hpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  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_BUFFER_ADAPTOR_HPP
  10. #define XTENSOR_BUFFER_ADAPTOR_HPP
  11. #include <algorithm>
  12. #include <functional>
  13. #include <iterator>
  14. #include <memory>
  15. #include <stdexcept>
  16. #include <xtl/xclosure.hpp>
  17. #include "xstorage.hpp"
  18. #include "xtensor_config.hpp"
  19. namespace xt
  20. {
  21. struct no_ownership
  22. {
  23. };
  24. using smart_ownership = no_ownership;
  25. struct acquire_ownership
  26. {
  27. };
  28. template <class CP, class O = no_ownership, class A = std::allocator<std::remove_pointer_t<std::remove_reference_t<CP>>>>
  29. class xbuffer_adaptor;
  30. /********************
  31. * buffer_storage_t *
  32. ********************/
  33. namespace detail
  34. {
  35. template <class CP, class A>
  36. class xbuffer_storage
  37. {
  38. public:
  39. using self_type = xbuffer_storage<CP, A>;
  40. using allocator_type = A;
  41. using destructor_type = allocator_type;
  42. using allocator_traits = std::allocator_traits<allocator_type>;
  43. using value_type = typename allocator_traits::value_type;
  44. using reference = std::conditional_t<
  45. std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
  46. const value_type&,
  47. value_type&>;
  48. using const_reference = const value_type&;
  49. using pointer = std::conditional_t<
  50. std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
  51. typename allocator_traits::const_pointer,
  52. typename allocator_traits::pointer>;
  53. using const_pointer = typename allocator_traits::const_pointer;
  54. using size_type = typename allocator_traits::size_type;
  55. using difference_type = typename allocator_traits::difference_type;
  56. xbuffer_storage();
  57. template <class P>
  58. xbuffer_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type());
  59. size_type size() const noexcept;
  60. void resize(size_type size);
  61. pointer data() noexcept;
  62. const_pointer data() const noexcept;
  63. void swap(self_type& rhs) noexcept;
  64. template <class P>
  65. void reset_data(P&& data, size_type size) noexcept;
  66. private:
  67. pointer p_data;
  68. size_type m_size;
  69. };
  70. template <class CP, class D>
  71. class xbuffer_smart_pointer
  72. {
  73. public:
  74. using self_type = xbuffer_storage<CP, D>;
  75. using destructor_type = D;
  76. using value_type = std::remove_const_t<std::remove_pointer_t<std::remove_reference_t<CP>>>;
  77. using allocator_type = std::allocator<value_type>;
  78. using allocator_traits = std::allocator_traits<allocator_type>;
  79. using reference = std::conditional_t<
  80. std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
  81. const value_type&,
  82. value_type&>;
  83. using const_reference = const value_type&;
  84. using pointer = std::conditional_t<
  85. std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
  86. typename allocator_traits::const_pointer,
  87. typename allocator_traits::pointer>;
  88. using const_pointer = typename allocator_traits::const_pointer;
  89. using size_type = typename allocator_traits::size_type;
  90. using difference_type = typename allocator_traits::difference_type;
  91. xbuffer_smart_pointer();
  92. template <class P, class DT>
  93. xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct);
  94. size_type size() const noexcept;
  95. void resize(size_type size);
  96. pointer data() noexcept;
  97. const_pointer data() const noexcept;
  98. void swap(self_type& rhs) noexcept;
  99. template <class P, class DT>
  100. void reset_data(P&& data, size_type size, DT&& destruct) noexcept;
  101. private:
  102. pointer p_data;
  103. size_type m_size;
  104. destructor_type m_destruct;
  105. };
  106. template <class CP, class A>
  107. class xbuffer_owner_storage
  108. {
  109. public:
  110. using self_type = xbuffer_owner_storage<CP, A>;
  111. using allocator_type = A;
  112. using destructor_type = allocator_type;
  113. using allocator_traits = std::allocator_traits<allocator_type>;
  114. using value_type = typename allocator_traits::value_type;
  115. using reference = std::conditional_t<
  116. std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
  117. const value_type&,
  118. value_type&>;
  119. using const_reference = const value_type&;
  120. using pointer = std::conditional_t<
  121. std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
  122. typename allocator_traits::const_pointer,
  123. typename allocator_traits::pointer>;
  124. using const_pointer = typename allocator_traits::const_pointer;
  125. using size_type = typename allocator_traits::size_type;
  126. using difference_type = typename allocator_traits::difference_type;
  127. xbuffer_owner_storage() = default;
  128. template <class P>
  129. xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type());
  130. ~xbuffer_owner_storage();
  131. xbuffer_owner_storage(const self_type&) = delete;
  132. self_type& operator=(const self_type&);
  133. xbuffer_owner_storage(self_type&&);
  134. self_type& operator=(self_type&&);
  135. size_type size() const noexcept;
  136. void resize(size_type size);
  137. pointer data() noexcept;
  138. const_pointer data() const noexcept;
  139. allocator_type get_allocator() const noexcept;
  140. void swap(self_type& rhs) noexcept;
  141. template <class P>
  142. void reset_data(P&& data, size_type size, const allocator_type& alloc = allocator_type()) noexcept;
  143. private:
  144. xtl::xclosure_wrapper<CP> m_data;
  145. size_type m_size;
  146. bool m_moved_from;
  147. allocator_type m_allocator;
  148. };
  149. // Workaround for MSVC2015: using void_t results in some
  150. // template instantiation caching that leads to wrong
  151. // type deduction later in xfunction.
  152. template <class T>
  153. struct msvc2015_void
  154. {
  155. using type = void;
  156. };
  157. template <class T>
  158. using msvc2015_void_t = typename msvc2015_void<T>::type;
  159. template <class E, class = void>
  160. struct is_lambda_type : std::false_type
  161. {
  162. };
  163. // check if operator() is available
  164. template <class E>
  165. struct is_lambda_type<E, msvc2015_void_t<decltype(&E::operator())>> : std::true_type
  166. {
  167. };
  168. template <class T>
  169. struct self_type
  170. {
  171. using type = T;
  172. };
  173. template <class CP, class A, class O>
  174. struct get_buffer_storage
  175. {
  176. using type = xtl::mpl::eval_if_t<
  177. is_lambda_type<A>,
  178. self_type<xbuffer_smart_pointer<CP, A>>,
  179. self_type<xbuffer_storage<CP, A>>>;
  180. };
  181. template <class CP, class A>
  182. struct get_buffer_storage<CP, A, acquire_ownership>
  183. {
  184. using type = xbuffer_owner_storage<CP, A>;
  185. };
  186. template <class CP, class T>
  187. struct get_buffer_storage<CP, std::shared_ptr<T>, no_ownership>
  188. {
  189. using type = xbuffer_smart_pointer<CP, std::shared_ptr<T>>;
  190. };
  191. template <class CP, class T>
  192. struct get_buffer_storage<CP, std::unique_ptr<T>, no_ownership>
  193. {
  194. using type = xbuffer_smart_pointer<CP, std::unique_ptr<T>>;
  195. };
  196. template <class CP, class A, class O>
  197. using buffer_storage_t = typename get_buffer_storage<CP, A, O>::type;
  198. }
  199. /************************
  200. * xbuffer_adaptor_base *
  201. ************************/
  202. template <class D>
  203. struct buffer_inner_types;
  204. template <class D>
  205. class xbuffer_adaptor_base
  206. {
  207. public:
  208. using self_type = xbuffer_adaptor_base<D>;
  209. using derived_type = D;
  210. using inner_types = buffer_inner_types<D>;
  211. using value_type = typename inner_types::value_type;
  212. using reference = typename inner_types::reference;
  213. using const_reference = typename inner_types::const_reference;
  214. using pointer = typename inner_types::pointer;
  215. using const_pointer = typename inner_types::const_pointer;
  216. using size_type = typename inner_types::size_type;
  217. using difference_type = typename inner_types::difference_type;
  218. using iterator = typename inner_types::iterator;
  219. using const_iterator = typename inner_types::const_iterator;
  220. using reverse_iterator = typename inner_types::reverse_iterator;
  221. using const_reverse_iterator = typename inner_types::const_reverse_iterator;
  222. using index_type = typename inner_types::index_type;
  223. bool empty() const noexcept;
  224. reference operator[](size_type i);
  225. const_reference operator[](size_type i) const;
  226. reference front();
  227. const_reference front() const;
  228. reference back();
  229. const_reference back() const;
  230. iterator begin() noexcept;
  231. iterator end() noexcept;
  232. const_iterator begin() const noexcept;
  233. const_iterator end() const noexcept;
  234. const_iterator cbegin() const noexcept;
  235. const_iterator cend() const noexcept;
  236. reverse_iterator rbegin() noexcept;
  237. reverse_iterator rend() noexcept;
  238. const_reverse_iterator rbegin() const noexcept;
  239. const_reverse_iterator rend() const noexcept;
  240. const_reverse_iterator crbegin() const noexcept;
  241. const_reverse_iterator crend() const noexcept;
  242. derived_type& derived_cast() noexcept;
  243. const derived_type& derived_cast() const noexcept;
  244. protected:
  245. xbuffer_adaptor_base() = default;
  246. ~xbuffer_adaptor_base() = default;
  247. xbuffer_adaptor_base(const self_type&) = default;
  248. self_type& operator=(const self_type&) = default;
  249. xbuffer_adaptor_base(self_type&&) = default;
  250. self_type& operator=(self_type&&) = default;
  251. };
  252. template <class D>
  253. bool operator==(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs);
  254. template <class D>
  255. bool operator!=(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs);
  256. template <class D>
  257. bool operator<(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs);
  258. template <class D>
  259. bool operator<=(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs);
  260. template <class D>
  261. bool operator>(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs);
  262. template <class D>
  263. bool operator>=(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs);
  264. /*******************
  265. * xbuffer_adaptor *
  266. *******************/
  267. template <class CP, class O, class A>
  268. struct buffer_inner_types<xbuffer_adaptor<CP, O, A>>
  269. {
  270. using base_type = detail::buffer_storage_t<CP, A, O>;
  271. using value_type = typename base_type::value_type;
  272. using reference = typename base_type::reference;
  273. using const_reference = typename base_type::const_reference;
  274. using pointer = typename base_type::pointer;
  275. using const_pointer = typename base_type::const_pointer;
  276. using size_type = typename base_type::size_type;
  277. using difference_type = typename base_type::difference_type;
  278. using iterator = pointer;
  279. using const_iterator = const_pointer;
  280. using reverse_iterator = std::reverse_iterator<iterator>;
  281. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  282. using index_type = size_type;
  283. };
  284. template <class CP, class O, class A>
  285. class xbuffer_adaptor : private detail::buffer_storage_t<CP, A, O>,
  286. public xbuffer_adaptor_base<xbuffer_adaptor<CP, O, A>>
  287. {
  288. public:
  289. using self_type = xbuffer_adaptor<CP, O, A>;
  290. using base_type = detail::buffer_storage_t<CP, A, O>;
  291. using buffer_base_type = xbuffer_adaptor_base<self_type>;
  292. using allocator_type = typename base_type::allocator_type;
  293. using destructor_type = typename base_type::destructor_type;
  294. using value_type = typename buffer_base_type::value_type;
  295. using reference = typename buffer_base_type::reference;
  296. using const_reference = typename buffer_base_type::const_reference;
  297. using pointer = typename buffer_base_type::pointer;
  298. using const_pointer = typename buffer_base_type::const_pointer;
  299. using size_type = typename buffer_base_type::size_type;
  300. using difference_type = typename buffer_base_type::difference_type;
  301. using iterator = typename buffer_base_type::iterator;
  302. using const_iterator = typename buffer_base_type::const_iterator;
  303. using reverse_iterator = typename buffer_base_type::reverse_iterator;
  304. using const_reverse_iterator = typename buffer_base_type::const_reverse_iterator;
  305. using temporary_type = uvector<value_type, allocator_type>;
  306. xbuffer_adaptor() = default;
  307. using base_type::base_type;
  308. ~xbuffer_adaptor() = default;
  309. xbuffer_adaptor(const self_type&) = default;
  310. self_type& operator=(const self_type&) = default;
  311. xbuffer_adaptor(self_type&&) = default;
  312. xbuffer_adaptor& operator=(self_type&&) = default;
  313. self_type& operator=(temporary_type&&);
  314. using base_type::data;
  315. using base_type::reset_data;
  316. using base_type::resize;
  317. using base_type::size;
  318. using base_type::swap;
  319. };
  320. template <class CP, class O, class A>
  321. void swap(xbuffer_adaptor<CP, O, A>& lhs, xbuffer_adaptor<CP, O, A>& rhs) noexcept;
  322. /*********************
  323. * xiterator_adaptor *
  324. *********************/
  325. template <class I, class CI>
  326. class xiterator_adaptor;
  327. template <class I, class CI>
  328. struct buffer_inner_types<xiterator_adaptor<I, CI>>
  329. {
  330. using traits = std::iterator_traits<I>;
  331. using const_traits = std::iterator_traits<CI>;
  332. using value_type = std::common_type_t<typename traits::value_type, typename const_traits::value_type>;
  333. using reference = typename traits::reference;
  334. using const_reference = typename const_traits::reference;
  335. using pointer = typename traits::pointer;
  336. using const_pointer = typename const_traits::pointer;
  337. using difference_type = std::common_type_t<typename traits::difference_type, typename const_traits::difference_type>;
  338. using size_type = std::make_unsigned_t<difference_type>;
  339. using iterator = I;
  340. using const_iterator = CI;
  341. using reverse_iterator = std::reverse_iterator<iterator>;
  342. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  343. using index_type = difference_type;
  344. };
  345. template <class I, class CI>
  346. class xiterator_adaptor : public xbuffer_adaptor_base<xiterator_adaptor<I, CI>>
  347. {
  348. public:
  349. using self_type = xiterator_adaptor<I, CI>;
  350. using base_type = xbuffer_adaptor_base<self_type>;
  351. using value_type = typename base_type::value_type;
  352. using allocator_type = std::allocator<value_type>;
  353. using size_type = typename base_type::size_type;
  354. using iterator = typename base_type::iterator;
  355. using const_iterator = typename base_type::const_iterator;
  356. using temporary_type = uvector<value_type, allocator_type>;
  357. xiterator_adaptor() = default;
  358. xiterator_adaptor(I it, CI cit, size_type size);
  359. ~xiterator_adaptor() = default;
  360. xiterator_adaptor(const self_type&) = default;
  361. xiterator_adaptor& operator=(const self_type&) = default;
  362. xiterator_adaptor(self_type&&) = default;
  363. xiterator_adaptor& operator=(self_type&&) = default;
  364. xiterator_adaptor& operator=(const temporary_type& rhs);
  365. xiterator_adaptor& operator=(temporary_type&& rhs);
  366. size_type size() const noexcept;
  367. void resize(size_type size);
  368. iterator data() noexcept;
  369. const_iterator data() const noexcept;
  370. void swap(self_type& rhs) noexcept;
  371. private:
  372. I m_it;
  373. CI m_cit;
  374. size_type m_size;
  375. };
  376. template <class I, class CI>
  377. void swap(xiterator_adaptor<I, CI>& lhs, xiterator_adaptor<I, CI>& rhs) noexcept;
  378. template <class I, class CI>
  379. struct is_contiguous_container<xiterator_adaptor<I, CI>> : is_contiguous_container<I>
  380. {
  381. };
  382. /***************************
  383. * xiterator_owner_adaptor *
  384. ***************************/
  385. template <class C, class IG>
  386. class xiterator_owner_adaptor;
  387. template <class C, class IG>
  388. struct buffer_inner_types<xiterator_owner_adaptor<C, IG>>
  389. {
  390. using iterator = typename IG::iterator;
  391. using const_iterator = typename IG::const_iterator;
  392. using reverse_iterator = std::reverse_iterator<iterator>;
  393. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  394. using traits = std::iterator_traits<iterator>;
  395. using const_traits = std::iterator_traits<const_iterator>;
  396. using value_type = std::common_type_t<typename traits::value_type, typename const_traits::value_type>;
  397. using reference = typename traits::reference;
  398. using const_reference = typename const_traits::reference;
  399. using pointer = typename traits::pointer;
  400. using const_pointer = typename const_traits::pointer;
  401. using difference_type = std::common_type_t<typename traits::difference_type, typename const_traits::difference_type>;
  402. using size_type = std::make_unsigned_t<difference_type>;
  403. using index_type = difference_type;
  404. };
  405. template <class C, class IG>
  406. class xiterator_owner_adaptor : public xbuffer_adaptor_base<xiterator_owner_adaptor<C, IG>>
  407. {
  408. public:
  409. using self_type = xiterator_owner_adaptor<C, IG>;
  410. using base_type = xbuffer_adaptor_base<self_type>;
  411. using value_type = typename base_type::value_type;
  412. using allocator_type = std::allocator<value_type>;
  413. using size_type = typename base_type::size_type;
  414. using iterator = typename base_type::iterator;
  415. using const_iterator = typename base_type::const_iterator;
  416. using temporary_type = uvector<value_type, allocator_type>;
  417. xiterator_owner_adaptor(C&& c);
  418. ~xiterator_owner_adaptor() = default;
  419. xiterator_owner_adaptor(const self_type&);
  420. xiterator_owner_adaptor& operator=(const self_type&);
  421. xiterator_owner_adaptor(self_type&&);
  422. xiterator_owner_adaptor& operator=(self_type&&);
  423. xiterator_owner_adaptor& operator=(const temporary_type& rhs);
  424. xiterator_owner_adaptor& operator=(temporary_type&& rhs);
  425. size_type size() const noexcept;
  426. void resize(size_type size);
  427. iterator data() noexcept;
  428. const_iterator data() const noexcept;
  429. void swap(self_type& rhs) noexcept;
  430. private:
  431. void init_iterators();
  432. C m_container;
  433. iterator m_it;
  434. const_iterator m_cit;
  435. size_type m_size;
  436. };
  437. template <class C, class IG>
  438. void swap(xiterator_owner_adaptor<C, IG>& lhs, xiterator_owner_adaptor<C, IG>& rhs) noexcept;
  439. template <class C, class IG>
  440. struct is_contiguous_container<xiterator_owner_adaptor<C, IG>>
  441. : is_contiguous_container<typename IG::iterator>
  442. {
  443. };
  444. /**************************
  445. * make_xiterator_adaptor *
  446. **************************/
  447. template <class C, class IG>
  448. auto make_xiterator_adaptor(C&& container, IG iterator_getter);
  449. /************************************
  450. * temporary_container metafunction *
  451. ************************************/
  452. template <class C>
  453. struct temporary_container
  454. {
  455. using type = C;
  456. };
  457. template <class CP, class O, class A>
  458. struct temporary_container<xbuffer_adaptor<CP, O, A>>
  459. {
  460. using type = typename xbuffer_adaptor<CP, O, A>::temporary_type;
  461. };
  462. template <class I, class CI>
  463. struct temporary_container<xiterator_adaptor<I, CI>>
  464. {
  465. using type = typename xiterator_adaptor<I, CI>::temporary_type;
  466. };
  467. template <class C, class IG>
  468. struct temporary_container<xiterator_owner_adaptor<C, IG>>
  469. {
  470. using type = typename xiterator_owner_adaptor<C, IG>::temporary_type;
  471. };
  472. template <class C>
  473. using temporary_container_t = typename temporary_container<C>::type;
  474. /**********************************
  475. * xbuffer_storage implementation *
  476. **********************************/
  477. namespace detail
  478. {
  479. template <class CP, class A>
  480. inline xbuffer_storage<CP, A>::xbuffer_storage()
  481. : p_data(nullptr)
  482. , m_size(0)
  483. {
  484. }
  485. template <class CP, class A>
  486. template <class P>
  487. inline xbuffer_storage<CP, A>::xbuffer_storage(P&& data, size_type size, const allocator_type&)
  488. : p_data(std::forward<P>(data))
  489. , m_size(size)
  490. {
  491. }
  492. template <class CP, class A>
  493. inline auto xbuffer_storage<CP, A>::size() const noexcept -> size_type
  494. {
  495. return m_size;
  496. }
  497. template <class CP, class A>
  498. inline void xbuffer_storage<CP, A>::resize(size_type size)
  499. {
  500. if (size != m_size)
  501. {
  502. XTENSOR_THROW(std::runtime_error, "xbuffer_storage not resizable");
  503. }
  504. }
  505. template <class CP, class A>
  506. inline auto xbuffer_storage<CP, A>::data() noexcept -> pointer
  507. {
  508. return p_data;
  509. }
  510. template <class CP, class A>
  511. inline auto xbuffer_storage<CP, A>::data() const noexcept -> const_pointer
  512. {
  513. return p_data;
  514. }
  515. template <class CP, class A>
  516. inline void xbuffer_storage<CP, A>::swap(self_type& rhs) noexcept
  517. {
  518. using std::swap;
  519. swap(p_data, rhs.p_data);
  520. swap(m_size, rhs.m_size);
  521. }
  522. template <class CP, class A>
  523. template <class P>
  524. inline void xbuffer_storage<CP, A>::reset_data(P&& data, size_type size) noexcept
  525. {
  526. p_data = std::forward<P>(data);
  527. m_size = size;
  528. }
  529. }
  530. /****************************************
  531. * xbuffer_owner_storage implementation *
  532. ****************************************/
  533. namespace detail
  534. {
  535. template <class CP, class A>
  536. template <class P>
  537. inline xbuffer_owner_storage<CP, A>::xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc)
  538. : m_data(std::forward<P>(data))
  539. , m_size(size)
  540. , m_moved_from(false)
  541. , m_allocator(alloc)
  542. {
  543. }
  544. template <class CP, class A>
  545. inline xbuffer_owner_storage<CP, A>::~xbuffer_owner_storage()
  546. {
  547. if (!m_moved_from)
  548. {
  549. safe_destroy_deallocate(m_allocator, m_data.get(), m_size);
  550. m_size = 0;
  551. }
  552. }
  553. template <class CP, class A>
  554. inline auto xbuffer_owner_storage<CP, A>::operator=(const self_type& rhs) -> self_type&
  555. {
  556. using std::swap;
  557. if (this != &rhs)
  558. {
  559. allocator_type al = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
  560. rhs.get_allocator()
  561. );
  562. pointer tmp = safe_init_allocate(al, rhs.m_size);
  563. if (xtrivially_default_constructible<value_type>::value)
  564. {
  565. std::uninitialized_copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp);
  566. }
  567. else
  568. {
  569. std::copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp);
  570. }
  571. swap(m_data.get(), tmp);
  572. swap(m_allocator, al);
  573. safe_destroy_deallocate(al, tmp, m_size);
  574. m_size = rhs.m_size;
  575. }
  576. return *this;
  577. }
  578. template <class CP, class A>
  579. inline xbuffer_owner_storage<CP, A>::xbuffer_owner_storage(self_type&& rhs)
  580. : m_data(std::move(rhs.m_data))
  581. , m_size(std::move(rhs.m_size))
  582. , m_moved_from(std::move(rhs.m_moved_from))
  583. , m_allocator(std::move(rhs.m_allocator))
  584. {
  585. rhs.m_moved_from = true;
  586. rhs.m_size = 0;
  587. }
  588. template <class CP, class A>
  589. inline auto xbuffer_owner_storage<CP, A>::operator=(self_type&& rhs) -> self_type&
  590. {
  591. swap(rhs);
  592. return *this;
  593. }
  594. template <class CP, class A>
  595. inline auto xbuffer_owner_storage<CP, A>::size() const noexcept -> size_type
  596. {
  597. return m_size;
  598. }
  599. template <class CP, class A>
  600. void xbuffer_owner_storage<CP, A>::resize(size_type size)
  601. {
  602. using std::swap;
  603. if (size != m_size)
  604. {
  605. pointer tmp = safe_init_allocate(m_allocator, size);
  606. swap(m_data.get(), tmp);
  607. swap(m_size, size);
  608. safe_destroy_deallocate(m_allocator, tmp, size);
  609. }
  610. }
  611. template <class CP, class A>
  612. inline auto xbuffer_owner_storage<CP, A>::data() noexcept -> pointer
  613. {
  614. return m_data.get();
  615. }
  616. template <class CP, class A>
  617. inline auto xbuffer_owner_storage<CP, A>::data() const noexcept -> const_pointer
  618. {
  619. return m_data.get();
  620. }
  621. template <class CP, class A>
  622. inline auto xbuffer_owner_storage<CP, A>::get_allocator() const noexcept -> allocator_type
  623. {
  624. return allocator_type(m_allocator);
  625. }
  626. template <class CP, class A>
  627. inline void xbuffer_owner_storage<CP, A>::swap(self_type& rhs) noexcept
  628. {
  629. using std::swap;
  630. swap(m_data, rhs.m_data);
  631. swap(m_size, rhs.m_size);
  632. swap(m_allocator, rhs.m_allocator);
  633. }
  634. template <class CP, class A>
  635. template <class P>
  636. inline void
  637. xbuffer_owner_storage<CP, A>::reset_data(P&& data, size_type size, const allocator_type& alloc) noexcept
  638. {
  639. xbuffer_owner_storage<CP, A> tmp(std::forward<P>(data), size, alloc);
  640. this->swap(tmp);
  641. }
  642. }
  643. /****************************************
  644. * xbuffer_smart_pointer implementation *
  645. ****************************************/
  646. namespace detail
  647. {
  648. template <class CP, class D>
  649. template <class P, class DT>
  650. xbuffer_smart_pointer<CP, D>::xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct)
  651. : p_data(data_ptr)
  652. , m_size(size)
  653. , m_destruct(std::forward<DT>(destruct))
  654. {
  655. }
  656. template <class CP, class D>
  657. auto xbuffer_smart_pointer<CP, D>::size() const noexcept -> size_type
  658. {
  659. return m_size;
  660. }
  661. template <class CP, class D>
  662. void xbuffer_smart_pointer<CP, D>::resize(size_type size)
  663. {
  664. if (m_size != size)
  665. {
  666. XTENSOR_THROW(std::runtime_error, "xbuffer_storage not resizeable");
  667. }
  668. }
  669. template <class CP, class D>
  670. auto xbuffer_smart_pointer<CP, D>::data() noexcept -> pointer
  671. {
  672. return p_data;
  673. }
  674. template <class CP, class D>
  675. auto xbuffer_smart_pointer<CP, D>::data() const noexcept -> const_pointer
  676. {
  677. return p_data;
  678. }
  679. template <class CP, class D>
  680. void xbuffer_smart_pointer<CP, D>::swap(self_type& rhs) noexcept
  681. {
  682. using std::swap;
  683. swap(p_data, rhs.p_data);
  684. swap(m_size, rhs.m_size);
  685. swap(m_destruct, rhs.m_destruct);
  686. }
  687. template <class CP, class D>
  688. template <class P, class DT>
  689. void xbuffer_smart_pointer<CP, D>::reset_data(P&& data, size_type size, DT&& destruct) noexcept
  690. {
  691. p_data = std::forward<P>(data);
  692. m_size = size;
  693. m_destruct = destruct;
  694. }
  695. }
  696. /***************************************
  697. * xbuffer_adaptor_base implementation *
  698. ***************************************/
  699. template <class D>
  700. inline bool xbuffer_adaptor_base<D>::empty() const noexcept
  701. {
  702. return derived_cast().size() == size_type(0);
  703. }
  704. template <class D>
  705. inline auto xbuffer_adaptor_base<D>::operator[](size_type i) -> reference
  706. {
  707. return derived_cast().data()[static_cast<index_type>(i)];
  708. }
  709. template <class D>
  710. inline auto xbuffer_adaptor_base<D>::operator[](size_type i) const -> const_reference
  711. {
  712. return derived_cast().data()[static_cast<index_type>(i)];
  713. }
  714. template <class D>
  715. inline auto xbuffer_adaptor_base<D>::front() -> reference
  716. {
  717. return this->operator[](0);
  718. }
  719. template <class D>
  720. inline auto xbuffer_adaptor_base<D>::front() const -> const_reference
  721. {
  722. return this->operator[](0);
  723. }
  724. template <class D>
  725. inline auto xbuffer_adaptor_base<D>::back() -> reference
  726. {
  727. return this->operator[](derived_cast().size() - 1);
  728. }
  729. template <class D>
  730. inline auto xbuffer_adaptor_base<D>::back() const -> const_reference
  731. {
  732. return this->operator[](derived_cast().size() - 1);
  733. }
  734. template <class D>
  735. inline auto xbuffer_adaptor_base<D>::begin() noexcept -> iterator
  736. {
  737. return derived_cast().data();
  738. }
  739. template <class D>
  740. inline auto xbuffer_adaptor_base<D>::end() noexcept -> iterator
  741. {
  742. return derived_cast().data() + static_cast<index_type>(derived_cast().size());
  743. }
  744. template <class D>
  745. inline auto xbuffer_adaptor_base<D>::begin() const noexcept -> const_iterator
  746. {
  747. return derived_cast().data();
  748. }
  749. template <class D>
  750. inline auto xbuffer_adaptor_base<D>::end() const noexcept -> const_iterator
  751. {
  752. return derived_cast().data() + static_cast<index_type>(derived_cast().size());
  753. }
  754. template <class D>
  755. inline auto xbuffer_adaptor_base<D>::cbegin() const noexcept -> const_iterator
  756. {
  757. return begin();
  758. }
  759. template <class D>
  760. inline auto xbuffer_adaptor_base<D>::cend() const noexcept -> const_iterator
  761. {
  762. return end();
  763. }
  764. template <class D>
  765. inline auto xbuffer_adaptor_base<D>::rbegin() noexcept -> reverse_iterator
  766. {
  767. return reverse_iterator(end());
  768. }
  769. template <class D>
  770. inline auto xbuffer_adaptor_base<D>::rend() noexcept -> reverse_iterator
  771. {
  772. return reverse_iterator(begin());
  773. }
  774. template <class D>
  775. inline auto xbuffer_adaptor_base<D>::rbegin() const noexcept -> const_reverse_iterator
  776. {
  777. return const_reverse_iterator(end());
  778. }
  779. template <class D>
  780. inline auto xbuffer_adaptor_base<D>::rend() const noexcept -> const_reverse_iterator
  781. {
  782. return const_reverse_iterator(begin());
  783. }
  784. template <class D>
  785. inline auto xbuffer_adaptor_base<D>::crbegin() const noexcept -> const_reverse_iterator
  786. {
  787. return rbegin();
  788. }
  789. template <class D>
  790. inline auto xbuffer_adaptor_base<D>::crend() const noexcept -> const_reverse_iterator
  791. {
  792. return rend();
  793. }
  794. template <class D>
  795. inline auto xbuffer_adaptor_base<D>::derived_cast() noexcept -> derived_type&
  796. {
  797. return *static_cast<derived_type*>(this);
  798. }
  799. template <class D>
  800. inline auto xbuffer_adaptor_base<D>::derived_cast() const noexcept -> const derived_type&
  801. {
  802. return *static_cast<const derived_type*>(this);
  803. }
  804. template <class D>
  805. inline bool operator==(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
  806. {
  807. return lhs.derived_cast().size() == rhs.derived_cast().size()
  808. && std::equal(lhs.begin(), lhs.end(), rhs.begin());
  809. }
  810. template <class D>
  811. inline bool operator!=(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
  812. {
  813. return !(lhs == rhs);
  814. }
  815. template <class D>
  816. inline bool operator<(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
  817. {
  818. return std::lexicographical_compare(
  819. lhs.begin(),
  820. lhs.end(),
  821. rhs.begin(),
  822. rhs.end(),
  823. std::less<typename D::value_type>()
  824. );
  825. }
  826. template <class D>
  827. inline bool operator<=(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
  828. {
  829. return std::lexicographical_compare(
  830. lhs.begin(),
  831. lhs.end(),
  832. rhs.begin(),
  833. rhs.end(),
  834. std::less_equal<typename D::value_type>()
  835. );
  836. }
  837. template <class D>
  838. inline bool operator>(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
  839. {
  840. return std::lexicographical_compare(
  841. lhs.begin(),
  842. lhs.end(),
  843. rhs.begin(),
  844. rhs.end(),
  845. std::greater<typename D::value_type>()
  846. );
  847. }
  848. template <class D>
  849. inline bool operator>=(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
  850. {
  851. return std::lexicographical_compare(
  852. lhs.begin(),
  853. lhs.end(),
  854. rhs.begin(),
  855. rhs.end(),
  856. std::greater_equal<typename D::value_type>()
  857. );
  858. }
  859. /**********************************
  860. * xbuffer_adaptor implementation *
  861. **********************************/
  862. template <class CP, class O, class A>
  863. inline auto xbuffer_adaptor<CP, O, A>::operator=(temporary_type&& tmp) -> self_type&
  864. {
  865. base_type::resize(tmp.size());
  866. std::copy(tmp.cbegin(), tmp.cend(), this->begin());
  867. return *this;
  868. }
  869. template <class CP, class O, class A>
  870. inline void swap(xbuffer_adaptor<CP, O, A>& lhs, xbuffer_adaptor<CP, O, A>& rhs) noexcept
  871. {
  872. lhs.swap(rhs);
  873. }
  874. /************************************
  875. * xiterator_adaptor implementation *
  876. ************************************/
  877. template <class I, class CI>
  878. inline xiterator_adaptor<I, CI>::xiterator_adaptor(I it, CI cit, size_type size)
  879. : m_it(it)
  880. , m_cit(cit)
  881. , m_size(size)
  882. {
  883. }
  884. template <class I, class CI>
  885. inline auto xiterator_adaptor<I, CI>::operator=(const temporary_type& rhs) -> self_type&
  886. {
  887. resize(rhs.size());
  888. std::copy(rhs.cbegin(), rhs.cend(), m_it);
  889. return *this;
  890. }
  891. template <class I, class CI>
  892. inline auto xiterator_adaptor<I, CI>::operator=(temporary_type&& rhs) -> self_type&
  893. {
  894. return (*this = rhs);
  895. }
  896. template <class I, class CI>
  897. inline auto xiterator_adaptor<I, CI>::size() const noexcept -> size_type
  898. {
  899. return m_size;
  900. }
  901. template <class I, class CI>
  902. inline void xiterator_adaptor<I, CI>::resize(size_type size)
  903. {
  904. if (m_size != size)
  905. {
  906. XTENSOR_THROW(std::runtime_error, "xiterator_adaptor not resizeable");
  907. }
  908. }
  909. template <class I, class CI>
  910. inline auto xiterator_adaptor<I, CI>::data() noexcept -> iterator
  911. {
  912. return m_it;
  913. }
  914. template <class I, class CI>
  915. inline auto xiterator_adaptor<I, CI>::data() const noexcept -> const_iterator
  916. {
  917. return m_cit;
  918. }
  919. template <class I, class CI>
  920. inline void xiterator_adaptor<I, CI>::swap(self_type& rhs) noexcept
  921. {
  922. using std::swap;
  923. swap(m_it, rhs.m_it);
  924. swap(m_cit, rhs.m_cit);
  925. swap(m_size, rhs.m_size);
  926. }
  927. template <class I, class CI>
  928. inline void swap(xiterator_adaptor<I, CI>& lhs, xiterator_adaptor<I, CI>& rhs) noexcept
  929. {
  930. lhs.swap(rhs);
  931. }
  932. /******************************************
  933. * xiterator_owner_adaptor implementation *
  934. ******************************************/
  935. template <class C, class IG>
  936. inline xiterator_owner_adaptor<C, IG>::xiterator_owner_adaptor(C&& c)
  937. : m_container(std::move(c))
  938. {
  939. init_iterators();
  940. }
  941. template <class C, class IG>
  942. inline xiterator_owner_adaptor<C, IG>::xiterator_owner_adaptor(const self_type& rhs)
  943. : m_container(rhs.m_container)
  944. {
  945. init_iterators();
  946. }
  947. template <class C, class IG>
  948. inline xiterator_owner_adaptor<C, IG>& xiterator_owner_adaptor<C, IG>::operator=(const self_type& rhs)
  949. {
  950. m_container = rhs.m_container;
  951. init_iterators();
  952. }
  953. template <class C, class IG>
  954. inline xiterator_owner_adaptor<C, IG>::xiterator_owner_adaptor(self_type&& rhs)
  955. : m_container(std::move(rhs.m_container))
  956. {
  957. init_iterators();
  958. }
  959. template <class C, class IG>
  960. inline xiterator_owner_adaptor<C, IG>& xiterator_owner_adaptor<C, IG>::operator=(self_type&& rhs)
  961. {
  962. m_container = std::move(rhs.m_container);
  963. init_iterators();
  964. }
  965. template <class C, class IG>
  966. inline xiterator_owner_adaptor<C, IG>& xiterator_owner_adaptor<C, IG>::operator=(const temporary_type& rhs)
  967. {
  968. resize(rhs.size());
  969. std::copy(rhs.cbegin(), rhs.cend(), m_it);
  970. return *this;
  971. }
  972. template <class C, class IG>
  973. inline xiterator_owner_adaptor<C, IG>& xiterator_owner_adaptor<C, IG>::operator=(temporary_type&& rhs)
  974. {
  975. return (*this = rhs);
  976. }
  977. template <class C, class IG>
  978. inline auto xiterator_owner_adaptor<C, IG>::size() const noexcept -> size_type
  979. {
  980. return m_size;
  981. }
  982. template <class C, class IG>
  983. inline void xiterator_owner_adaptor<C, IG>::resize(size_type size)
  984. {
  985. if (m_size != size)
  986. {
  987. XTENSOR_THROW(std::runtime_error, "xiterator_owner_adaptor not resizeable");
  988. }
  989. }
  990. template <class C, class IG>
  991. inline auto xiterator_owner_adaptor<C, IG>::data() noexcept -> iterator
  992. {
  993. return m_it;
  994. }
  995. template <class C, class IG>
  996. inline auto xiterator_owner_adaptor<C, IG>::data() const noexcept -> const_iterator
  997. {
  998. return m_cit;
  999. }
  1000. template <class C, class IG>
  1001. inline void xiterator_owner_adaptor<C, IG>::swap(self_type& rhs) noexcept
  1002. {
  1003. using std::swap;
  1004. swap(m_container, rhs.m_container);
  1005. init_iterators();
  1006. rhs.init_iterators();
  1007. }
  1008. template <class C, class IG>
  1009. inline void xiterator_owner_adaptor<C, IG>::init_iterators()
  1010. {
  1011. m_it = IG::begin(m_container);
  1012. m_cit = IG::cbegin(m_container);
  1013. m_size = IG::size(m_container);
  1014. }
  1015. template <class C, class IG>
  1016. inline void swap(xiterator_owner_adaptor<C, IG>& lhs, xiterator_owner_adaptor<C, IG>& rhs) noexcept
  1017. {
  1018. lhs.swap(rhs);
  1019. }
  1020. /*****************************************
  1021. * make_xiterator_adaptor implementation *
  1022. *****************************************/
  1023. namespace detail
  1024. {
  1025. template <class C, class IG, bool = std::is_lvalue_reference<C>::value>
  1026. struct xiterator_adaptor_builder
  1027. {
  1028. using iterator = decltype(IG::begin(std::declval<C>()));
  1029. using const_iterator = decltype(IG::cbegin(std::declval<C>()));
  1030. using type = xiterator_adaptor<iterator, const_iterator>;
  1031. inline static type build(C& c)
  1032. {
  1033. return type(IG::begin(c), IG::cbegin(c), IG::size(c));
  1034. }
  1035. };
  1036. template <class C, class IG>
  1037. struct xiterator_adaptor_builder<C, IG, false>
  1038. {
  1039. using type = xiterator_owner_adaptor<C, IG>;
  1040. inline static type build(C&& c)
  1041. {
  1042. return type(std::move(c));
  1043. }
  1044. };
  1045. }
  1046. template <class C, class IG>
  1047. inline auto make_xiterator_adaptor(C&& container, IG)
  1048. {
  1049. using builder_type = detail::xiterator_adaptor_builder<C, IG>;
  1050. return builder_type::build(std::forward<C>(container));
  1051. }
  1052. }
  1053. #endif