File indexing completed on 2025-09-16 09:04:38
0001
0002
0003
0004 #ifndef QSPAN_H
0005 #define QSPAN_H
0006
0007 #include <QtCore/qcompilerdetection.h>
0008 #include <QtCore/qtypes.h>
0009 #include <QtCore/qcontainerfwd.h>
0010
0011 #include <array>
0012 #include <cstddef>
0013 #include <cassert>
0014 #include <initializer_list>
0015 #include <QtCore/q20iterator.h>
0016 #include <QtCore/q20memory.h>
0017 #ifdef __cpp_lib_span
0018 #include <span>
0019 #endif
0020 #include <QtCore/q20type_traits.h>
0021
0022 QT_BEGIN_NAMESPACE
0023
0024
0025 namespace q20 {
0026 inline constexpr auto dynamic_extent = std::size_t(-1);
0027 }
0028
0029 QT_BEGIN_INCLUDE_NAMESPACE
0030 #ifdef __cpp_lib_span
0031 #ifdef __cpp_lib_concepts
0032 namespace std::ranges {
0033
0034
0035
0036 template <typename T, std::size_t E>
0037 constexpr inline bool enable_borrowed_range<QT_PREPEND_NAMESPACE(QSpan)<T, E>> = true;
0038 template <typename T, std::size_t E>
0039 constexpr inline bool enable_view<QT_PREPEND_NAMESPACE(QSpan)<T, E>> = true;
0040 }
0041 #endif
0042 #endif
0043 QT_END_INCLUDE_NAMESPACE
0044
0045 namespace QSpanPrivate {
0046
0047 template <typename From, typename To>
0048 std::conditional_t<std::is_const_v<From>, const To &, To &>
0049 const_propagated(To &in) { return in; }
0050
0051 template <typename T, std::size_t E> class QSpanBase;
0052
0053 template <typename T>
0054 struct is_qspan_helper : std::false_type {};
0055 template <typename T, std::size_t E>
0056 struct is_qspan_helper<QSpan<T, E>> : std::true_type {};
0057 template <typename T, std::size_t E>
0058 struct is_qspan_helper<QSpanBase<T, E>> : std::true_type {};
0059 template <typename T>
0060 using is_qspan = is_qspan_helper<q20::remove_cvref_t<T>>;
0061
0062 template <typename T>
0063 struct is_std_span_helper : std::false_type {};
0064 #ifdef __cpp_lib_span
0065 template <typename T, std::size_t E>
0066 struct is_std_span_helper<std::span<T, E>> : std::true_type {};
0067 #endif
0068 template <typename T>
0069 using is_std_span = is_std_span_helper<q20::remove_cvref_t<T>>;
0070
0071 template <typename T>
0072 struct is_std_array_helper : std::false_type {};
0073 template <typename T, std::size_t N>
0074 struct is_std_array_helper<std::array<T, N>> : std::true_type {};
0075 template <typename T>
0076 using is_std_array = is_std_array_helper<q20::remove_cvref_t<T>>;
0077
0078 template <typename From, typename To>
0079 using is_qualification_conversion =
0080 std::is_convertible<From(*)[], To(*)[]>;
0081 template <typename From, typename To>
0082 constexpr inline bool is_qualification_conversion_v = is_qualification_conversion<From, To>::value;
0083
0084 namespace AdlTester {
0085 #define MAKE_ADL_TEST(what) \
0086 using std:: what; \
0087 template <typename T> using what ## _result = decltype( what (std::declval<T&&>())); \
0088
0089 MAKE_ADL_TEST(begin)
0090 MAKE_ADL_TEST(data)
0091 MAKE_ADL_TEST(size)
0092 #undef MAKE_ADL_TEST
0093 }
0094
0095
0096
0097 template <typename Range>
0098 AdlTester::begin_result<Range> adl_begin(Range &&r) { using std::begin; return begin(r); }
0099 template <typename Range>
0100 AdlTester::data_result<Range> adl_data(Range &&r) { using std::data; return data(r); }
0101 template <typename Range>
0102 AdlTester::size_result<Range> adl_size(Range &&r) { using std::size; return size(r); }
0103
0104
0105
0106 template <typename Range>
0107 using iterator_t = decltype(QSpanPrivate::adl_begin(std::declval<Range&>()));
0108 template <typename Range>
0109 using range_reference_t = q20::iter_reference_t<QSpanPrivate::iterator_t<Range>>;
0110
0111 template <typename T>
0112 class QSpanCommon {
0113 protected:
0114 template <typename Iterator>
0115 using is_compatible_iterator = std::conjunction<
0116
0117 std::is_base_of<
0118 std::random_access_iterator_tag,
0119 typename std::iterator_traits<Iterator>::iterator_category
0120 >,
0121 is_qualification_conversion<
0122 std::remove_reference_t<q20::iter_reference_t<Iterator>>,
0123 T
0124 >
0125 >;
0126 template <typename Iterator, typename End>
0127 using is_compatible_iterator_and_sentinel = std::conjunction<
0128
0129 is_compatible_iterator<Iterator>,
0130 std::negation<std::is_convertible<End, std::size_t>>
0131 >;
0132 template <typename Range, typename = void>
0133 struct is_compatible_range_helper : std::false_type {};
0134 template <typename Range>
0135 struct is_compatible_range_helper<Range, std::void_t<QSpanPrivate::iterator_t<Range>>>
0136 : is_compatible_iterator<QSpanPrivate::iterator_t<Range>> {};
0137 template <typename Range>
0138 using is_compatible_range = std::conjunction<
0139
0140 std::negation<is_qspan<Range>>,
0141 std::negation<is_std_span<Range>>,
0142 std::negation<is_std_array<Range>>,
0143 std::negation<std::is_array<q20::remove_cvref_t<Range>>>,
0144 is_compatible_range_helper<Range>
0145 >;
0146
0147
0148 template <typename Iterator>
0149 using if_compatible_iterator = std::enable_if_t<
0150 is_compatible_iterator<Iterator>::value
0151 , bool>;
0152 template <typename Iterator, typename End>
0153 using if_compatible_iterator_and_sentinel = std::enable_if_t<
0154 is_compatible_iterator_and_sentinel<Iterator, End>::value
0155 , bool>;
0156 template <typename Range>
0157 using if_compatible_range = std::enable_if_t<is_compatible_range<Range>::value, bool>;
0158 };
0159
0160 template <typename T, std::size_t E>
0161 class QSpanBase : protected QSpanCommon<T>
0162 {
0163 static_assert(E < size_t{(std::numeric_limits<qsizetype>::max)()},
0164 "QSpan only supports extents that fit into the signed size type (qsizetype).");
0165
0166 template <typename S, std::size_t N>
0167 using if_compatible_array = std::enable_if_t<
0168 N == E && is_qualification_conversion_v<S, T>
0169 , bool>;
0170
0171 template <typename S>
0172 using if_qualification_conversion = std::enable_if_t<
0173 is_qualification_conversion_v<S, T>
0174 , bool>;
0175 protected:
0176 using Base = QSpanCommon<T>;
0177
0178
0179 T *m_data;
0180 static constexpr qsizetype m_size = qsizetype(E);
0181
0182
0183
0184
0185
0186 public:
0187 template <std::size_t E2 = E, std::enable_if_t<E2 == 0, bool> = true>
0188 Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr} {}
0189
0190 template <typename It, typename Base::template if_compatible_iterator<It> = true>
0191 explicit constexpr QSpanBase(It first, qsizetype count)
0192 : m_data{q20::to_address(first)}
0193 {
0194 Q_ASSERT(count == m_size);
0195 }
0196
0197 template <typename It, typename End, typename Base::template if_compatible_iterator_and_sentinel<It, End> = true>
0198 explicit constexpr QSpanBase(It first, End last)
0199 : QSpanBase(first, last - first) {}
0200
0201 template <size_t N, std::enable_if_t<N == E, bool> = true>
0202 Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t<T> (&arr)[N]) noexcept
0203 : QSpanBase(arr, N) {}
0204
0205 template <typename S, size_t N, if_compatible_array<S, N> = true>
0206 Q_IMPLICIT constexpr QSpanBase(std::array<S, N> &arr) noexcept
0207 : QSpanBase(arr.data(), N) {}
0208
0209 template <typename S, size_t N, if_compatible_array<S, N> = true>
0210 Q_IMPLICIT constexpr QSpanBase(const std::array<S, N> &arr) noexcept
0211 : QSpanBase(arr.data(), N) {}
0212
0213 template <typename Range, typename Base::template if_compatible_range<Range> = true>
0214 Q_IMPLICIT constexpr QSpanBase(Range &&r)
0215 : QSpanBase(QSpanPrivate::adl_data(QSpanPrivate::const_propagated<T>(r)),
0216 qsizetype(QSpanPrivate::adl_size(r)))
0217 {}
0218
0219 template <typename S, if_qualification_conversion<S> = true>
0220 Q_IMPLICIT constexpr QSpanBase(QSpan<S, E> other) noexcept
0221 : QSpanBase(other.data(), other.size())
0222 {}
0223
0224 template <typename S, if_qualification_conversion<S> = true>
0225 Q_IMPLICIT constexpr QSpanBase(QSpan<S> other)
0226 : QSpanBase(other.data(), other.size())
0227 {}
0228
0229 template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
0230 Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il)
0231 : QSpanBase(il.begin(), il.size())
0232 {}
0233
0234 #ifdef __cpp_lib_span
0235 template <typename S, if_qualification_conversion<S> = true>
0236 Q_IMPLICIT constexpr QSpanBase(std::span<S, E> other) noexcept
0237 : QSpanBase(other.data(), other.size())
0238 {}
0239
0240 template <typename S, if_qualification_conversion<S> = true>
0241 Q_IMPLICIT constexpr QSpanBase(std::span<S> other)
0242 : QSpanBase(other.data(), other.size())
0243 {}
0244 #endif
0245 };
0246
0247 template <typename T>
0248 class QSpanBase<T, q20::dynamic_extent> : protected QSpanCommon<T>
0249 {
0250 template <typename S>
0251 using if_qualification_conversion = std::enable_if_t<
0252 is_qualification_conversion_v<S, T>
0253 , bool>;
0254 protected:
0255 using Base = QSpanCommon<T>;
0256
0257
0258 T *m_data;
0259 qsizetype m_size;
0260
0261
0262 public:
0263 Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr}, m_size{0} {}
0264
0265 template <typename It, typename Base::template if_compatible_iterator<It> = true>
0266 Q_IMPLICIT constexpr QSpanBase(It first, qsizetype count)
0267 : m_data{q20::to_address(first)}, m_size{count} {}
0268
0269 template <typename It, typename End, typename Base::template if_compatible_iterator_and_sentinel<It, End> = true>
0270 Q_IMPLICIT constexpr QSpanBase(It first, End last)
0271 : QSpanBase(first, last - first) {}
0272
0273 template <size_t N>
0274 Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t<T> (&arr)[N]) noexcept
0275 : QSpanBase(arr, N) {}
0276
0277 template <typename S, size_t N, if_qualification_conversion<S> = true>
0278 Q_IMPLICIT constexpr QSpanBase(std::array<S, N> &arr) noexcept
0279 : QSpanBase(arr.data(), N) {}
0280
0281 template <typename S, size_t N, if_qualification_conversion<S> = true>
0282 Q_IMPLICIT constexpr QSpanBase(const std::array<S, N> &arr) noexcept
0283 : QSpanBase(arr.data(), N) {}
0284
0285 template <typename Range, typename Base::template if_compatible_range<Range> = true>
0286 Q_IMPLICIT constexpr QSpanBase(Range &&r)
0287 : QSpanBase(QSpanPrivate::adl_data(QSpanPrivate::const_propagated<T>(r)),
0288 qsizetype(QSpanPrivate::adl_size(r)))
0289 {}
0290
0291 template <typename S, size_t N, if_qualification_conversion<S> = true>
0292 Q_IMPLICIT constexpr QSpanBase(QSpan<S, N> other) noexcept
0293 : QSpanBase(other.data(), other.size())
0294 {}
0295
0296 template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
0297 Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il) noexcept
0298 : QSpanBase(il.begin(), il.size())
0299 {}
0300
0301 #ifdef __cpp_lib_span
0302 template <typename S, size_t N, if_qualification_conversion<S> = true>
0303 Q_IMPLICIT constexpr QSpanBase(std::span<S, N> other) noexcept
0304 : QSpanBase(other.data(), other.size())
0305 {}
0306 #endif
0307 };
0308
0309 }
0310
0311 template <typename T, std::size_t E>
0312 class QSpan
0313 #ifndef Q_QDOC
0314 : private QSpanPrivate::QSpanBase<T, E>
0315 #endif
0316 {
0317 using Base = QSpanPrivate::QSpanBase<T, E>;
0318 Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
0319 [[maybe_unused]] qsizetype n = 1) const
0320 {
0321 Q_ASSERT(pos >= 0);
0322 Q_ASSERT(pos <= size());
0323 Q_ASSERT(n >= 0);
0324 Q_ASSERT(n <= size() - pos);
0325 }
0326
0327 template <std::size_t N>
0328 static constexpr bool subspan_always_succeeds_v = N <= E && E != q20::dynamic_extent;
0329 public:
0330
0331 using value_type = std::remove_cv_t<T>;
0332 #ifdef QT_COMPILER_HAS_LWG3346
0333 using iterator_concept = std::contiguous_iterator_tag;
0334 using element_type = T;
0335 #endif
0336 using size_type = qsizetype;
0337 using difference_type = qptrdiff;
0338 using pointer = T*;
0339 using const_pointer = const T*;
0340 using reference = T&;
0341 using const_reference = const T&;
0342 using iterator = pointer;
0343 using const_iterator = const_pointer;
0344 using reverse_iterator = std::reverse_iterator<iterator>;
0345 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0346 static constexpr std::size_t extent = E;
0347
0348
0349 using Base::Base;
0350 #ifdef Q_QDOC
0351 template <typename It> using if_compatible_iterator = bool;
0352 template <typename S> using if_qualification_conversion = bool;
0353 template <typename Range> using if_compatible_range = bool;
0354 template <typename It, if_compatible_iterator<It> = true> constexpr QSpan(It first, qsizetype count);
0355 template <typename It, if_compatible_iterator<It> = true> constexpr QSpan(It first, It last);
0356 template <size_t N> constexpr QSpan(q20::type_identity_t<T> (&arr)[N]) noexcept;
0357 template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::array<S, N> &arr) noexcept;
0358 template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(const std::array<S, N> &arr) noexcept;
0359 template <typename Range, if_compatible_range<Range> = true> constexpr QSpan(Range &&r);
0360 template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(QSpan<S, N> other) noexcept;
0361 template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::span<S, N> other) noexcept;
0362 constexpr QSpan(std::initializer_list<value_type> il);
0363 #endif
0364
0365
0366 [[nodiscard]] constexpr size_type size() const noexcept { return this->m_size; }
0367 [[nodiscard]] constexpr size_type size_bytes() const noexcept { return size() * sizeof(T); }
0368 [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
0369
0370
0371 [[nodiscard]] constexpr reference operator[](size_type idx) const
0372 { verify(idx); return data()[idx]; }
0373 [[nodiscard]] constexpr reference front() const { verify(); return *data(); }
0374 [[nodiscard]] constexpr reference back() const { verify(); return data()[size() - 1]; }
0375 [[nodiscard]] constexpr pointer data() const noexcept { return this->m_data; }
0376
0377
0378 [[nodiscard]] constexpr iterator begin() const noexcept { return data(); }
0379 [[nodiscard]] constexpr iterator end() const noexcept { return data() + size(); }
0380 [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return begin(); }
0381 [[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); }
0382 [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
0383 [[nodiscard]] constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
0384 [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
0385 [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); }
0386
0387
0388 template <std::size_t Count>
0389 [[nodiscard]] constexpr QSpan<T, Count> first() const
0390 noexcept(subspan_always_succeeds_v<Count>)
0391 {
0392 static_assert(Count <= E,
0393 "Count cannot be larger than the span's extent.");
0394 verify(0, Count);
0395 return QSpan<T, Count>{data(), Count};
0396 }
0397
0398 template <std::size_t Count>
0399 [[nodiscard]] constexpr QSpan<T, Count> last() const
0400 noexcept(subspan_always_succeeds_v<Count>)
0401 {
0402 static_assert(Count <= E,
0403 "Count cannot be larger than the span's extent.");
0404 verify(0, Count);
0405 return QSpan<T, Count>{data() + (size() - Count), Count};
0406 }
0407
0408 template <std::size_t Offset>
0409 [[nodiscard]] constexpr auto subspan() const
0410 noexcept(subspan_always_succeeds_v<Offset>)
0411 {
0412 static_assert(Offset <= E,
0413 "Offset cannot be larger than the span's extent.");
0414 verify(Offset, 0);
0415 if constexpr (E == q20::dynamic_extent)
0416 return QSpan<T>{data() + Offset, qsizetype(size() - Offset)};
0417 else
0418 return QSpan<T, E - Offset>{data() + Offset, qsizetype(E - Offset)};
0419 }
0420
0421 template <std::size_t Offset, std::size_t Count>
0422 [[nodiscard]] constexpr auto subspan() const
0423 noexcept(subspan_always_succeeds_v<Offset + Count>)
0424 { return subspan<Offset>().template first<Count>(); }
0425
0426 [[nodiscard]] constexpr QSpan<T> first(size_type n) const { verify(0, n); return {data(), n}; }
0427 [[nodiscard]] constexpr QSpan<T> last(size_type n) const { verify(0, n); return {data() + (size() - n), n}; }
0428 [[nodiscard]] constexpr QSpan<T> subspan(size_type pos) const { verify(pos, 0); return {data() + pos, size() - pos}; }
0429 [[nodiscard]] constexpr QSpan<T> subspan(size_type pos, size_type n) const { return subspan(pos).first(n); }
0430
0431
0432 [[nodiscard]] constexpr bool isEmpty() const noexcept { return empty(); }
0433
0434 [[nodiscard]] constexpr QSpan<T> sliced(size_type pos) const { return subspan(pos); }
0435 [[nodiscard]] constexpr QSpan<T> sliced(size_type pos, size_type n) const { return subspan(pos, n); }
0436 [[nodiscard]] constexpr QSpan<T> chopped(size_type n) const { verify(0, n); return first(size() - n); }
0437
0438 #ifdef __cpp_concepts
0439 # define QT_ONLY_IF_DYNAMIC_SPAN(DECL) \
0440 DECL requires(E == q20::dynamic_extent)
0441 #else
0442 # define QT_ONLY_IF_DYNAMIC_SPAN(DECL) \
0443 template <size_t M = E, typename = std::enable_if_t<M == q20::dynamic_extent>> DECL
0444 #endif
0445 QT_ONLY_IF_DYNAMIC_SPAN(
0446 constexpr void slice(size_type pos)
0447 )
0448 { *this = sliced(pos); }
0449 QT_ONLY_IF_DYNAMIC_SPAN(
0450 constexpr void slice(size_type pos, size_type n)
0451 )
0452 { *this = sliced(pos, n); }
0453 QT_ONLY_IF_DYNAMIC_SPAN(
0454 constexpr void chop(size_type n)
0455 )
0456 { *this = chopped(n); }
0457 #undef QT_ONLY_IF_DYNAMIC_SPAN
0458
0459 private:
0460
0461 [[nodiscard]] friend
0462 QSpan<const std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>
0463 as_bytes(QSpan s) noexcept
0464 {
0465 using R = QSpan<const std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>;
0466 return R{reinterpret_cast<const std::byte *>(s.data()), s.size_bytes()};
0467 }
0468
0469 template <typename U>
0470 using if_mutable = std::enable_if_t<!std::is_const_v<U>, bool>;
0471
0472 #ifndef Q_QDOC
0473 template <typename T2 = T, if_mutable<T2> = true>
0474 #endif
0475 [[nodiscard]] friend
0476 QSpan<std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>
0477 as_writable_bytes(QSpan s) noexcept
0478 {
0479 using R = QSpan<std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>;
0480 return R{reinterpret_cast<std::byte *>(s.data()), s.size_bytes()};
0481 }
0482 };
0483
0484
0485 template <class It, class EndOrSize>
0486 QSpan(It, EndOrSize) -> QSpan<std::remove_reference_t<q20::iter_reference_t<It>>>;
0487 template <class T, std::size_t N>
0488 QSpan(T (&)[N]) -> QSpan<T, N>;
0489 template <class T, std::size_t N>
0490 QSpan(std::array<T, N> &) -> QSpan<T, N>;
0491 template <class T, std::size_t N>
0492 QSpan(const std::array<T, N> &) -> QSpan<const T, N>;
0493 template <class R>
0494 QSpan(R&&) -> QSpan<std::remove_reference_t<QSpanPrivate::range_reference_t<R>>>;
0495
0496 QT_END_NAMESPACE
0497
0498 #endif