span.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /*************************************************************************
  2. *
  3. * Copyright 2022 Realm Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. **************************************************************************/
  18. #ifndef REALM_UTIL_SPAN_HPP
  19. #define REALM_UTIL_SPAN_HPP
  20. #include <realm/util/assert.hpp>
  21. #include <array>
  22. #include <cstddef>
  23. #include <iterator>
  24. #include <limits>
  25. #include <type_traits>
  26. namespace realm::util {
  27. // This is an implementation of C++20's std::span. This should be an exact
  28. // drop-in replacement that can be deleted once we switch to building as C++20.
  29. // See https://en.cppreference.com/w/cpp/container/span for documentation on this type.
  30. inline constexpr size_t dynamic_extent = std::numeric_limits<size_t>::max();
  31. template <typename T, size_t extent = dynamic_extent>
  32. class Span;
  33. } // namespace realm::util
  34. namespace realm::_impl {
  35. // SFINAE helpers: anything which has std::data() and std::size() and
  36. // std::data() produces the correct type can be converted to Span, but
  37. // std::array, C arrays, and Span have separate conversions which need to be
  38. // used instead of the generic one.
  39. template <typename T>
  40. struct IsSpan : public std::false_type {
  41. };
  42. template <typename T, size_t extent>
  43. struct IsSpan<util::Span<T, extent>> : public std::true_type {
  44. };
  45. template <typename T>
  46. struct IsStdArray : public std::false_type {
  47. };
  48. template <typename T, size_t size>
  49. struct IsStdArray<std::array<T, size>> : public std::true_type {
  50. };
  51. // msvc v19.28 hits an internal compiler error if these are inline in the
  52. // template using them rather than type aliases. This appears to be fixed in
  53. // newer versions
  54. template <typename T>
  55. using StdDataT = decltype(std::data(std::declval<T>()));
  56. template <typename T>
  57. using StdSizeT = decltype(std::size(std::declval<T>()));
  58. template <typename T, typename U, typename A = StdDataT<T>, typename B = StdSizeT<T>>
  59. constexpr bool is_span_compatible()
  60. {
  61. return !IsSpan<std::remove_cv_t<T>>::value && !IsStdArray<std::remove_cv_t<T>>::value && !std::is_array_v<T> &&
  62. std::is_convertible_v<std::remove_pointer_t<decltype(std::data(std::declval<T&>()))>(*)[], U(*)[]>;
  63. }
  64. template <typename C, typename T>
  65. using EnableIfSpanCompatible = std::enable_if_t<is_span_compatible<C, T>(), int>;
  66. } // namespace realm::_impl
  67. namespace realm::util {
  68. template <typename T, size_t Extent>
  69. class Span {
  70. public:
  71. using element_type = T;
  72. using value_type = std::remove_cv_t<T>;
  73. using size_type = size_t;
  74. using difference_type = ptrdiff_t;
  75. using pointer = T*;
  76. using const_pointer = const T*;
  77. using reference = T&;
  78. using const_reference = const T&;
  79. using iterator = pointer;
  80. using reverse_iterator = std::reverse_iterator<iterator>;
  81. static constexpr size_type extent = Extent;
  82. template <size_t size = extent, std::enable_if_t<size == 0, int> = 0>
  83. constexpr Span() noexcept
  84. {
  85. }
  86. constexpr Span(const Span&) noexcept = default;
  87. constexpr Span& operator=(const Span&) noexcept = default;
  88. constexpr explicit Span(pointer ptr, size_type count)
  89. : m_data{ptr}
  90. {
  91. REALM_ASSERT(extent == count);
  92. }
  93. constexpr explicit Span(pointer begin, pointer end)
  94. : m_data{begin}
  95. {
  96. REALM_ASSERT(extent == std::distance(begin, end));
  97. }
  98. #if 0 // VS 16.9 incorrectly rejects this. 16.10+ support it
  99. constexpr Span(element_type (&arr)[extent]) noexcept
  100. : m_data{arr}
  101. {
  102. }
  103. #endif
  104. template <class U, std::enable_if_t<std::is_convertible_v<U (*)[], element_type (*)[]>, int> = 0>
  105. constexpr Span(std::array<U, extent>& arr) noexcept
  106. : m_data{arr.data()}
  107. {
  108. }
  109. template <class U, std::enable_if_t<std::is_convertible_v<const U (*)[], element_type (*)[]>, int> = 0>
  110. constexpr Span(const std::array<U, extent>& arr) noexcept
  111. : m_data{arr.data()}
  112. {
  113. }
  114. template <class Container, _impl::EnableIfSpanCompatible<Container, T> = 0>
  115. constexpr explicit Span(Container& c)
  116. : m_data{std::data(c)}
  117. {
  118. REALM_ASSERT(extent == std::size(c));
  119. }
  120. template <class Container, _impl::EnableIfSpanCompatible<const Container, T> = 0>
  121. constexpr explicit Span(const Container& c)
  122. : m_data{std::data(c)}
  123. {
  124. REALM_ASSERT(extent == std::size(c));
  125. }
  126. template <class U, std::enable_if_t<std::is_convertible_v<U (*)[], element_type (*)[]>, int> = 0>
  127. constexpr Span(const Span<U, extent>& other)
  128. : m_data{other.data()}
  129. {
  130. }
  131. #if 0 // VS 16.9 incorrectly rejects this. 16.10+ support it
  132. template <class U, std::enable_if_t<std::is_convertible_v<U (*)[], element_type (*)[]>, int> = 0>
  133. constexpr explicit Span(const Span<U, dynamic_extent>& other) noexcept
  134. : m_data{other.data()}
  135. {
  136. REALM_ASSERT(extent == other.size());
  137. }
  138. #endif
  139. template <size_t count>
  140. constexpr Span<element_type, count> first() const noexcept
  141. {
  142. static_assert(count <= extent);
  143. return Span<element_type, count>{data(), count};
  144. }
  145. template <size_t count>
  146. constexpr Span<element_type, count> last() const noexcept
  147. {
  148. static_assert(count <= extent);
  149. return Span<element_type, count>{data() + size() - count, count};
  150. }
  151. constexpr Span<element_type, dynamic_extent> first(size_type count) const noexcept
  152. {
  153. REALM_ASSERT(count <= size());
  154. return {data(), count};
  155. }
  156. constexpr Span<element_type, dynamic_extent> last(size_type count) const noexcept
  157. {
  158. REALM_ASSERT(count <= size());
  159. return {data() + size() - count, count};
  160. }
  161. template <size_t offset, size_t count = dynamic_extent>
  162. constexpr auto sub_span() const noexcept
  163. {
  164. static_assert(offset <= extent);
  165. static_assert(count == dynamic_extent || count <= extent - offset);
  166. using Ret = Span<element_type, count != dynamic_extent ? count : extent - offset>;
  167. return Ret{data() + offset, count == dynamic_extent ? size() - offset : count};
  168. }
  169. constexpr Span<element_type, dynamic_extent> sub_span(size_type offset,
  170. size_type count = dynamic_extent) const noexcept
  171. {
  172. REALM_ASSERT(offset <= size());
  173. REALM_ASSERT(count <= size() || count == dynamic_extent);
  174. if (count == dynamic_extent)
  175. return {data() + offset, size() - offset};
  176. REALM_ASSERT(count <= size() - offset);
  177. return {data() + offset, count};
  178. }
  179. constexpr size_type size() const noexcept
  180. {
  181. return extent;
  182. }
  183. constexpr size_type size_bytes() const noexcept
  184. {
  185. return extent * sizeof(element_type);
  186. }
  187. constexpr bool empty() const noexcept
  188. {
  189. return extent == 0;
  190. }
  191. constexpr reference operator[](size_type idx) const noexcept
  192. {
  193. REALM_ASSERT(idx < size());
  194. return m_data[idx];
  195. }
  196. constexpr reference front() const noexcept
  197. {
  198. REALM_ASSERT(!empty());
  199. return m_data[0];
  200. }
  201. constexpr reference back() const noexcept
  202. {
  203. REALM_ASSERT(!empty());
  204. return m_data[size() - 1];
  205. }
  206. constexpr pointer data() const noexcept
  207. {
  208. return m_data;
  209. }
  210. constexpr iterator begin() const noexcept
  211. {
  212. return data();
  213. }
  214. constexpr iterator end() const noexcept
  215. {
  216. return data() + size();
  217. }
  218. constexpr reverse_iterator rbegin() const noexcept
  219. {
  220. return reverse_iterator(end());
  221. }
  222. constexpr reverse_iterator rend() const noexcept
  223. {
  224. return reverse_iterator(begin());
  225. }
  226. Span<const std::byte, extent * sizeof(element_type)> as_bytes() const noexcept
  227. {
  228. return Span<const std::byte, extent * sizeof(element_type)>{reinterpret_cast<const std::byte*>(data()),
  229. size_bytes()};
  230. }
  231. Span<std::byte, extent * sizeof(element_type)> as_writable_bytes() const noexcept
  232. {
  233. return Span<std::byte, extent * sizeof(element_type)>{reinterpret_cast<std::byte*>(data()), size_bytes()};
  234. }
  235. private:
  236. pointer m_data = nullptr;
  237. };
  238. template <typename T>
  239. class Span<T, dynamic_extent> {
  240. public:
  241. using element_type = T;
  242. using value_type = std::remove_cv_t<T>;
  243. using size_type = size_t;
  244. using difference_type = ptrdiff_t;
  245. using pointer = T*;
  246. using const_pointer = const T*;
  247. using reference = T&;
  248. using const_reference = const T&;
  249. using iterator = pointer;
  250. using reverse_iterator = std::reverse_iterator<iterator>;
  251. static constexpr size_type extent = dynamic_extent;
  252. constexpr Span() noexcept = default;
  253. constexpr Span(const Span&) noexcept = default;
  254. constexpr Span& operator=(const Span&) noexcept = default;
  255. constexpr Span(pointer ptr, size_type count)
  256. : m_data{ptr}
  257. , m_size{count}
  258. {
  259. }
  260. constexpr Span(pointer f, pointer l)
  261. : m_data{f}
  262. , m_size{static_cast<size_t>(std::distance(f, l))}
  263. {
  264. }
  265. template <size_t size>
  266. constexpr Span(element_type (&arr)[size]) noexcept
  267. : m_data{arr}
  268. , m_size{size}
  269. {
  270. }
  271. template <class U, size_t size, std::enable_if_t<std::is_convertible_v<U (*)[], element_type (*)[]>, int> = 0>
  272. constexpr Span(std::array<U, size>& arr) noexcept
  273. : m_data{arr.data()}
  274. , m_size{size}
  275. {
  276. }
  277. template <class U, size_t size,
  278. std::enable_if_t<std::is_convertible_v<const U (*)[], element_type (*)[]>, int> = 0>
  279. constexpr Span(const std::array<U, size>& arr) noexcept
  280. : m_data{arr.data()}
  281. , m_size{size}
  282. {
  283. }
  284. template <class Container, _impl::EnableIfSpanCompatible<Container, T> = 0>
  285. constexpr Span(Container& c)
  286. : m_data{std::data(c)}
  287. , m_size{(size_type)std::size(c)}
  288. {
  289. }
  290. template <class Container, _impl::EnableIfSpanCompatible<const Container, T> = 0>
  291. constexpr Span(const Container& c)
  292. : m_data{std::data(c)}
  293. , m_size{(size_type)std::size(c)}
  294. {
  295. }
  296. template <class U, size_t E, std::enable_if_t<std::is_convertible_v<U (*)[], element_type (*)[]>, int> = 0>
  297. constexpr Span(const Span<U, E>& other) noexcept
  298. : m_data{other.data()}
  299. , m_size{other.size()}
  300. {
  301. }
  302. template <size_t count>
  303. constexpr Span<element_type, count> first() const noexcept
  304. {
  305. REALM_ASSERT(count <= m_size);
  306. return Span<element_type, count>{m_data, count};
  307. }
  308. template <size_t count>
  309. constexpr Span<element_type, count> last() const noexcept
  310. {
  311. REALM_ASSERT(count <= m_size);
  312. return Span<element_type, count>{m_data + m_size - count, count};
  313. }
  314. constexpr Span<element_type, dynamic_extent> first(size_type count) const noexcept
  315. {
  316. REALM_ASSERT(count <= m_size);
  317. return {m_data, count};
  318. }
  319. constexpr Span<element_type, dynamic_extent> last(size_type count) const noexcept
  320. {
  321. REALM_ASSERT(count <= m_size);
  322. return {m_data + m_size - count, count};
  323. }
  324. template <size_t offset, size_t count = dynamic_extent>
  325. constexpr Span<element_type, count> sub_span() const noexcept
  326. {
  327. REALM_ASSERT(offset <= m_size);
  328. REALM_ASSERT(count == dynamic_extent || count <= m_size - offset);
  329. return Span<element_type, count>{m_data + offset, count == dynamic_extent ? m_size - offset : count};
  330. }
  331. constexpr Span<element_type, dynamic_extent> sub_span(size_type offset,
  332. size_type count = dynamic_extent) const noexcept
  333. {
  334. REALM_ASSERT(offset <= m_size);
  335. REALM_ASSERT(count <= m_size || count == dynamic_extent);
  336. if (count == dynamic_extent)
  337. return {m_data + offset, m_size - offset};
  338. REALM_ASSERT(count <= m_size - offset);
  339. return {m_data + offset, count};
  340. }
  341. constexpr size_type size() const noexcept
  342. {
  343. return m_size;
  344. }
  345. constexpr size_type size_bytes() const noexcept
  346. {
  347. return m_size * sizeof(element_type);
  348. }
  349. constexpr bool empty() const noexcept
  350. {
  351. return m_size == 0;
  352. }
  353. constexpr reference operator[](size_type idx) const noexcept
  354. {
  355. REALM_ASSERT(idx < m_size);
  356. return m_data[idx];
  357. }
  358. constexpr reference front() const noexcept
  359. {
  360. REALM_ASSERT(m_size);
  361. return m_data[0];
  362. }
  363. constexpr reference back() const noexcept
  364. {
  365. REALM_ASSERT(m_size);
  366. return m_data[m_size - 1];
  367. }
  368. constexpr pointer data() const noexcept
  369. {
  370. return m_data;
  371. }
  372. constexpr iterator begin() const noexcept
  373. {
  374. return m_data;
  375. }
  376. constexpr iterator end() const noexcept
  377. {
  378. return m_data + m_size;
  379. }
  380. constexpr reverse_iterator rbegin() const noexcept
  381. {
  382. return reverse_iterator(end());
  383. }
  384. constexpr reverse_iterator rend() const noexcept
  385. {
  386. return reverse_iterator(begin());
  387. }
  388. Span<const std::byte, dynamic_extent> as_bytes() const noexcept
  389. {
  390. return {reinterpret_cast<const std::byte*>(m_data), size_bytes()};
  391. }
  392. Span<std::byte, dynamic_extent> as_writable_bytes() const noexcept
  393. {
  394. return {reinterpret_cast<std::byte*>(m_data), size_bytes()};
  395. }
  396. private:
  397. pointer m_data = nullptr;
  398. size_type m_size = 0;
  399. };
  400. template <typename T, size_t extent>
  401. auto as_bytes(Span<T, extent> s) noexcept -> decltype(s.as_bytes())
  402. {
  403. return s.as_bytes();
  404. }
  405. template <typename T, size_t extent>
  406. auto as_writable_bytes(Span<T, extent> s) noexcept
  407. -> std::enable_if_t<!std::is_const_v<T>, decltype(s.as_writable_bytes())>
  408. {
  409. return s.as_writable_bytes();
  410. }
  411. template <typename T, typename... Args>
  412. constexpr auto unsafe_span_cast(Args&&... args)
  413. {
  414. auto temp = Span(std::forward<Args>(args)...);
  415. return Span<T, decltype(temp)::extent>(reinterpret_cast<T*>(temp.data()), temp.size());
  416. }
  417. // Deduction guides
  418. template <typename T, size_t extent>
  419. Span(T (&)[extent]) -> Span<T, extent>;
  420. template <typename T, size_t extent>
  421. Span(std::array<T, extent>&) -> Span<T, extent>;
  422. template <typename T, size_t extent>
  423. Span(const std::array<T, extent>&) -> Span<const T, extent>;
  424. template <class Container>
  425. Span(Container&) -> Span<typename Container::value_type>;
  426. template <class Container>
  427. Span(const Container&) -> Span<const typename Container::value_type>;
  428. } // namespace realm::util
  429. #endif // REALM_UTIL_SPAN_HPP