xstorage.hpp 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984
  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_STORAGE_HPP
  10. #define XTENSOR_STORAGE_HPP
  11. #include <algorithm>
  12. #include <cstddef>
  13. #include <functional>
  14. #include <initializer_list>
  15. #include <iterator>
  16. #include <memory>
  17. #include <type_traits>
  18. #include "xexception.hpp"
  19. #include "xtensor_config.hpp"
  20. #include "xtensor_simd.hpp"
  21. #include "xutils.hpp"
  22. namespace xt
  23. {
  24. namespace detail
  25. {
  26. template <class It>
  27. using require_input_iter = typename std::enable_if<
  28. std::is_convertible<typename std::iterator_traits<It>::iterator_category, std::input_iterator_tag>::value>::type;
  29. }
  30. template <class C>
  31. struct is_contiguous_container : std::true_type
  32. {
  33. };
  34. template <class T, class A = std::allocator<T>>
  35. class uvector
  36. {
  37. public:
  38. using allocator_type = A;
  39. using value_type = typename std::allocator_traits<A>::value_type;
  40. using reference = value_type&;
  41. using const_reference = const value_type&;
  42. using pointer = typename std::allocator_traits<A>::pointer;
  43. using const_pointer = typename std::allocator_traits<A>::const_pointer;
  44. using size_type = typename std::allocator_traits<A>::size_type;
  45. using difference_type = typename std::allocator_traits<A>::difference_type;
  46. using iterator = pointer;
  47. using const_iterator = const_pointer;
  48. using reverse_iterator = std::reverse_iterator<iterator>;
  49. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  50. uvector() noexcept;
  51. explicit uvector(const allocator_type& alloc) noexcept;
  52. explicit uvector(size_type count, const allocator_type& alloc = allocator_type());
  53. uvector(size_type count, const_reference value, const allocator_type& alloc = allocator_type());
  54. template <class InputIt, class = detail::require_input_iter<InputIt>>
  55. uvector(InputIt first, InputIt last, const allocator_type& alloc = allocator_type());
  56. uvector(std::initializer_list<T> init, const allocator_type& alloc = allocator_type());
  57. ~uvector();
  58. uvector(const uvector& rhs);
  59. uvector(const uvector& rhs, const allocator_type& alloc);
  60. uvector& operator=(const uvector&);
  61. uvector(uvector&& rhs) noexcept;
  62. uvector(uvector&& rhs, const allocator_type& alloc) noexcept;
  63. uvector& operator=(uvector&& rhs) noexcept;
  64. allocator_type get_allocator() const noexcept;
  65. bool empty() const noexcept;
  66. size_type size() const noexcept;
  67. void resize(size_type size);
  68. size_type max_size() const noexcept;
  69. void reserve(size_type new_cap);
  70. size_type capacity() const noexcept;
  71. void shrink_to_fit();
  72. void clear();
  73. reference operator[](size_type i);
  74. const_reference operator[](size_type i) const;
  75. reference at(size_type i);
  76. const_reference at(size_type i) const;
  77. reference front();
  78. const_reference front() const;
  79. reference back();
  80. const_reference back() const;
  81. pointer data() noexcept;
  82. const_pointer data() const noexcept;
  83. iterator begin() noexcept;
  84. iterator end() noexcept;
  85. const_iterator begin() const noexcept;
  86. const_iterator end() const noexcept;
  87. const_iterator cbegin() const noexcept;
  88. const_iterator cend() const noexcept;
  89. reverse_iterator rbegin() noexcept;
  90. reverse_iterator rend() noexcept;
  91. const_reverse_iterator rbegin() const noexcept;
  92. const_reverse_iterator rend() const noexcept;
  93. const_reverse_iterator crbegin() const noexcept;
  94. const_reverse_iterator crend() const noexcept;
  95. void swap(uvector& rhs) noexcept;
  96. private:
  97. template <class I>
  98. void init_data(I first, I last);
  99. void resize_impl(size_type new_size);
  100. allocator_type m_allocator;
  101. // Storing a pair of pointers is more efficient for iterating than
  102. // storing a pointer to the beginning and the size of the container
  103. pointer p_begin;
  104. pointer p_end;
  105. };
  106. template <class T, class A>
  107. bool operator==(const uvector<T, A>& lhs, const uvector<T, A>& rhs);
  108. template <class T, class A>
  109. bool operator!=(const uvector<T, A>& lhs, const uvector<T, A>& rhs);
  110. template <class T, class A>
  111. bool operator<(const uvector<T, A>& lhs, const uvector<T, A>& rhs);
  112. template <class T, class A>
  113. bool operator<=(const uvector<T, A>& lhs, const uvector<T, A>& rhs);
  114. template <class T, class A>
  115. bool operator>(const uvector<T, A>& lhs, const uvector<T, A>& rhs);
  116. template <class T, class A>
  117. bool operator>=(const uvector<T, A>& lhs, const uvector<T, A>& rhs);
  118. template <class T, class A>
  119. void swap(uvector<T, A>& lhs, uvector<T, A>& rhs) noexcept;
  120. /**************************
  121. * uvector implementation *
  122. **************************/
  123. namespace detail
  124. {
  125. template <class A>
  126. inline typename std::allocator_traits<A>::pointer
  127. safe_init_allocate(A& alloc, typename std::allocator_traits<A>::size_type size)
  128. {
  129. using traits = std::allocator_traits<A>;
  130. using pointer = typename traits::pointer;
  131. using value_type = typename traits::value_type;
  132. pointer res = alloc.allocate(size);
  133. if (!xtrivially_default_constructible<value_type>::value)
  134. {
  135. for (pointer p = res; p != res + size; ++p)
  136. {
  137. traits::construct(alloc, p, value_type());
  138. }
  139. }
  140. return res;
  141. }
  142. template <class A>
  143. inline void safe_destroy_deallocate(
  144. A& alloc,
  145. typename std::allocator_traits<A>::pointer ptr,
  146. typename std::allocator_traits<A>::size_type size
  147. )
  148. {
  149. using traits = std::allocator_traits<A>;
  150. using pointer = typename traits::pointer;
  151. using value_type = typename traits::value_type;
  152. if (ptr != nullptr)
  153. {
  154. if (!xtrivially_default_constructible<value_type>::value)
  155. {
  156. for (pointer p = ptr; p != ptr + size; ++p)
  157. {
  158. traits::destroy(alloc, p);
  159. }
  160. }
  161. traits::deallocate(alloc, ptr, size);
  162. }
  163. }
  164. }
  165. template <class T, class A>
  166. template <class I>
  167. inline void uvector<T, A>::init_data(I first, I last)
  168. {
  169. size_type size = static_cast<size_type>(std::distance(first, last));
  170. if (size != size_type(0))
  171. {
  172. p_begin = m_allocator.allocate(size);
  173. std::uninitialized_copy(first, last, p_begin);
  174. p_end = p_begin + size;
  175. }
  176. }
  177. template <class T, class A>
  178. inline void uvector<T, A>::resize_impl(size_type new_size)
  179. {
  180. size_type old_size = size();
  181. pointer old_begin = p_begin;
  182. if (new_size != old_size)
  183. {
  184. p_begin = detail::safe_init_allocate(m_allocator, new_size);
  185. p_end = p_begin + new_size;
  186. detail::safe_destroy_deallocate(m_allocator, old_begin, old_size);
  187. }
  188. }
  189. template <class T, class A>
  190. inline uvector<T, A>::uvector() noexcept
  191. : uvector(allocator_type())
  192. {
  193. }
  194. template <class T, class A>
  195. inline uvector<T, A>::uvector(const allocator_type& alloc) noexcept
  196. : m_allocator(alloc)
  197. , p_begin(nullptr)
  198. , p_end(nullptr)
  199. {
  200. }
  201. template <class T, class A>
  202. inline uvector<T, A>::uvector(size_type count, const allocator_type& alloc)
  203. : m_allocator(alloc)
  204. , p_begin(nullptr)
  205. , p_end(nullptr)
  206. {
  207. if (count != 0)
  208. {
  209. p_begin = detail::safe_init_allocate(m_allocator, count);
  210. p_end = p_begin + count;
  211. }
  212. }
  213. template <class T, class A>
  214. inline uvector<T, A>::uvector(size_type count, const_reference value, const allocator_type& alloc)
  215. : m_allocator(alloc)
  216. , p_begin(nullptr)
  217. , p_end(nullptr)
  218. {
  219. if (count != 0)
  220. {
  221. p_begin = m_allocator.allocate(count);
  222. p_end = p_begin + count;
  223. std::uninitialized_fill(p_begin, p_end, value);
  224. }
  225. }
  226. template <class T, class A>
  227. template <class InputIt, class>
  228. inline uvector<T, A>::uvector(InputIt first, InputIt last, const allocator_type& alloc)
  229. : m_allocator(alloc)
  230. , p_begin(nullptr)
  231. , p_end(nullptr)
  232. {
  233. init_data(first, last);
  234. }
  235. template <class T, class A>
  236. inline uvector<T, A>::uvector(std::initializer_list<T> init, const allocator_type& alloc)
  237. : m_allocator(alloc)
  238. , p_begin(nullptr)
  239. , p_end(nullptr)
  240. {
  241. init_data(init.begin(), init.end());
  242. }
  243. template <class T, class A>
  244. inline uvector<T, A>::~uvector()
  245. {
  246. detail::safe_destroy_deallocate(m_allocator, p_begin, size());
  247. p_begin = nullptr;
  248. p_end = nullptr;
  249. }
  250. template <class T, class A>
  251. inline uvector<T, A>::uvector(const uvector& rhs)
  252. : m_allocator(
  253. std::allocator_traits<allocator_type>::select_on_container_copy_construction(rhs.get_allocator())
  254. )
  255. , p_begin(nullptr)
  256. , p_end(nullptr)
  257. {
  258. init_data(rhs.p_begin, rhs.p_end);
  259. }
  260. template <class T, class A>
  261. inline uvector<T, A>::uvector(const uvector& rhs, const allocator_type& alloc)
  262. : m_allocator(alloc)
  263. , p_begin(nullptr)
  264. , p_end(nullptr)
  265. {
  266. init_data(rhs.p_begin, rhs.p_end);
  267. }
  268. template <class T, class A>
  269. inline uvector<T, A>& uvector<T, A>::operator=(const uvector& rhs)
  270. {
  271. // No copy and swap idiom here due to performance issues
  272. if (this != &rhs)
  273. {
  274. m_allocator = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
  275. rhs.get_allocator()
  276. );
  277. resize_impl(rhs.size());
  278. if (xtrivially_default_constructible<value_type>::value)
  279. {
  280. std::uninitialized_copy(rhs.p_begin, rhs.p_end, p_begin);
  281. }
  282. else
  283. {
  284. std::copy(rhs.p_begin, rhs.p_end, p_begin);
  285. }
  286. }
  287. return *this;
  288. }
  289. template <class T, class A>
  290. inline uvector<T, A>::uvector(uvector&& rhs) noexcept
  291. : m_allocator(std::move(rhs.m_allocator))
  292. , p_begin(rhs.p_begin)
  293. , p_end(rhs.p_end)
  294. {
  295. rhs.p_begin = nullptr;
  296. rhs.p_end = nullptr;
  297. }
  298. template <class T, class A>
  299. inline uvector<T, A>::uvector(uvector&& rhs, const allocator_type& alloc) noexcept
  300. : m_allocator(alloc)
  301. , p_begin(rhs.p_begin)
  302. , p_end(rhs.p_end)
  303. {
  304. rhs.p_begin = nullptr;
  305. rhs.p_end = nullptr;
  306. }
  307. template <class T, class A>
  308. inline uvector<T, A>& uvector<T, A>::operator=(uvector&& rhs) noexcept
  309. {
  310. using std::swap;
  311. uvector tmp(std::move(rhs));
  312. swap(p_begin, tmp.p_begin);
  313. swap(p_end, tmp.p_end);
  314. return *this;
  315. }
  316. template <class T, class A>
  317. inline auto uvector<T, A>::get_allocator() const noexcept -> allocator_type
  318. {
  319. return allocator_type(m_allocator);
  320. }
  321. template <class T, class A>
  322. inline bool uvector<T, A>::empty() const noexcept
  323. {
  324. return size() == size_type(0);
  325. }
  326. template <class T, class A>
  327. inline auto uvector<T, A>::size() const noexcept -> size_type
  328. {
  329. return static_cast<size_type>(p_end - p_begin);
  330. }
  331. template <class T, class A>
  332. inline void uvector<T, A>::resize(size_type size)
  333. {
  334. resize_impl(size);
  335. }
  336. template <class T, class A>
  337. inline auto uvector<T, A>::max_size() const noexcept -> size_type
  338. {
  339. return m_allocator.max_size();
  340. }
  341. template <class T, class A>
  342. inline void uvector<T, A>::reserve(size_type /*new_cap*/)
  343. {
  344. }
  345. template <class T, class A>
  346. inline auto uvector<T, A>::capacity() const noexcept -> size_type
  347. {
  348. return size();
  349. }
  350. template <class T, class A>
  351. inline void uvector<T, A>::shrink_to_fit()
  352. {
  353. }
  354. template <class T, class A>
  355. inline void uvector<T, A>::clear()
  356. {
  357. resize(size_type(0));
  358. }
  359. template <class T, class A>
  360. inline auto uvector<T, A>::operator[](size_type i) -> reference
  361. {
  362. return p_begin[i];
  363. }
  364. template <class T, class A>
  365. inline auto uvector<T, A>::operator[](size_type i) const -> const_reference
  366. {
  367. return p_begin[i];
  368. }
  369. template <class T, class A>
  370. inline auto uvector<T, A>::at(size_type i) -> reference
  371. {
  372. if (i >= size())
  373. {
  374. XTENSOR_THROW(std::out_of_range, "Out of range in uvector access");
  375. }
  376. return this->operator[](i);
  377. }
  378. template <class T, class A>
  379. inline auto uvector<T, A>::at(size_type i) const -> const_reference
  380. {
  381. if (i >= size())
  382. {
  383. XTENSOR_THROW(std::out_of_range, "Out of range in uvector access");
  384. }
  385. return this->operator[](i);
  386. }
  387. template <class T, class A>
  388. inline auto uvector<T, A>::front() -> reference
  389. {
  390. return p_begin[0];
  391. }
  392. template <class T, class A>
  393. inline auto uvector<T, A>::front() const -> const_reference
  394. {
  395. return p_begin[0];
  396. }
  397. template <class T, class A>
  398. inline auto uvector<T, A>::back() -> reference
  399. {
  400. return *(p_end - 1);
  401. }
  402. template <class T, class A>
  403. inline auto uvector<T, A>::back() const -> const_reference
  404. {
  405. return *(p_end - 1);
  406. }
  407. template <class T, class A>
  408. inline auto uvector<T, A>::data() noexcept -> pointer
  409. {
  410. return p_begin;
  411. }
  412. template <class T, class A>
  413. inline auto uvector<T, A>::data() const noexcept -> const_pointer
  414. {
  415. return p_begin;
  416. }
  417. template <class T, class A>
  418. inline auto uvector<T, A>::begin() noexcept -> iterator
  419. {
  420. return p_begin;
  421. }
  422. template <class T, class A>
  423. inline auto uvector<T, A>::end() noexcept -> iterator
  424. {
  425. return p_end;
  426. }
  427. template <class T, class A>
  428. inline auto uvector<T, A>::begin() const noexcept -> const_iterator
  429. {
  430. return p_begin;
  431. }
  432. template <class T, class A>
  433. inline auto uvector<T, A>::end() const noexcept -> const_iterator
  434. {
  435. return p_end;
  436. }
  437. template <class T, class A>
  438. inline auto uvector<T, A>::cbegin() const noexcept -> const_iterator
  439. {
  440. return begin();
  441. }
  442. template <class T, class A>
  443. inline auto uvector<T, A>::cend() const noexcept -> const_iterator
  444. {
  445. return end();
  446. }
  447. template <class T, class A>
  448. inline auto uvector<T, A>::rbegin() noexcept -> reverse_iterator
  449. {
  450. return reverse_iterator(end());
  451. }
  452. template <class T, class A>
  453. inline auto uvector<T, A>::rend() noexcept -> reverse_iterator
  454. {
  455. return reverse_iterator(begin());
  456. }
  457. template <class T, class A>
  458. inline auto uvector<T, A>::rbegin() const noexcept -> const_reverse_iterator
  459. {
  460. return const_reverse_iterator(end());
  461. }
  462. template <class T, class A>
  463. inline auto uvector<T, A>::rend() const noexcept -> const_reverse_iterator
  464. {
  465. return const_reverse_iterator(begin());
  466. }
  467. template <class T, class A>
  468. inline auto uvector<T, A>::crbegin() const noexcept -> const_reverse_iterator
  469. {
  470. return rbegin();
  471. }
  472. template <class T, class A>
  473. inline auto uvector<T, A>::crend() const noexcept -> const_reverse_iterator
  474. {
  475. return rend();
  476. }
  477. template <class T, class A>
  478. inline void uvector<T, A>::swap(uvector<T, A>& rhs) noexcept
  479. {
  480. using std::swap;
  481. swap(m_allocator, rhs.m_allocator);
  482. swap(p_begin, rhs.p_begin);
  483. swap(p_end, rhs.p_end);
  484. }
  485. template <class T, class A>
  486. inline bool operator==(const uvector<T, A>& lhs, const uvector<T, A>& rhs)
  487. {
  488. return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
  489. }
  490. template <class T, class A>
  491. inline bool operator!=(const uvector<T, A>& lhs, const uvector<T, A>& rhs)
  492. {
  493. return !(lhs == rhs);
  494. }
  495. template <class T, class A>
  496. inline bool operator<(const uvector<T, A>& lhs, const uvector<T, A>& rhs)
  497. {
  498. return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  499. }
  500. template <class T, class A>
  501. inline bool operator<=(const uvector<T, A>& lhs, const uvector<T, A>& rhs)
  502. {
  503. return !(lhs > rhs);
  504. }
  505. template <class T, class A>
  506. inline bool operator>(const uvector<T, A>& lhs, const uvector<T, A>& rhs)
  507. {
  508. return rhs < lhs;
  509. }
  510. template <class T, class A>
  511. inline bool operator>=(const uvector<T, A>& lhs, const uvector<T, A>& rhs)
  512. {
  513. return !(lhs < rhs);
  514. }
  515. template <class T, class A>
  516. inline void swap(uvector<T, A>& lhs, uvector<T, A>& rhs) noexcept
  517. {
  518. lhs.swap(rhs);
  519. }
  520. /**************************
  521. * svector implementation *
  522. **************************/
  523. namespace detail
  524. {
  525. template <class T>
  526. struct allocator_alignment
  527. {
  528. static constexpr std::size_t value = 0;
  529. };
  530. template <class T, std::size_t A>
  531. struct allocator_alignment<xt_simd::aligned_allocator<T, A>>
  532. {
  533. static constexpr std::size_t value = A;
  534. };
  535. }
  536. template <class T, std::size_t N = 4, class A = std::allocator<T>, bool Init = true>
  537. class svector
  538. {
  539. public:
  540. using self_type = svector<T, N, A, Init>;
  541. using allocator_type = A;
  542. using size_type = typename std::allocator_traits<A>::size_type;
  543. using value_type = typename std::allocator_traits<A>::value_type;
  544. using pointer = typename std::allocator_traits<A>::pointer;
  545. using const_pointer = typename std::allocator_traits<A>::const_pointer;
  546. using reference = value_type&;
  547. using const_reference = const value_type&;
  548. using difference_type = typename std::allocator_traits<A>::difference_type;
  549. using iterator = pointer;
  550. using const_iterator = const_pointer;
  551. using reverse_iterator = std::reverse_iterator<iterator>;
  552. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  553. #if defined(_MSC_VER) && _MSC_VER < 1910
  554. static constexpr std::size_t alignment = detail::allocator_alignment<A>::value;
  555. #else
  556. static constexpr std::size_t alignment = detail::allocator_alignment<A>::value != 0
  557. ? detail::allocator_alignment<A>::value
  558. : alignof(T);
  559. #endif
  560. svector() noexcept;
  561. ~svector();
  562. explicit svector(const allocator_type& alloc) noexcept;
  563. explicit svector(size_type n, const allocator_type& alloc = allocator_type());
  564. svector(size_type n, const value_type& v, const allocator_type& alloc = allocator_type());
  565. svector(std::initializer_list<T> il, const allocator_type& alloc = allocator_type());
  566. svector(const std::vector<T>& vec);
  567. template <class IT, class = detail::require_input_iter<IT>>
  568. svector(IT begin, IT end, const allocator_type& alloc = allocator_type());
  569. template <std::size_t N2, bool I2, class = std::enable_if_t<N != N2, void>>
  570. explicit svector(const svector<T, N2, A, I2>& rhs);
  571. svector& operator=(const svector& rhs);
  572. svector& operator=(svector&& rhs) noexcept(std::is_nothrow_move_assignable<value_type>::value);
  573. svector& operator=(const std::vector<T>& rhs);
  574. svector& operator=(std::initializer_list<T> il);
  575. template <std::size_t N2, bool I2, class = std::enable_if_t<N != N2, void>>
  576. svector& operator=(const svector<T, N2, A, I2>& rhs);
  577. svector(const svector& other);
  578. svector(svector&& other) noexcept(std::is_nothrow_move_constructible<value_type>::value);
  579. void assign(size_type n, const value_type& v);
  580. template <class V>
  581. void assign(std::initializer_list<V> il);
  582. template <class IT>
  583. void assign(IT other_begin, IT other_end);
  584. reference operator[](size_type idx);
  585. const_reference operator[](size_type idx) const;
  586. reference at(size_type idx);
  587. const_reference at(size_type idx) const;
  588. pointer data();
  589. const_pointer data() const;
  590. void push_back(const T& elt);
  591. void push_back(T&& elt);
  592. void pop_back();
  593. iterator begin();
  594. const_iterator begin() const;
  595. const_iterator cbegin() const;
  596. iterator end();
  597. const_iterator end() const;
  598. const_iterator cend() const;
  599. reverse_iterator rbegin();
  600. const_reverse_iterator rbegin() const;
  601. const_reverse_iterator crbegin() const;
  602. reverse_iterator rend();
  603. const_reverse_iterator rend() const;
  604. const_reverse_iterator crend() const;
  605. bool empty() const;
  606. size_type size() const;
  607. void resize(size_type n);
  608. size_type max_size() const noexcept;
  609. size_type capacity() const;
  610. void reserve(size_type n);
  611. void shrink_to_fit();
  612. void clear();
  613. reference front();
  614. const_reference front() const;
  615. reference back();
  616. const_reference back() const;
  617. bool on_stack();
  618. iterator erase(const_iterator cit);
  619. iterator erase(const_iterator cfirst, const_iterator clast);
  620. iterator insert(const_iterator it, const T& elt);
  621. template <class It>
  622. iterator insert(const_iterator pos, It first, It last);
  623. iterator insert(const_iterator pos, std::initializer_list<T> l);
  624. template <std::size_t ON, class OA, bool InitA>
  625. void swap(svector<T, ON, OA, InitA>& rhs);
  626. allocator_type get_allocator() const noexcept;
  627. private:
  628. A m_allocator;
  629. T* m_begin = std::begin(m_data);
  630. T* m_end = std::begin(m_data);
  631. T* m_capacity = std::end(m_data);
  632. // stack allocated memory
  633. alignas(alignment) T m_data[N > 0 ? N : 1];
  634. void grow(size_type min_capacity = 0);
  635. void destroy_range(T* begin, T* end);
  636. };
  637. template <class T, std::size_t N, class A, bool Init>
  638. inline svector<T, N, A, Init>::~svector()
  639. {
  640. if (!on_stack())
  641. {
  642. detail::safe_destroy_deallocate(m_allocator, m_begin, static_cast<std::size_t>(m_capacity - m_begin));
  643. }
  644. }
  645. template <class T, std::size_t N, class A, bool Init>
  646. inline svector<T, N, A, Init>::svector() noexcept
  647. : svector(allocator_type())
  648. {
  649. }
  650. template <class T, std::size_t N, class A, bool Init>
  651. inline svector<T, N, A, Init>::svector(const allocator_type& alloc) noexcept
  652. : m_allocator(alloc)
  653. {
  654. }
  655. template <class T, std::size_t N, class A, bool Init>
  656. inline svector<T, N, A, Init>::svector(size_type n, const allocator_type& alloc)
  657. : m_allocator(alloc)
  658. {
  659. if (Init)
  660. {
  661. assign(n, T(0));
  662. }
  663. else
  664. {
  665. resize(n);
  666. }
  667. }
  668. template <class T, std::size_t N, class A, bool Init>
  669. template <class IT, class>
  670. inline svector<T, N, A, Init>::svector(IT begin, IT end, const allocator_type& alloc)
  671. : m_allocator(alloc)
  672. {
  673. assign(begin, end);
  674. }
  675. template <class T, std::size_t N, class A, bool Init>
  676. template <std::size_t N2, bool I2, class>
  677. inline svector<T, N, A, Init>::svector(const svector<T, N2, A, I2>& rhs)
  678. : m_allocator(rhs.get_allocator())
  679. {
  680. assign(rhs.begin(), rhs.end());
  681. }
  682. template <class T, std::size_t N, class A, bool Init>
  683. inline svector<T, N, A, Init>::svector(const std::vector<T>& vec)
  684. {
  685. assign(vec.begin(), vec.end());
  686. }
  687. template <class T, std::size_t N, class A, bool Init>
  688. inline svector<T, N, A, Init>::svector(size_type n, const value_type& v, const allocator_type& alloc)
  689. : m_allocator(alloc)
  690. {
  691. assign(n, v);
  692. }
  693. template <class T, std::size_t N, class A, bool Init>
  694. inline svector<T, N, A, Init>::svector(std::initializer_list<T> il, const allocator_type& alloc)
  695. : m_allocator(alloc)
  696. {
  697. assign(il.begin(), il.end());
  698. }
  699. template <class T, std::size_t N, class A, bool Init>
  700. inline svector<T, N, A, Init>& svector<T, N, A, Init>::operator=(const svector& rhs)
  701. {
  702. assign(rhs.begin(), rhs.end());
  703. return *this;
  704. }
  705. template <class T, std::size_t N, class A, bool Init>
  706. inline svector<T, N, A, Init>& svector<T, N, A, Init>::operator=(svector&& rhs
  707. ) noexcept(std::is_nothrow_move_assignable<value_type>::value)
  708. {
  709. assign(rhs.begin(), rhs.end());
  710. return *this;
  711. }
  712. template <class T, std::size_t N, class A, bool Init>
  713. inline svector<T, N, A, Init>& svector<T, N, A, Init>::operator=(const std::vector<T>& rhs)
  714. {
  715. m_allocator = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
  716. rhs.get_allocator()
  717. );
  718. assign(rhs.begin(), rhs.end());
  719. return *this;
  720. }
  721. template <class T, std::size_t N, class A, bool Init>
  722. inline svector<T, N, A, Init>& svector<T, N, A, Init>::operator=(std::initializer_list<T> il)
  723. {
  724. return operator=(self_type(il));
  725. }
  726. template <class T, std::size_t N, class A, bool Init>
  727. template <std::size_t N2, bool I2, class>
  728. inline svector<T, N, A, Init>& svector<T, N, A, Init>::operator=(const svector<T, N2, A, I2>& rhs)
  729. {
  730. m_allocator = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
  731. rhs.get_allocator()
  732. );
  733. assign(rhs.begin(), rhs.end());
  734. return *this;
  735. }
  736. template <class T, std::size_t N, class A, bool Init>
  737. inline svector<T, N, A, Init>::svector(const svector& rhs)
  738. : m_allocator(
  739. std::allocator_traits<allocator_type>::select_on_container_copy_construction(rhs.get_allocator())
  740. )
  741. {
  742. assign(rhs.begin(), rhs.end());
  743. }
  744. template <class T, std::size_t N, class A, bool Init>
  745. inline svector<T, N, A, Init>::svector(svector&& rhs
  746. ) noexcept(std::is_nothrow_move_constructible<value_type>::value)
  747. {
  748. this->swap(rhs);
  749. }
  750. template <class T, std::size_t N, class A, bool Init>
  751. inline void svector<T, N, A, Init>::assign(size_type n, const value_type& v)
  752. {
  753. if (n > N && n > capacity())
  754. {
  755. grow(n);
  756. }
  757. m_end = m_begin + n;
  758. std::fill(begin(), end(), v);
  759. }
  760. template <class T, std::size_t N, class A, bool Init>
  761. template <class V>
  762. inline void svector<T, N, A, Init>::assign(std::initializer_list<V> il)
  763. {
  764. assign(il.begin(), il.end());
  765. }
  766. template <class T, std::size_t N, class A, bool Init>
  767. template <class IT>
  768. inline void svector<T, N, A, Init>::assign(IT other_begin, IT other_end)
  769. {
  770. std::size_t size = static_cast<std::size_t>(other_end - other_begin);
  771. if (size > N && size > capacity())
  772. {
  773. grow(size);
  774. }
  775. std::uninitialized_copy(other_begin, other_end, m_begin);
  776. m_end = m_begin + size;
  777. }
  778. template <class T, std::size_t N, class A, bool Init>
  779. inline auto svector<T, N, A, Init>::operator[](size_type idx) -> reference
  780. {
  781. return m_begin[idx];
  782. }
  783. template <class T, std::size_t N, class A, bool Init>
  784. inline auto svector<T, N, A, Init>::operator[](size_type idx) const -> const_reference
  785. {
  786. return m_begin[idx];
  787. }
  788. template <class T, std::size_t N, class A, bool Init>
  789. inline auto svector<T, N, A, Init>::at(size_type idx) -> reference
  790. {
  791. if (idx >= size())
  792. {
  793. XTENSOR_THROW(std::out_of_range, "Out of range in svector access");
  794. }
  795. return this->operator[](idx);
  796. }
  797. template <class T, std::size_t N, class A, bool Init>
  798. inline auto svector<T, N, A, Init>::at(size_type idx) const -> const_reference
  799. {
  800. if (idx >= size())
  801. {
  802. XTENSOR_THROW(std::out_of_range, "Out of range in svector access");
  803. }
  804. return this->operator[](idx);
  805. }
  806. template <class T, std::size_t N, class A, bool Init>
  807. inline auto svector<T, N, A, Init>::data() -> pointer
  808. {
  809. return m_begin;
  810. }
  811. template <class T, std::size_t N, class A, bool Init>
  812. inline auto svector<T, N, A, Init>::data() const -> const_pointer
  813. {
  814. return m_begin;
  815. }
  816. template <class T, std::size_t N, class A, bool Init>
  817. void svector<T, N, A, Init>::resize(size_type n)
  818. {
  819. if (n > N && n > capacity())
  820. {
  821. grow(n);
  822. }
  823. size_type old_size = size();
  824. m_end = m_begin + n;
  825. if (Init && old_size < size())
  826. {
  827. std::fill(begin() + old_size, end(), T());
  828. }
  829. }
  830. template <class T, std::size_t N, class A, bool Init>
  831. inline auto svector<T, N, A, Init>::max_size() const noexcept -> size_type
  832. {
  833. return m_allocator.max_size();
  834. }
  835. template <class T, std::size_t N, class A, bool Init>
  836. inline auto svector<T, N, A, Init>::capacity() const -> size_type
  837. {
  838. return static_cast<std::size_t>(m_capacity - m_begin);
  839. }
  840. template <class T, std::size_t N, class A, bool Init>
  841. inline void svector<T, N, A, Init>::reserve(size_type n)
  842. {
  843. if (n > N && n > capacity())
  844. {
  845. grow(n);
  846. }
  847. }
  848. template <class T, std::size_t N, class A, bool Init>
  849. inline void svector<T, N, A, Init>::shrink_to_fit()
  850. {
  851. // No op for now
  852. }
  853. template <class T, std::size_t N, class A, bool Init>
  854. inline void svector<T, N, A, Init>::clear()
  855. {
  856. resize(size_type(0));
  857. }
  858. template <class T, std::size_t N, class A, bool Init>
  859. void svector<T, N, A, Init>::push_back(const T& elt)
  860. {
  861. if (m_end >= m_capacity)
  862. {
  863. grow();
  864. }
  865. *(m_end++) = elt;
  866. }
  867. template <class T, std::size_t N, class A, bool Init>
  868. void svector<T, N, A, Init>::push_back(T&& elt)
  869. {
  870. if (m_end >= m_capacity)
  871. {
  872. grow();
  873. }
  874. *(m_end++) = std::move(elt);
  875. }
  876. template <class T, std::size_t N, class A, bool Init>
  877. void svector<T, N, A, Init>::pop_back()
  878. {
  879. --m_end;
  880. }
  881. template <class T, std::size_t N, class A, bool Init>
  882. inline auto svector<T, N, A, Init>::begin() -> iterator
  883. {
  884. return m_begin;
  885. }
  886. template <class T, std::size_t N, class A, bool Init>
  887. inline auto svector<T, N, A, Init>::begin() const -> const_iterator
  888. {
  889. return m_begin;
  890. }
  891. template <class T, std::size_t N, class A, bool Init>
  892. inline auto svector<T, N, A, Init>::cbegin() const -> const_iterator
  893. {
  894. return m_begin;
  895. }
  896. template <class T, std::size_t N, class A, bool Init>
  897. inline auto svector<T, N, A, Init>::end() -> iterator
  898. {
  899. return m_end;
  900. }
  901. template <class T, std::size_t N, class A, bool Init>
  902. inline auto svector<T, N, A, Init>::end() const -> const_iterator
  903. {
  904. return m_end;
  905. }
  906. template <class T, std::size_t N, class A, bool Init>
  907. inline auto svector<T, N, A, Init>::cend() const -> const_iterator
  908. {
  909. return m_end;
  910. }
  911. template <class T, std::size_t N, class A, bool Init>
  912. inline auto svector<T, N, A, Init>::rbegin() -> reverse_iterator
  913. {
  914. return reverse_iterator(m_end);
  915. }
  916. template <class T, std::size_t N, class A, bool Init>
  917. inline auto svector<T, N, A, Init>::rbegin() const -> const_reverse_iterator
  918. {
  919. return const_reverse_iterator(m_end);
  920. }
  921. template <class T, std::size_t N, class A, bool Init>
  922. inline auto svector<T, N, A, Init>::crbegin() const -> const_reverse_iterator
  923. {
  924. return const_reverse_iterator(m_end);
  925. }
  926. template <class T, std::size_t N, class A, bool Init>
  927. inline auto svector<T, N, A, Init>::rend() -> reverse_iterator
  928. {
  929. return reverse_iterator(m_begin);
  930. }
  931. template <class T, std::size_t N, class A, bool Init>
  932. inline auto svector<T, N, A, Init>::rend() const -> const_reverse_iterator
  933. {
  934. return const_reverse_iterator(m_begin);
  935. }
  936. template <class T, std::size_t N, class A, bool Init>
  937. inline auto svector<T, N, A, Init>::crend() const -> const_reverse_iterator
  938. {
  939. return const_reverse_iterator(m_begin);
  940. }
  941. template <class T, std::size_t N, class A, bool Init>
  942. inline auto svector<T, N, A, Init>::size() const -> size_type
  943. {
  944. return static_cast<size_type>(m_end - m_begin);
  945. }
  946. template <class T, std::size_t N, class A, bool Init>
  947. inline auto svector<T, N, A, Init>::empty() const -> bool
  948. {
  949. return m_begin == m_end;
  950. }
  951. template <class T, std::size_t N, class A, bool Init>
  952. inline auto svector<T, N, A, Init>::front() -> reference
  953. {
  954. XTENSOR_ASSERT(!empty());
  955. return m_begin[0];
  956. }
  957. template <class T, std::size_t N, class A, bool Init>
  958. inline auto svector<T, N, A, Init>::front() const -> const_reference
  959. {
  960. XTENSOR_ASSERT(!empty());
  961. return m_begin[0];
  962. }
  963. template <class T, std::size_t N, class A, bool Init>
  964. inline auto svector<T, N, A, Init>::back() -> reference
  965. {
  966. XTENSOR_ASSERT(!empty());
  967. return m_end[-1];
  968. }
  969. template <class T, std::size_t N, class A, bool Init>
  970. inline auto svector<T, N, A, Init>::back() const -> const_reference
  971. {
  972. XTENSOR_ASSERT(!empty());
  973. return m_end[-1];
  974. }
  975. template <class T, std::size_t N, class A, bool Init>
  976. inline auto svector<T, N, A, Init>::on_stack() -> bool
  977. {
  978. return m_begin == &m_data[0];
  979. }
  980. template <class T, std::size_t N, class A, bool Init>
  981. inline auto svector<T, N, A, Init>::get_allocator() const noexcept -> allocator_type
  982. {
  983. return m_allocator;
  984. }
  985. template <class T, std::size_t N, class A, bool Init>
  986. inline auto svector<T, N, A, Init>::erase(const_iterator cit) -> iterator
  987. {
  988. auto it = const_cast<pointer>(cit);
  989. iterator ret_val = it;
  990. std::move(it + 1, m_end, it);
  991. --m_end;
  992. return ret_val;
  993. }
  994. template <class T, std::size_t N, class A, bool Init>
  995. inline auto svector<T, N, A, Init>::erase(const_iterator cfirst, const_iterator clast) -> iterator
  996. {
  997. auto first = const_cast<pointer>(cfirst);
  998. auto last = const_cast<pointer>(clast);
  999. if (last == m_end)
  1000. {
  1001. m_end = first;
  1002. return first;
  1003. }
  1004. iterator new_end = std::move(last, m_end, first);
  1005. m_end = new_end;
  1006. return first;
  1007. }
  1008. template <class T, std::size_t N, class A, bool Init>
  1009. inline auto svector<T, N, A, Init>::insert(const_iterator cit, const T& elt) -> iterator
  1010. {
  1011. auto it = const_cast<pointer>(cit);
  1012. if (it == m_end)
  1013. {
  1014. push_back(elt);
  1015. return m_end - 1;
  1016. }
  1017. if (m_end >= m_capacity)
  1018. {
  1019. std::ptrdiff_t elt_no = it - m_begin;
  1020. grow();
  1021. it = m_begin + elt_no;
  1022. }
  1023. (*m_end) = back();
  1024. std::move_backward(it, m_end - 1, m_end);
  1025. ++m_end;
  1026. // Update ref if element moved
  1027. const T* elt_ptr = &elt;
  1028. bool cond = it <= elt_ptr && elt_ptr < m_end;
  1029. // More complicated than incrementing elt_ptr, but this avoids
  1030. // false positive array-bounds warning on GCC 10
  1031. const T* src_ptr = cond ? it + (elt_ptr - it) + std::ptrdiff_t(1) : elt_ptr;
  1032. *it = *src_ptr;
  1033. return it;
  1034. }
  1035. template <class T, std::size_t N, class A, bool Init>
  1036. template <class It>
  1037. inline auto svector<T, N, A, Init>::insert(const_iterator pos, It first, It last) -> iterator
  1038. {
  1039. auto it = const_cast<pointer>(pos);
  1040. difference_type n = std::distance(first, last);
  1041. if (n > 0)
  1042. {
  1043. if (n > m_capacity - m_end)
  1044. {
  1045. std::ptrdiff_t elt_no = it - m_begin;
  1046. grow(static_cast<size_t>((m_capacity - m_begin) + n));
  1047. it = m_begin + elt_no;
  1048. }
  1049. std::move_backward(it, m_end, m_end + n);
  1050. m_end += n;
  1051. std::copy(first, last, it);
  1052. }
  1053. return it;
  1054. }
  1055. template <class T, std::size_t N, class A, bool Init>
  1056. inline auto svector<T, N, A, Init>::insert(const_iterator pos, std::initializer_list<T> l) -> iterator
  1057. {
  1058. return insert(pos, l.begin(), l.end());
  1059. }
  1060. template <class T, std::size_t N, class A, bool Init>
  1061. inline void svector<T, N, A, Init>::destroy_range(T* begin, T* end)
  1062. {
  1063. if (!xtrivially_default_constructible<T>::value)
  1064. {
  1065. while (begin != end)
  1066. {
  1067. --end;
  1068. end->~T();
  1069. }
  1070. }
  1071. }
  1072. template <class T, std::size_t N, class A, bool Init>
  1073. template <std::size_t ON, class OA, bool InitA>
  1074. inline void svector<T, N, A, Init>::swap(svector<T, ON, OA, InitA>& rhs)
  1075. {
  1076. using std::swap;
  1077. if (this == &rhs)
  1078. {
  1079. return;
  1080. }
  1081. // We can only avoid copying elements if neither vector is small.
  1082. if (!this->on_stack() && !rhs.on_stack())
  1083. {
  1084. swap(this->m_begin, rhs.m_begin);
  1085. swap(this->m_end, rhs.m_end);
  1086. swap(this->m_capacity, rhs.m_capacity);
  1087. return;
  1088. }
  1089. size_type rhs_old_size = rhs.size();
  1090. size_type old_size = this->size();
  1091. if (rhs_old_size > old_size)
  1092. {
  1093. this->resize(rhs_old_size);
  1094. }
  1095. else if (old_size > rhs_old_size)
  1096. {
  1097. rhs.resize(old_size);
  1098. }
  1099. // Swap the shared elements.
  1100. size_type min_size = (std::min)(old_size, rhs_old_size);
  1101. for (size_type i = 0; i < min_size; ++i)
  1102. {
  1103. swap((*this)[i], rhs[i]);
  1104. }
  1105. // Copy over the extra elts.
  1106. if (old_size > rhs_old_size)
  1107. {
  1108. std::copy(this->begin() + min_size, this->end(), rhs.begin() + min_size);
  1109. this->destroy_range(this->begin() + min_size, this->end());
  1110. this->m_end = this->begin() + min_size;
  1111. }
  1112. else if (rhs_old_size > old_size)
  1113. {
  1114. std::copy(rhs.begin() + min_size, rhs.end(), this->begin() + min_size);
  1115. this->destroy_range(rhs.begin() + min_size, rhs.end());
  1116. rhs.m_end = rhs.begin() + min_size;
  1117. }
  1118. }
  1119. template <class T, std::size_t N, class A, bool Init>
  1120. inline void svector<T, N, A, Init>::grow(size_type min_capacity)
  1121. {
  1122. size_type current_size = size();
  1123. size_type new_capacity = 2 * current_size + 1; // Always grow.
  1124. if (new_capacity < min_capacity)
  1125. {
  1126. new_capacity = min_capacity;
  1127. }
  1128. T* new_alloc;
  1129. // is data stack allocated?
  1130. if (m_begin == &m_data[0])
  1131. {
  1132. new_alloc = m_allocator.allocate(new_capacity);
  1133. std::uninitialized_copy(m_begin, m_end, new_alloc);
  1134. }
  1135. else
  1136. {
  1137. // If this wasn't grown from the inline copy, grow the allocated space.
  1138. new_alloc = m_allocator.allocate(new_capacity);
  1139. std::uninitialized_copy(m_begin, m_end, new_alloc);
  1140. m_allocator.deallocate(m_begin, std::size_t(m_capacity - m_begin));
  1141. }
  1142. XTENSOR_ASSERT(new_alloc);
  1143. m_end = new_alloc + current_size;
  1144. m_begin = new_alloc;
  1145. m_capacity = new_alloc + new_capacity;
  1146. }
  1147. template <class T, std::size_t N, class A, bool Init>
  1148. inline bool operator==(const std::vector<T>& lhs, const svector<T, N, A, Init>& rhs)
  1149. {
  1150. return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
  1151. }
  1152. template <class T, std::size_t N, class A, bool Init>
  1153. inline bool operator==(const svector<T, N, A, Init>& lhs, const std::vector<T>& rhs)
  1154. {
  1155. return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
  1156. }
  1157. template <class T, std::size_t N, class A, bool Init>
  1158. inline bool operator==(const svector<T, N, A, Init>& lhs, const svector<T, N, A, Init>& rhs)
  1159. {
  1160. return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
  1161. }
  1162. template <class T, std::size_t N, class A, bool Init>
  1163. inline bool operator!=(const svector<T, N, A, Init>& lhs, const svector<T, N, A, Init>& rhs)
  1164. {
  1165. return !(lhs == rhs);
  1166. }
  1167. template <class T, std::size_t N, class A, bool Init>
  1168. inline bool operator<(const svector<T, N, A, Init>& lhs, const svector<T, N, A, Init>& rhs)
  1169. {
  1170. return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  1171. }
  1172. template <class T, std::size_t N, class A, bool Init>
  1173. inline bool operator<=(const svector<T, N, A, Init>& lhs, const svector<T, N, A, Init>& rhs)
  1174. {
  1175. return !(lhs > rhs);
  1176. }
  1177. template <class T, std::size_t N, class A, bool Init>
  1178. inline bool operator>(const svector<T, N, A, Init>& lhs, const svector<T, N, A, Init>& rhs)
  1179. {
  1180. return rhs < lhs;
  1181. }
  1182. template <class T, std::size_t N, class A, bool Init>
  1183. inline bool operator>=(const svector<T, N, A, Init>& lhs, const svector<T, N, A, Init>& rhs)
  1184. {
  1185. return !(lhs < rhs);
  1186. }
  1187. template <class T, std::size_t N, class A, bool Init>
  1188. inline void swap(svector<T, N, A, Init>& lhs, svector<T, N, A, Init>& rhs) noexcept
  1189. {
  1190. lhs.swap(rhs);
  1191. }
  1192. template <class X, class T, std::size_t N, class A, bool B>
  1193. struct rebind_container<X, svector<T, N, A, B>>
  1194. {
  1195. using traits = std::allocator_traits<A>;
  1196. using allocator = typename traits::template rebind_alloc<X>;
  1197. using type = svector<X, N, allocator, B>;
  1198. };
  1199. /**
  1200. * This array class is modeled after ``std::array`` but adds optional alignment through a template
  1201. * parameter.
  1202. *
  1203. * To be moved to xtl, along with the rest of xstorage.hpp
  1204. */
  1205. template <class T, std::size_t N, std::size_t Align = XTENSOR_SELECT_ALIGN(T)>
  1206. class alignas(Align) aligned_array : public std::array<T, N>
  1207. {
  1208. public:
  1209. // Note: this is for alignment detection. The allocator serves no other purpose than
  1210. // that of a trait here.
  1211. using allocator_type = std::conditional_t<Align != 0, xt_simd::aligned_allocator<T, Align>, std::allocator<T>>;
  1212. };
  1213. #if defined(_MSC_VER)
  1214. #define XTENSOR_CONST
  1215. #else
  1216. #define XTENSOR_CONST const
  1217. #endif
  1218. #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
  1219. #define GCC4_FALLBACK
  1220. namespace const_array_detail
  1221. {
  1222. template <class T, std::size_t N>
  1223. struct array_traits
  1224. {
  1225. using storage_type = T[N];
  1226. static constexpr T& ref(const storage_type& t, std::size_t n) noexcept
  1227. {
  1228. return const_cast<T&>(t[n]);
  1229. }
  1230. static constexpr T* ptr(const storage_type& t) noexcept
  1231. {
  1232. return const_cast<T*>(t);
  1233. }
  1234. };
  1235. template <class T>
  1236. struct array_traits<T, 0>
  1237. {
  1238. struct empty
  1239. {
  1240. };
  1241. using storage_type = empty;
  1242. static constexpr T& ref(const storage_type& /*t*/, std::size_t /*n*/) noexcept
  1243. {
  1244. return *static_cast<T*>(nullptr);
  1245. }
  1246. static constexpr T* ptr(const storage_type& /*t*/) noexcept
  1247. {
  1248. return nullptr;
  1249. }
  1250. };
  1251. }
  1252. #endif
  1253. /**
  1254. * A std::array like class with all member function (except reverse iterators)
  1255. * as constexpr. The data is immutable once set.
  1256. */
  1257. template <class T, std::size_t N>
  1258. struct const_array
  1259. {
  1260. using size_type = std::size_t;
  1261. using value_type = T;
  1262. using pointer = value_type*;
  1263. using const_pointer = const value_type*;
  1264. using reference = value_type&;
  1265. using const_reference = const value_type&;
  1266. using difference_type = std::ptrdiff_t;
  1267. using iterator = pointer;
  1268. using const_iterator = const_pointer;
  1269. using reverse_iterator = std::reverse_iterator<const_iterator>;
  1270. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  1271. constexpr const_reference operator[](std::size_t idx) const
  1272. {
  1273. #ifdef GCC4_FALLBACK
  1274. return const_array_detail::array_traits<T, N>::ref(m_data, idx);
  1275. #else
  1276. return m_data[idx];
  1277. #endif
  1278. }
  1279. constexpr const_iterator begin() const noexcept
  1280. {
  1281. return cbegin();
  1282. }
  1283. constexpr const_iterator end() const noexcept
  1284. {
  1285. return cend();
  1286. }
  1287. constexpr const_iterator cbegin() const noexcept
  1288. {
  1289. return data();
  1290. }
  1291. constexpr const_iterator cend() const noexcept
  1292. {
  1293. return data() + N;
  1294. }
  1295. // TODO make constexpr once C++17 arrives
  1296. reverse_iterator rbegin() const noexcept
  1297. {
  1298. return crbegin();
  1299. }
  1300. reverse_iterator rend() const noexcept
  1301. {
  1302. return crend();
  1303. }
  1304. const_reverse_iterator crbegin() const noexcept
  1305. {
  1306. return const_reverse_iterator(end());
  1307. }
  1308. const_reverse_iterator crend() const noexcept
  1309. {
  1310. return const_reverse_iterator(begin());
  1311. }
  1312. constexpr const_pointer data() const noexcept
  1313. {
  1314. #ifdef GCC4_FALLBACK
  1315. return const_array_detail::array_traits<T, N>::ptr(m_data);
  1316. #else
  1317. return m_data;
  1318. #endif
  1319. }
  1320. constexpr const_reference front() const noexcept
  1321. {
  1322. #ifdef GCC4_FALLBACK
  1323. return const_array_detail::array_traits<T, N>::ref(m_data, 0);
  1324. #else
  1325. return m_data[0];
  1326. #endif
  1327. }
  1328. constexpr const_reference back() const noexcept
  1329. {
  1330. #ifdef GCC4_FALLBACK
  1331. return N ? const_array_detail::array_traits<T, N>::ref(m_data, N - 1)
  1332. : const_array_detail::array_traits<T, N>::ref(m_data, 0);
  1333. #else
  1334. return m_data[size() - 1];
  1335. #endif
  1336. }
  1337. constexpr bool empty() const noexcept
  1338. {
  1339. return size() == size_type(0);
  1340. }
  1341. constexpr size_type size() const noexcept
  1342. {
  1343. return N;
  1344. }
  1345. #ifdef GCC4_FALLBACK
  1346. XTENSOR_CONST typename const_array_detail::array_traits<T, N>::storage_type m_data;
  1347. #else
  1348. XTENSOR_CONST T m_data[N > 0 ? N : 1];
  1349. #endif
  1350. };
  1351. #undef GCC4_FALLBACK
  1352. template <class T, std::size_t N>
  1353. inline bool operator==(const const_array<T, N>& lhs, const const_array<T, N>& rhs)
  1354. {
  1355. return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
  1356. }
  1357. template <class T, std::size_t N>
  1358. inline bool operator!=(const const_array<T, N>& lhs, const const_array<T, N>& rhs)
  1359. {
  1360. return !(lhs == rhs);
  1361. }
  1362. template <class T, std::size_t N>
  1363. inline bool operator<(const const_array<T, N>& lhs, const const_array<T, N>& rhs)
  1364. {
  1365. return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  1366. }
  1367. template <class T, std::size_t N>
  1368. inline bool operator<=(const const_array<T, N>& lhs, const const_array<T, N>& rhs)
  1369. {
  1370. return !(lhs > rhs);
  1371. }
  1372. template <class T, std::size_t N>
  1373. inline bool operator>(const const_array<T, N>& lhs, const const_array<T, N>& rhs)
  1374. {
  1375. return rhs < lhs;
  1376. }
  1377. template <class T, std::size_t N>
  1378. inline bool operator>=(const const_array<T, N>& lhs, const const_array<T, N>& rhs)
  1379. {
  1380. return !(lhs < rhs);
  1381. }
  1382. // Workaround for rebind_container problems on GCC 8 with C++17 enabled
  1383. #if defined(__GNUC__) && __GNUC__ > 6 && !defined(__clang__) && __cplusplus >= 201703L
  1384. template <class X, class T, std::size_t N>
  1385. struct rebind_container<X, aligned_array<T, N>>
  1386. {
  1387. using type = aligned_array<X, N>;
  1388. };
  1389. template <class X, class T, std::size_t N>
  1390. struct rebind_container<X, const_array<T, N>>
  1391. {
  1392. using type = const_array<X, N>;
  1393. };
  1394. #endif
  1395. /**
  1396. * @class fixed_shape
  1397. * Fixed shape implementation for compile time defined arrays.
  1398. * @sa xshape
  1399. */
  1400. template <std::size_t... X>
  1401. class fixed_shape
  1402. {
  1403. public:
  1404. #if defined(_MSC_VER)
  1405. using cast_type = std::array<std::size_t, sizeof...(X)>;
  1406. #define XTENSOR_FIXED_SHAPE_CONSTEXPR inline
  1407. #else
  1408. using cast_type = const_array<std::size_t, sizeof...(X)>;
  1409. #define XTENSOR_FIXED_SHAPE_CONSTEXPR constexpr
  1410. #endif
  1411. using value_type = std::size_t;
  1412. using size_type = std::size_t;
  1413. using const_iterator = typename cast_type::const_iterator;
  1414. static constexpr std::size_t size()
  1415. {
  1416. return sizeof...(X);
  1417. }
  1418. template <std::size_t idx>
  1419. static constexpr auto get()
  1420. {
  1421. using tmp_cast_type = std::array<std::size_t, sizeof...(X)>;
  1422. return std::get<idx>(tmp_cast_type{X...});
  1423. }
  1424. XTENSOR_FIXED_SHAPE_CONSTEXPR operator cast_type() const
  1425. {
  1426. return cast_type({X...});
  1427. }
  1428. XTENSOR_FIXED_SHAPE_CONSTEXPR auto begin() const
  1429. {
  1430. return m_array.begin();
  1431. }
  1432. XTENSOR_FIXED_SHAPE_CONSTEXPR auto end() const
  1433. {
  1434. return m_array.end();
  1435. }
  1436. auto rbegin() const
  1437. {
  1438. return m_array.rbegin();
  1439. }
  1440. auto rend() const
  1441. {
  1442. return m_array.rend();
  1443. }
  1444. XTENSOR_FIXED_SHAPE_CONSTEXPR auto cbegin() const
  1445. {
  1446. return m_array.cbegin();
  1447. }
  1448. XTENSOR_FIXED_SHAPE_CONSTEXPR auto cend() const
  1449. {
  1450. return m_array.cend();
  1451. }
  1452. XTENSOR_FIXED_SHAPE_CONSTEXPR std::size_t operator[](std::size_t idx) const
  1453. {
  1454. return m_array[idx];
  1455. }
  1456. XTENSOR_FIXED_SHAPE_CONSTEXPR bool empty() const
  1457. {
  1458. return sizeof...(X) == 0;
  1459. }
  1460. private:
  1461. XTENSOR_CONSTEXPR_ENHANCED_STATIC cast_type m_array = cast_type({X...});
  1462. };
  1463. #ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED
  1464. template <std::size_t... X>
  1465. constexpr typename fixed_shape<X...>::cast_type fixed_shape<X...>::m_array;
  1466. #endif
  1467. #undef XTENSOR_FIXED_SHAPE_CONSTEXPR
  1468. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End = -1>
  1469. class sequence_view
  1470. {
  1471. public:
  1472. using value_type = typename E::value_type;
  1473. using reference = typename E::reference;
  1474. using const_reference = typename E::const_reference;
  1475. using pointer = typename E::pointer;
  1476. using const_pointer = typename E::const_pointer;
  1477. using size_type = typename E::size_type;
  1478. using difference_type = typename E::difference_type;
  1479. using iterator = typename E::iterator;
  1480. using const_iterator = typename E::const_iterator;
  1481. using reverse_iterator = typename E::reverse_iterator;
  1482. using const_reverse_iterator = typename E::const_reverse_iterator;
  1483. explicit sequence_view(const E& container);
  1484. template <std::ptrdiff_t OS, std::ptrdiff_t OE>
  1485. explicit sequence_view(const sequence_view<E, OS, OE>& other);
  1486. template <class T, class R = decltype(std::declval<T>().begin())>
  1487. operator T() const;
  1488. bool empty() const;
  1489. size_type size() const;
  1490. const_reference operator[](std::size_t idx) const;
  1491. const_iterator end() const;
  1492. const_iterator begin() const;
  1493. const_iterator cend() const;
  1494. const_iterator cbegin() const;
  1495. const_reverse_iterator rend() const;
  1496. const_reverse_iterator rbegin() const;
  1497. const_reverse_iterator crend() const;
  1498. const_reverse_iterator crbegin() const;
  1499. const_reference front() const;
  1500. const_reference back() const;
  1501. const E& storage() const;
  1502. private:
  1503. const E& m_sequence;
  1504. };
  1505. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1506. sequence_view<E, Start, End>::sequence_view(const E& container)
  1507. : m_sequence(container)
  1508. {
  1509. }
  1510. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1511. template <std::ptrdiff_t OS, std::ptrdiff_t OE>
  1512. sequence_view<E, Start, End>::sequence_view(const sequence_view<E, OS, OE>& other)
  1513. : m_sequence(other.storage())
  1514. {
  1515. }
  1516. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1517. template <class T, class R>
  1518. sequence_view<E, Start, End>::operator T() const
  1519. {
  1520. T ret = xtl::make_sequence<T>(this->size());
  1521. std::copy(this->cbegin(), this->cend(), ret.begin());
  1522. return ret;
  1523. }
  1524. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1525. bool sequence_view<E, Start, End>::empty() const
  1526. {
  1527. return size() == size_type(0);
  1528. }
  1529. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1530. auto sequence_view<E, Start, End>::size() const -> size_type
  1531. {
  1532. if (End == -1)
  1533. {
  1534. return m_sequence.size() - static_cast<size_type>(Start);
  1535. }
  1536. else
  1537. {
  1538. return static_cast<size_type>(End - Start);
  1539. }
  1540. }
  1541. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1542. auto sequence_view<E, Start, End>::operator[](std::size_t idx) const -> const_reference
  1543. {
  1544. return m_sequence[idx + static_cast<std::size_t>(Start)];
  1545. }
  1546. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1547. auto sequence_view<E, Start, End>::end() const -> const_iterator
  1548. {
  1549. if (End != -1)
  1550. {
  1551. return m_sequence.begin() + End;
  1552. }
  1553. else
  1554. {
  1555. return m_sequence.end();
  1556. }
  1557. }
  1558. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1559. auto sequence_view<E, Start, End>::begin() const -> const_iterator
  1560. {
  1561. return m_sequence.begin() + Start;
  1562. }
  1563. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1564. auto sequence_view<E, Start, End>::cend() const -> const_iterator
  1565. {
  1566. return end();
  1567. }
  1568. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1569. auto sequence_view<E, Start, End>::cbegin() const -> const_iterator
  1570. {
  1571. return begin();
  1572. }
  1573. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1574. auto sequence_view<E, Start, End>::rend() const -> const_reverse_iterator
  1575. {
  1576. return const_reverse_iterator(begin());
  1577. }
  1578. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1579. auto sequence_view<E, Start, End>::rbegin() const -> const_reverse_iterator
  1580. {
  1581. return const_reverse_iterator(end());
  1582. }
  1583. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1584. auto sequence_view<E, Start, End>::crend() const -> const_reverse_iterator
  1585. {
  1586. return rend();
  1587. }
  1588. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1589. auto sequence_view<E, Start, End>::crbegin() const -> const_reverse_iterator
  1590. {
  1591. return rbegin();
  1592. }
  1593. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1594. auto sequence_view<E, Start, End>::front() const -> const_reference
  1595. {
  1596. return *(m_sequence.begin() + Start);
  1597. }
  1598. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1599. auto sequence_view<E, Start, End>::back() const -> const_reference
  1600. {
  1601. if (End == -1)
  1602. {
  1603. return m_sequence.back();
  1604. }
  1605. else
  1606. {
  1607. return m_sequence[static_cast<std::size_t>(End - 1)];
  1608. }
  1609. }
  1610. template <class E, std::ptrdiff_t Start, std::ptrdiff_t End>
  1611. const E& sequence_view<E, Start, End>::storage() const
  1612. {
  1613. return m_sequence;
  1614. }
  1615. template <class T, std::ptrdiff_t TB, std::ptrdiff_t TE>
  1616. inline bool operator==(const sequence_view<T, TB, TE>& lhs, const sequence_view<T, TB, TE>& rhs)
  1617. {
  1618. return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
  1619. }
  1620. template <class T, std::ptrdiff_t TB, std::ptrdiff_t TE>
  1621. inline bool operator!=(const sequence_view<T, TB, TE>& lhs, const sequence_view<T, TB, TE>& rhs)
  1622. {
  1623. return !(lhs == rhs);
  1624. }
  1625. }
  1626. /******************************
  1627. * std::tuple_size extensions *
  1628. ******************************/
  1629. // The C++ standard defines tuple_size as a class, however
  1630. // G++ 8 C++ library does define it as a struct hence we get
  1631. // clang warnings here
  1632. // Do not remove space between "#" and "pragma". This is required for CRAN checks.
  1633. // clang-format off
  1634. #if defined(__clang__)
  1635. # pragma clang diagnostic push
  1636. # pragma clang diagnostic ignored "-Wmismatched-tags"
  1637. #endif
  1638. // clang-format on
  1639. namespace std
  1640. {
  1641. template <class T, std::size_t N>
  1642. class tuple_size<xt::const_array<T, N>> : public integral_constant<std::size_t, N>
  1643. {
  1644. };
  1645. template <std::size_t... N>
  1646. class tuple_size<xt::fixed_shape<N...>> : public integral_constant<std::size_t, sizeof...(N)>
  1647. {
  1648. };
  1649. template <class T, std::ptrdiff_t Start, std::ptrdiff_t End>
  1650. class tuple_size<xt::sequence_view<T, Start, End>>
  1651. : public integral_constant<std::size_t, std::size_t(End - Start)>
  1652. {
  1653. };
  1654. // Undefine tuple size for not-known sequence view size
  1655. template <class T, std::ptrdiff_t Start>
  1656. class tuple_size<xt::sequence_view<T, Start, -1>>;
  1657. }
  1658. // Do not remove space between "#" and "pragma". This is required for CRAN checks.
  1659. // clang-format off
  1660. #if defined(__clang__)
  1661. # pragma clang diagnostic pop
  1662. #endif
  1663. // clang-format on
  1664. #undef XTENSOR_CONST
  1665. #endif