xspan_impl.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. // https://github.com/tcbrindle/span/blob/master/include/tcb/span.hpp
  2. // TCP SPAN @commit cd0c6d0
  3. /*
  4. This is an implementation of std::span from P0122R7
  5. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0122r7.pdf
  6. */
  7. // Copyright Tristan Brindle 2018.
  8. // Distributed under the Boost Software License, Version 1.0.
  9. // (See accompanying file ../../LICENSE_1_0.txt or copy at
  10. // https://www.boost.org/LICENSE_1_0.txt)
  11. #ifndef TCB_SPAN_HPP_INCLUDED
  12. #define TCB_SPAN_HPP_INCLUDED
  13. #include <array>
  14. #include <cstddef>
  15. #include <exception>
  16. #include <type_traits>
  17. #ifndef TCB_SPAN_NO_EXCEPTIONS
  18. // Attempt to discover whether we're being compiled with exception support
  19. #if !(defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND))
  20. #define TCB_SPAN_NO_EXCEPTIONS
  21. #endif
  22. #endif
  23. #ifndef TCB_SPAN_NO_EXCEPTIONS
  24. #include <cstdio>
  25. #include <stdexcept>
  26. #endif
  27. // Various feature test macros
  28. #ifndef TCB_SPAN_NAMESPACE_NAME
  29. #define TCB_SPAN_NAMESPACE_NAME tcb
  30. #endif
  31. #ifdef TCB_SPAN_STD_COMPLIANT_MODE
  32. #define TCB_SPAN_NO_DEPRECATION_WARNINGS
  33. #endif
  34. #ifndef TCB_SPAN_NO_DEPRECATION_WARNINGS
  35. #define TCB_SPAN_DEPRECATED_FOR(msg) [[deprecated(msg)]]
  36. #else
  37. #define TCB_SPAN_DEPRECATED_FOR(msg)
  38. #endif
  39. #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
  40. #define TCB_SPAN_HAVE_CPP17
  41. #endif
  42. #if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
  43. #define TCB_SPAN_HAVE_CPP14
  44. #endif
  45. namespace TCB_SPAN_NAMESPACE_NAME {
  46. // Establish default contract checking behavior
  47. #if !defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION) && \
  48. !defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) && \
  49. !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
  50. #if defined(NDEBUG) || !defined(TCB_SPAN_HAVE_CPP14)
  51. #define TCB_SPAN_NO_CONTRACT_CHECKING
  52. #else
  53. #define TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION
  54. #endif
  55. #endif
  56. #if defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION)
  57. struct contract_violation_error : std::logic_error {
  58. explicit contract_violation_error(const char* msg) : std::logic_error(msg)
  59. {}
  60. };
  61. inline void contract_violation(const char* msg)
  62. {
  63. throw contract_violation_error(msg);
  64. }
  65. #elif defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION)
  66. [[noreturn]] inline void contract_violation(const char* /*unused*/)
  67. {
  68. std::terminate();
  69. }
  70. #endif
  71. #if !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
  72. #define TCB_SPAN_STRINGIFY(cond) #cond
  73. #define TCB_SPAN_EXPECT(cond) \
  74. cond ? (void) 0 : contract_violation("Expected " TCB_SPAN_STRINGIFY(cond))
  75. #else
  76. #define TCB_SPAN_EXPECT(cond)
  77. #endif
  78. #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_inline_variables)
  79. #define TCB_SPAN_INLINE_VAR inline
  80. #else
  81. #define TCB_SPAN_INLINE_VAR
  82. #endif
  83. #if defined(TCB_SPAN_HAVE_CPP14) || \
  84. (defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
  85. #define TCB_SPAN_CONSTEXPR14 constexpr
  86. #else
  87. #define TCB_SPAN_CONSTEXPR14
  88. #endif
  89. #if defined(TCB_SPAN_NO_CONTRACT_CHECKING)
  90. #define TCB_SPAN_CONSTEXPR11 constexpr
  91. #else
  92. #define TCB_SPAN_CONSTEXPR11 TCB_SPAN_CONSTEXPR14
  93. #endif
  94. #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_deduction_guides)
  95. #define TCB_SPAN_HAVE_DEDUCTION_GUIDES
  96. #endif
  97. #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_byte) && !(defined(_HAS_STD_BYTE) && !_HAS_STD_BYTE)
  98. #define TCB_SPAN_HAVE_STD_BYTE
  99. #endif
  100. #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_array_constexpr)
  101. #define TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC
  102. #endif
  103. #if defined(TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC)
  104. #define TCB_SPAN_ARRAY_CONSTEXPR constexpr
  105. #else
  106. #define TCB_SPAN_ARRAY_CONSTEXPR
  107. #endif
  108. #ifdef TCB_SPAN_HAVE_STD_BYTE
  109. using byte = std::byte;
  110. #else
  111. using byte = unsigned char;
  112. #endif
  113. TCB_SPAN_INLINE_VAR constexpr std::ptrdiff_t dynamic_extent = -1;
  114. template <typename ElementType, std::ptrdiff_t Extent = dynamic_extent>
  115. class span;
  116. namespace detail {
  117. template <typename E, std::ptrdiff_t S>
  118. struct span_storage {
  119. constexpr span_storage() noexcept = default;
  120. constexpr span_storage(E* aptr, std::ptrdiff_t /*unused*/) noexcept
  121. : ptr(aptr)
  122. {}
  123. E* ptr = nullptr;
  124. static constexpr std::ptrdiff_t size = S;
  125. };
  126. template <typename E>
  127. struct span_storage<E, dynamic_extent> {
  128. constexpr span_storage() noexcept = default;
  129. constexpr span_storage(E* aptr, std::size_t asize) noexcept
  130. : ptr(aptr), size(asize)
  131. {}
  132. E* ptr = nullptr;
  133. std::size_t size = 0;
  134. };
  135. // Reimplementation of C++17 std::size() and std::data()
  136. #if defined(TCB_SPAN_HAVE_CPP17) || \
  137. defined(__cpp_lib_nonmember_container_access)
  138. using std::data;
  139. using std::size;
  140. #else
  141. template <class C>
  142. constexpr auto size(const C& c) -> decltype(c.size())
  143. {
  144. return c.size();
  145. }
  146. template <class T, std::size_t N>
  147. constexpr std::size_t size(const T (&)[N]) noexcept
  148. {
  149. return N;
  150. }
  151. template <class C>
  152. constexpr auto data(C& c) -> decltype(c.data())
  153. {
  154. return c.data();
  155. }
  156. template <class C>
  157. constexpr auto data(const C& c) -> decltype(c.data())
  158. {
  159. return c.data();
  160. }
  161. template <class T, std::size_t N>
  162. constexpr T* data(T (&array)[N]) noexcept
  163. {
  164. return array;
  165. }
  166. template <class E>
  167. constexpr const E* data(std::initializer_list<E> il) noexcept
  168. {
  169. return il.begin();
  170. }
  171. #endif // TCB_SPAN_HAVE_CPP17
  172. #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_void_t)
  173. using std::void_t;
  174. #else
  175. template <typename...>
  176. using void_t = void;
  177. #endif
  178. template <typename T>
  179. using uncvref_t =
  180. typename std::remove_cv<typename std::remove_reference<T>::type>::type;
  181. template <typename>
  182. struct is_span : std::false_type {};
  183. template <typename T, std::ptrdiff_t S>
  184. struct is_span<span<T, S>> : std::true_type {};
  185. template <typename>
  186. struct is_std_array : std::false_type {};
  187. template <typename T, std::size_t N>
  188. struct is_std_array<std::array<T, N>> : std::true_type {};
  189. template <typename, typename = void>
  190. struct has_size_and_data : std::false_type {};
  191. template <typename T>
  192. struct has_size_and_data<T, void_t<decltype(detail::size(std::declval<T>())),
  193. decltype(detail::data(std::declval<T>()))>>
  194. : std::true_type {};
  195. template <typename C, typename U = uncvref_t<C>>
  196. struct is_container {
  197. static constexpr bool value =
  198. !is_span<U>::value && !is_std_array<U>::value &&
  199. !std::is_array<U>::value && has_size_and_data<C>::value;
  200. };
  201. template <typename T>
  202. using remove_pointer_t = typename std::remove_pointer<T>::type;
  203. template <typename, typename, typename = void>
  204. struct is_container_element_type_compatible : std::false_type {};
  205. template <typename T, typename E>
  206. struct is_container_element_type_compatible<
  207. T, E, void_t<decltype(detail::data(std::declval<T>()))>>
  208. : std::is_convertible<
  209. remove_pointer_t<decltype(detail::data(std::declval<T>()))> (*)[],
  210. E (*)[]> {};
  211. template <typename, typename = size_t>
  212. struct is_complete : std::false_type {};
  213. template <typename T>
  214. struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
  215. } // namespace detail
  216. template <typename ElementType, std::ptrdiff_t Extent>
  217. class span {
  218. static_assert(Extent == dynamic_extent || Extent >= 0,
  219. "A span must have an extent greater than or equal to zero, "
  220. "or a dynamic extent");
  221. static_assert(std::is_object<ElementType>::value,
  222. "A span's ElementType must be an object type (not a "
  223. "reference type or void)");
  224. static_assert(detail::is_complete<ElementType>::value,
  225. "A span's ElementType must be a complete type (not a forward "
  226. "declaration)");
  227. static_assert(!std::is_abstract<ElementType>::value,
  228. "A span's ElementType cannot be an abstract class type");
  229. using storage_type = detail::span_storage<ElementType, Extent>;
  230. public:
  231. // constants and types
  232. using element_type = ElementType;
  233. using value_type = typename std::remove_cv<ElementType>::type;
  234. using index_type = std::size_t;
  235. using difference_type = std::ptrdiff_t;
  236. using pointer = ElementType*;
  237. using reference = ElementType&;
  238. using iterator = pointer;
  239. using const_iterator = const ElementType*;
  240. using reverse_iterator = std::reverse_iterator<iterator>;
  241. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  242. static constexpr index_type extent = static_cast<index_type>(Extent);
  243. // [span.cons], span constructors, copy, assignment, and destructor
  244. template <std::ptrdiff_t E = Extent,
  245. typename std::enable_if<E <= 0, int>::type = 0>
  246. constexpr span() noexcept
  247. {}
  248. TCB_SPAN_CONSTEXPR11 span(pointer ptr, index_type count)
  249. : storage_(ptr, count)
  250. {
  251. TCB_SPAN_EXPECT(extent == dynamic_extent || count == extent);
  252. }
  253. TCB_SPAN_CONSTEXPR11 span(pointer first_elem, pointer last_elem)
  254. : storage_(first_elem, last_elem - first_elem)
  255. {
  256. TCB_SPAN_EXPECT(extent == dynamic_extent ||
  257. last_elem - first_elem == extent);
  258. }
  259. template <
  260. std::size_t N, std::ptrdiff_t E = Extent,
  261. typename std::enable_if<
  262. (E == dynamic_extent || static_cast<std::ptrdiff_t>(N) == E) &&
  263. detail::is_container_element_type_compatible<
  264. element_type (&)[N], ElementType>::value,
  265. int>::type = 0>
  266. constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N)
  267. {}
  268. template <
  269. std::size_t N, std::ptrdiff_t E = Extent,
  270. typename std::enable_if<
  271. (E == dynamic_extent || static_cast<std::ptrdiff_t>(N) == E) &&
  272. detail::is_container_element_type_compatible<
  273. std::array<value_type, N>&, ElementType>::value,
  274. int>::type = 0>
  275. TCB_SPAN_ARRAY_CONSTEXPR span(std::array<value_type, N>& arr) noexcept
  276. : storage_(arr.data(), N)
  277. {}
  278. template <
  279. std::size_t N, std::ptrdiff_t E = Extent,
  280. typename std::enable_if<
  281. (E == dynamic_extent || static_cast<std::ptrdiff_t>(N) == E) &&
  282. detail::is_container_element_type_compatible<
  283. const std::array<value_type, N>&, ElementType>::value,
  284. int>::type = 0>
  285. TCB_SPAN_ARRAY_CONSTEXPR span(const std::array<value_type, N>& arr) noexcept
  286. : storage_(arr.data(), N)
  287. {}
  288. template <typename Container,
  289. typename std::enable_if<
  290. detail::is_container<Container>::value &&
  291. detail::is_container_element_type_compatible<
  292. Container&, ElementType>::value,
  293. int>::type = 0>
  294. TCB_SPAN_CONSTEXPR11 span(Container& cont)
  295. : storage_(detail::data(cont), detail::size(cont))
  296. {
  297. TCB_SPAN_EXPECT(extent == dynamic_extent ||
  298. static_cast<std::ptrdiff_t>(detail::size(cont)) ==
  299. extent);
  300. }
  301. template <typename Container,
  302. typename std::enable_if<
  303. detail::is_container<Container>::value &&
  304. detail::is_container_element_type_compatible<
  305. const Container&, ElementType>::value,
  306. int>::type = 0>
  307. TCB_SPAN_CONSTEXPR11 span(const Container& cont)
  308. : storage_(detail::data(cont), detail::size(cont))
  309. {
  310. TCB_SPAN_EXPECT(extent == dynamic_extent ||
  311. static_cast<std::ptrdiff_t>(detail::size(cont)) ==
  312. extent);
  313. }
  314. constexpr span(const span& other) noexcept = default;
  315. template <typename OtherElementType, std::ptrdiff_t OtherExtent,
  316. typename std::enable_if<
  317. (Extent == OtherExtent || Extent == dynamic_extent) &&
  318. std::is_convertible<OtherElementType (*)[],
  319. ElementType (*)[]>::value,
  320. int>::type = 0>
  321. constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
  322. : storage_(other.data(), other.size())
  323. {}
  324. ~span() noexcept = default;
  325. span& operator=(const span& other) noexcept = default;
  326. // [span.sub], span subviews
  327. template <std::ptrdiff_t Count>
  328. TCB_SPAN_CONSTEXPR11 span<element_type, Count> first() const
  329. {
  330. TCB_SPAN_EXPECT(Count >= 0 && Count <= size());
  331. return {data(), Count};
  332. }
  333. template <std::ptrdiff_t Count>
  334. TCB_SPAN_CONSTEXPR11 span<element_type, Count> last() const
  335. {
  336. TCB_SPAN_EXPECT(Count >= 0 && Count <= size());
  337. return {data() + (size() - Count), Count};
  338. }
  339. template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
  340. using subspan_return_t =
  341. span<ElementType, Count != dynamic_extent
  342. ? Count
  343. : (Extent != dynamic_extent ? Extent - Offset
  344. : dynamic_extent)>;
  345. template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
  346. TCB_SPAN_CONSTEXPR11 subspan_return_t<Offset, Count> subspan() const
  347. {
  348. TCB_SPAN_EXPECT((Offset >= 0 && Offset <= size()) &&
  349. (Count == dynamic_extent ||
  350. (Count >= 0 && Offset + Count <= size())));
  351. return {data() + Offset,
  352. Count != dynamic_extent
  353. ? Count
  354. : (Extent != dynamic_extent ? Extent - Offset
  355. : size() - Offset)};
  356. }
  357. TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent>
  358. first(index_type count) const
  359. {
  360. TCB_SPAN_EXPECT(count >= 0 && count <= size());
  361. return {data(), count};
  362. }
  363. TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent>
  364. last(index_type count) const
  365. {
  366. TCB_SPAN_EXPECT(count >= 0 && count <= size());
  367. return {data() + (size() - count), count};
  368. }
  369. TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent>
  370. subspan(index_type offset, index_type count = static_cast<index_type>(dynamic_extent)) const
  371. {
  372. TCB_SPAN_EXPECT((offset >= 0 && offset <= size()) &&
  373. (count == dynamic_extent ||
  374. (count >= 0 && offset + count <= size())));
  375. return {data() + offset,
  376. count == dynamic_extent ? size() - offset : count};
  377. }
  378. // [span.obs], span observers
  379. constexpr index_type size() const noexcept { return storage_.size; }
  380. constexpr index_type size_bytes() const noexcept
  381. {
  382. return size() * sizeof(element_type);
  383. }
  384. constexpr bool empty() const noexcept { return size() == 0; }
  385. // [span.elem], span element access
  386. TCB_SPAN_CONSTEXPR11 reference operator[](index_type idx) const
  387. {
  388. TCB_SPAN_EXPECT(idx >= 0 && idx < size());
  389. return *(data() + idx);
  390. }
  391. /* Extension: not in P0122 */
  392. #ifndef TCB_SPAN_STD_COMPLIANT_MODE
  393. TCB_SPAN_CONSTEXPR14 reference at(index_type idx) const
  394. {
  395. #ifndef TCB_SPAN_NO_EXCEPTIONS
  396. if (idx < 0 || idx >= size()) {
  397. char msgbuf[64] = {
  398. 0,
  399. };
  400. std::snprintf(msgbuf, sizeof(msgbuf),
  401. "Index %td is out of range for span of size %td", idx,
  402. size());
  403. throw std::out_of_range{msgbuf};
  404. }
  405. #endif // TCB_SPAN_NO_EXCEPTIONS
  406. return this->operator[](idx);
  407. }
  408. TCB_SPAN_CONSTEXPR11 reference front() const
  409. {
  410. TCB_SPAN_EXPECT(!empty());
  411. return *data();
  412. }
  413. TCB_SPAN_CONSTEXPR11 reference back() const
  414. {
  415. TCB_SPAN_EXPECT(!empty());
  416. return *(data() + (size() - 1));
  417. }
  418. #endif // TCB_SPAN_STD_COMPLIANT_MODE
  419. #ifndef TCB_SPAN_NO_FUNCTION_CALL_OPERATOR
  420. TCB_SPAN_DEPRECATED_FOR("Use operator[] instead")
  421. constexpr reference operator()(index_type idx) const
  422. {
  423. return this->operator[](idx);
  424. }
  425. #endif // TCB_SPAN_NO_FUNCTION_CALL_OPERATOR
  426. constexpr pointer data() const noexcept { return storage_.ptr; }
  427. // [span.iterators], span iterator support
  428. constexpr iterator begin() const noexcept { return data(); }
  429. constexpr iterator end() const noexcept { return data() + size(); }
  430. constexpr const_iterator cbegin() const noexcept { return begin(); }
  431. constexpr const_iterator cend() const noexcept { return end(); }
  432. TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rbegin() const noexcept
  433. {
  434. return reverse_iterator(end());
  435. }
  436. TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rend() const noexcept
  437. {
  438. return reverse_iterator(begin());
  439. }
  440. TCB_SPAN_ARRAY_CONSTEXPR const_reverse_iterator crbegin() const noexcept
  441. {
  442. return const_reverse_iterator(cend());
  443. }
  444. TCB_SPAN_ARRAY_CONSTEXPR const_reverse_iterator crend() const noexcept
  445. {
  446. return const_reverse_iterator(cbegin());
  447. }
  448. private:
  449. storage_type storage_{};
  450. };
  451. #ifdef TCB_SPAN_HAVE_DEDUCTION_GUIDES
  452. /* Deduction Guides */
  453. template <class T, size_t N>
  454. span(T (&)[N])->span<T, N>;
  455. template <class T, size_t N>
  456. span(std::array<T, N>&)->span<T, N>;
  457. template <class T, size_t N>
  458. span(const std::array<T, N>&)->span<const T, N>;
  459. template <class Container>
  460. span(Container&)->span<typename Container::value_type>;
  461. template <class Container>
  462. span(const Container&)->span<const typename Container::value_type>;
  463. #endif // TCB_HAVE_DEDUCTION_GUIDES
  464. template <typename ElementType, std::ptrdiff_t Extent>
  465. constexpr span<ElementType, Extent>
  466. make_span(span<ElementType, Extent> s) noexcept
  467. {
  468. return s;
  469. }
  470. #define AS_SIGNED(N) static_cast<std::ptrdiff_t>(N)
  471. template <typename T, std::size_t N>
  472. constexpr span<T, AS_SIGNED(N)> make_span(T (&arr)[N]) noexcept
  473. {
  474. return {arr};
  475. }
  476. template <typename T, std::size_t N>
  477. TCB_SPAN_ARRAY_CONSTEXPR span<T, AS_SIGNED(N)> make_span(std::array<T, N>& arr) noexcept
  478. {
  479. return {arr};
  480. }
  481. template <typename T, std::size_t N>
  482. TCB_SPAN_ARRAY_CONSTEXPR span<const T, AS_SIGNED(N)>
  483. make_span(const std::array<T, N>& arr) noexcept
  484. {
  485. return {arr};
  486. }
  487. #undef AS_SIGNED
  488. template <typename Container>
  489. constexpr span<typename Container::value_type> make_span(Container& cont)
  490. {
  491. return {cont};
  492. }
  493. template <typename Container>
  494. constexpr span<const typename Container::value_type>
  495. make_span(const Container& cont)
  496. {
  497. return {cont};
  498. }
  499. /* Comparison operators */
  500. // Implementation note: the implementations of == and < are equivalent to
  501. // 4-legged std::equal and std::lexicographical_compare respectively
  502. template <typename T, std::ptrdiff_t X, typename U, std::ptrdiff_t Y>
  503. TCB_SPAN_CONSTEXPR14 bool operator==(span<T, X> lhs, span<U, Y> rhs)
  504. {
  505. if (lhs.size() != rhs.size()) {
  506. return false;
  507. }
  508. for (std::ptrdiff_t i = 0; i < lhs.size(); i++) {
  509. if (lhs[i] != rhs[i]) {
  510. return false;
  511. }
  512. }
  513. return true;
  514. }
  515. template <typename T, std::ptrdiff_t X, typename U, std::ptrdiff_t Y>
  516. TCB_SPAN_CONSTEXPR14 bool operator!=(span<T, X> lhs, span<U, Y> rhs)
  517. {
  518. return !(lhs == rhs);
  519. }
  520. template <typename T, std::ptrdiff_t X, typename U, std::ptrdiff_t Y>
  521. TCB_SPAN_CONSTEXPR14 bool operator<(span<T, X> lhs, span<U, Y> rhs)
  522. {
  523. // No std::min to avoid dragging in <algorithm>
  524. const std::ptrdiff_t size =
  525. lhs.size() < rhs.size() ? lhs.size() : rhs.size();
  526. for (std::ptrdiff_t i = 0; i < size; i++) {
  527. if (lhs[i] < rhs[i]) {
  528. return true;
  529. }
  530. if (lhs[i] > rhs[i]) {
  531. return false;
  532. }
  533. }
  534. return lhs.size() < rhs.size();
  535. }
  536. template <typename T, std::ptrdiff_t X, typename U, std::ptrdiff_t Y>
  537. TCB_SPAN_CONSTEXPR14 bool operator<=(span<T, X> lhs, span<U, Y> rhs)
  538. {
  539. return !(rhs < lhs);
  540. }
  541. template <typename T, std::ptrdiff_t X, typename U, std::ptrdiff_t Y>
  542. TCB_SPAN_CONSTEXPR14 bool operator>(span<T, X> lhs, span<U, Y> rhs)
  543. {
  544. return rhs < lhs;
  545. }
  546. template <typename T, std::ptrdiff_t X, typename U, std::ptrdiff_t Y>
  547. TCB_SPAN_CONSTEXPR14 bool operator>=(span<T, X> lhs, span<U, Y> rhs)
  548. {
  549. return !(lhs < rhs);
  550. }
  551. template <typename ElementType, std::ptrdiff_t Extent>
  552. span<const byte, ((Extent == dynamic_extent)
  553. ? dynamic_extent
  554. : (static_cast<ptrdiff_t>(sizeof(ElementType)) * Extent))>
  555. as_bytes(span<ElementType, Extent> s) noexcept
  556. {
  557. return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
  558. }
  559. template <
  560. class ElementType, ptrdiff_t Extent,
  561. typename std::enable_if<!std::is_const<ElementType>::value, int>::type = 0>
  562. span<byte, ((Extent == dynamic_extent)
  563. ? dynamic_extent
  564. : (static_cast<ptrdiff_t>(sizeof(ElementType)) * Extent))>
  565. as_writable_bytes(span<ElementType, Extent> s) noexcept
  566. {
  567. return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
  568. }
  569. /* Extension: nonmember subview operations */
  570. #ifndef TCB_SPAN_STD_COMPLIANT_MODE
  571. template <std::ptrdiff_t Count, typename T>
  572. TCB_SPAN_CONSTEXPR11 auto first(T& t)
  573. -> decltype(make_span(t).template first<Count>())
  574. {
  575. return make_span(t).template first<Count>();
  576. }
  577. template <std::ptrdiff_t Count, typename T>
  578. TCB_SPAN_CONSTEXPR11 auto last(T& t)
  579. -> decltype(make_span(t).template last<Count>())
  580. {
  581. return make_span(t).template last<Count>();
  582. }
  583. template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent,
  584. typename T>
  585. TCB_SPAN_CONSTEXPR11 auto subspan(T& t)
  586. -> decltype(make_span(t).template subspan<Offset, Count>())
  587. {
  588. return make_span(t).template subspan<Offset, Count>();
  589. }
  590. template <typename T>
  591. TCB_SPAN_CONSTEXPR11 auto first(T& t, std::ptrdiff_t count)
  592. -> decltype(make_span(t).first(count))
  593. {
  594. return make_span(t).first(count);
  595. }
  596. template <typename T>
  597. TCB_SPAN_CONSTEXPR11 auto last(T& t, std::ptrdiff_t count)
  598. -> decltype(make_span(t).last(count))
  599. {
  600. return make_span(t).last(count);
  601. }
  602. template <typename T>
  603. TCB_SPAN_CONSTEXPR11 auto subspan(T& t, std::ptrdiff_t offset,
  604. std::ptrdiff_t count = dynamic_extent)
  605. -> decltype(make_span(t).subspan(offset, count))
  606. {
  607. return make_span(t).subspan(offset, count);
  608. }
  609. #endif // TCB_SPAN_STD_COMPLIANT_MODE
  610. } // namespace TCB_SPAN_NAMESPACE_NAME
  611. /* Extension: support for C++17 structured bindings */
  612. #ifndef TCB_SPAN_STD_COMPLIANT_MODE
  613. namespace TCB_SPAN_NAMESPACE_NAME {
  614. template <std::ptrdiff_t N, typename E, std::ptrdiff_t S>
  615. constexpr auto get(span<E, S> s) -> decltype(s[N])
  616. {
  617. return s[N];
  618. }
  619. } // namespace TCB_SPAN_NAMESPACE_NAME
  620. namespace std {
  621. template <typename E, ptrdiff_t S>
  622. class tuple_size<tcb::span<E, S>> : public integral_constant<size_t, static_cast<size_t>(S)> {};
  623. template <typename E>
  624. class tuple_size<tcb::span<E, tcb::dynamic_extent>>; // not defined
  625. template <size_t N, typename E, ptrdiff_t S>
  626. class tuple_element<N, tcb::span<E, S>> {
  627. public:
  628. using type = E;
  629. };
  630. } // end namespace std
  631. #endif // TCB_SPAN_STD_COMPLIANT_MODE
  632. #endif // TCB_SPAN_HPP_INCLUDED