Warning, file /include/QtCore/qspan.h was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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 T, std::size_t E> class QSpanBase;
0048
0049 template <typename T>
0050 struct is_qspan_helper : std::false_type {};
0051 template <typename T, std::size_t E>
0052 struct is_qspan_helper<QSpan<T, E>> : std::true_type {};
0053 template <typename T, std::size_t E>
0054 struct is_qspan_helper<QSpanBase<T, E>> : std::true_type {};
0055 template <typename T>
0056 using is_qspan = is_qspan_helper<q20::remove_cvref_t<T>>;
0057
0058 template <typename T>
0059 struct is_std_span_helper : std::false_type {};
0060 #ifdef __cpp_lib_span
0061 template <typename T, std::size_t E>
0062 struct is_std_span_helper<std::span<T, E>> : std::true_type {};
0063 #endif
0064 template <typename T>
0065 using is_std_span = is_std_span_helper<q20::remove_cvref_t<T>>;
0066
0067 template <typename T>
0068 struct is_std_array_helper : std::false_type {};
0069 template <typename T, std::size_t N>
0070 struct is_std_array_helper<std::array<T, N>> : std::true_type {};
0071 template <typename T>
0072 using is_std_array = is_std_array_helper<q20::remove_cvref_t<T>>;
0073
0074 template <typename From, typename To>
0075 using is_qualification_conversion =
0076 std::is_convertible<From(*)[], To(*)[]>;
0077 template <typename From, typename To>
0078 constexpr inline bool is_qualification_conversion_v = is_qualification_conversion<From, To>::value;
0079
0080 namespace AdlTester {
0081 #define MAKE_ADL_TEST(what) \
0082 using std:: what; \
0083 template <typename T> using what ## _result = decltype( what (std::declval<T&&>())); \
0084
0085 MAKE_ADL_TEST(begin)
0086 MAKE_ADL_TEST(data)
0087 MAKE_ADL_TEST(size)
0088 #undef MAKE_ADL_TEST
0089 }
0090
0091
0092
0093 template <typename Range>
0094 AdlTester::begin_result<Range> adl_begin(Range &&r) { using std::begin; return begin(r); }
0095 template <typename Range>
0096 AdlTester::data_result<Range> adl_data(Range &&r) { using std::data; return data(r); }
0097 template <typename Range>
0098 AdlTester::size_result<Range> adl_size(Range &&r) { using std::size; return size(r); }
0099
0100
0101
0102 template <typename Range>
0103 using iterator_t = decltype(QSpanPrivate::adl_begin(std::declval<Range&>()));
0104 template <typename Range>
0105 using range_reference_t = q20::iter_reference_t<QSpanPrivate::iterator_t<Range>>;
0106
0107 template <typename T>
0108 class QSpanCommon {
0109 protected:
0110 template <typename Iterator>
0111 using is_compatible_iterator = std::conjunction<
0112
0113 std::is_base_of<
0114 std::random_access_iterator_tag,
0115 typename std::iterator_traits<Iterator>::iterator_category
0116 >,
0117 is_qualification_conversion<
0118 std::remove_reference_t<q20::iter_reference_t<Iterator>>,
0119 T
0120 >
0121 >;
0122 template <typename Iterator, typename End>
0123 using is_compatible_iterator_and_sentinel = std::conjunction<
0124
0125 is_compatible_iterator<Iterator>,
0126 std::negation<std::is_convertible<End, std::size_t>>
0127 >;
0128 template <typename Range, typename = void>
0129 struct is_compatible_range_helper : std::false_type {};
0130 template <typename Range>
0131 struct is_compatible_range_helper<Range, std::void_t<QSpanPrivate::iterator_t<Range>>>
0132 : is_compatible_iterator<QSpanPrivate::iterator_t<Range>> {};
0133 template <typename Range>
0134 using is_compatible_range = std::conjunction<
0135
0136 std::negation<is_qspan<Range>>,
0137 std::negation<is_std_span<Range>>,
0138 std::negation<is_std_array<Range>>,
0139 std::negation<std::is_array<q20::remove_cvref_t<Range>>>,
0140 is_compatible_range_helper<Range>
0141 >;
0142
0143
0144 template <typename Iterator>
0145 using if_compatible_iterator = std::enable_if_t<
0146 is_compatible_iterator<Iterator>::value
0147 , bool>;
0148 template <typename Iterator, typename End>
0149 using if_compatible_iterator_and_sentinel = std::enable_if_t<
0150 is_compatible_iterator_and_sentinel<Iterator, End>::value
0151 , bool>;
0152 template <typename Range>
0153 using if_compatible_range = std::enable_if_t<is_compatible_range<Range>::value, bool>;
0154 };
0155
0156 template <typename T, std::size_t E>
0157 class QSpanBase : protected QSpanCommon<T>
0158 {
0159 static_assert(E < size_t{(std::numeric_limits<qsizetype>::max)()},
0160 "QSpan only supports extents that fit into the signed size type (qsizetype).");
0161
0162 struct Enabled_t { explicit Enabled_t() = default; };
0163 static inline constexpr Enabled_t Enable{};
0164
0165 template <typename S, std::size_t N>
0166 using if_compatible_array = std::enable_if_t<
0167 N == E && is_qualification_conversion_v<S, T>
0168 , bool>;
0169
0170 template <typename S>
0171 using if_qualification_conversion = std::enable_if_t<
0172 is_qualification_conversion_v<S, T>
0173 , bool>;
0174 protected:
0175 using Base = QSpanCommon<T>;
0176
0177
0178 T *m_data;
0179 static constexpr qsizetype m_size = qsizetype(E);
0180
0181
0182
0183
0184
0185 public:
0186 template <std::size_t E2 = E, std::enable_if_t<E2 == 0, bool> = true>
0187 Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr} {}
0188
0189 template <typename It, typename Base::template if_compatible_iterator<It> = true>
0190 explicit constexpr QSpanBase(It first, qsizetype count)
0191 : m_data{q20::to_address(first)}
0192 {
0193 Q_ASSERT(count == m_size);
0194 }
0195
0196 template <typename It, typename End, typename Base::template if_compatible_iterator_and_sentinel<It, End> = true>
0197 explicit constexpr QSpanBase(It first, End last)
0198 : QSpanBase(first, last - first) {}
0199
0200 template <size_t N, std::enable_if_t<N == E, bool> = true>
0201 Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t<T> (&arr)[N]) noexcept
0202 : QSpanBase(arr, N) {}
0203
0204 template <typename S, size_t N, if_compatible_array<S, N> = true>
0205 Q_IMPLICIT constexpr QSpanBase(std::array<S, N> &arr) noexcept
0206 : QSpanBase(arr.data(), N) {}
0207
0208 template <typename S, size_t N, if_compatible_array<S, N> = true>
0209 Q_IMPLICIT constexpr QSpanBase(const std::array<S, N> &arr) noexcept
0210 : QSpanBase(arr.data(), N) {}
0211
0212 template <typename Range, typename Base::template if_compatible_range<Range> = true>
0213 Q_IMPLICIT constexpr QSpanBase(Range &&r)
0214 : QSpanBase(QSpanPrivate::adl_data(r),
0215 qsizetype(QSpanPrivate::adl_size(r)))
0216 {}
0217
0218 template <typename S, if_qualification_conversion<S> = true>
0219 Q_IMPLICIT constexpr QSpanBase(QSpan<S, E> other) noexcept
0220 : QSpanBase(other.data(), other.size())
0221 {}
0222
0223 template <typename S, if_qualification_conversion<S> = true>
0224 Q_IMPLICIT constexpr QSpanBase(QSpan<S> other)
0225 : QSpanBase(other.data(), other.size())
0226 {}
0227
0228 template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
0229 Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il)
0230 : QSpanBase(il.begin(), il.size())
0231 {}
0232
0233 #ifdef __cpp_lib_span
0234 template <typename S, if_qualification_conversion<S> = true>
0235 Q_IMPLICIT constexpr QSpanBase(std::span<S, E> other) noexcept
0236 : QSpanBase(other.data(), other.size())
0237 {}
0238
0239 template <typename S, if_qualification_conversion<S> = true>
0240 Q_IMPLICIT constexpr QSpanBase(std::span<S> other)
0241 : QSpanBase(other.data(), other.size())
0242 {}
0243 #endif
0244 };
0245
0246 template <typename T>
0247 class QSpanBase<T, q20::dynamic_extent> : protected QSpanCommon<T>
0248 {
0249 template <typename S>
0250 using if_qualification_conversion = std::enable_if_t<
0251 is_qualification_conversion_v<S, T>
0252 , bool>;
0253 protected:
0254 using Base = QSpanCommon<T>;
0255
0256
0257 T *m_data;
0258 qsizetype m_size;
0259
0260
0261 public:
0262 Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr}, m_size{0} {}
0263
0264 template <typename It, typename Base::template if_compatible_iterator<It> = true>
0265 Q_IMPLICIT constexpr QSpanBase(It first, qsizetype count)
0266 : m_data{q20::to_address(first)}, m_size{count} {}
0267
0268 template <typename It, typename End, typename Base::template if_compatible_iterator_and_sentinel<It, End> = true>
0269 Q_IMPLICIT constexpr QSpanBase(It first, End last)
0270 : QSpanBase(first, last - first) {}
0271
0272 template <size_t N>
0273 Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t<T> (&arr)[N]) noexcept
0274 : QSpanBase(arr, N) {}
0275
0276 template <typename S, size_t N, if_qualification_conversion<S> = true>
0277 Q_IMPLICIT constexpr QSpanBase(std::array<S, N> &arr) noexcept
0278 : QSpanBase(arr.data(), N) {}
0279
0280 template <typename S, size_t N, if_qualification_conversion<S> = true>
0281 Q_IMPLICIT constexpr QSpanBase(const std::array<S, N> &arr) noexcept
0282 : QSpanBase(arr.data(), N) {}
0283
0284 template <typename Range, typename Base::template if_compatible_range<Range> = true>
0285 Q_IMPLICIT constexpr QSpanBase(Range &&r)
0286 : QSpanBase(QSpanPrivate::adl_data(r),
0287 qsizetype(QSpanPrivate::adl_size(r)))
0288 {}
0289
0290 template <typename S, size_t N, if_qualification_conversion<S> = true>
0291 Q_IMPLICIT constexpr QSpanBase(QSpan<S, N> other) noexcept
0292 : QSpanBase(other.data(), other.size())
0293 {}
0294
0295 template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
0296 Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il) noexcept
0297 : QSpanBase(il.begin(), il.size())
0298 {}
0299
0300 #ifdef __cpp_lib_span
0301 template <typename S, size_t N, if_qualification_conversion<S> = true>
0302 Q_IMPLICIT constexpr QSpanBase(std::span<S, N> other) noexcept
0303 : QSpanBase(other.data(), other.size())
0304 {}
0305 #endif
0306 };
0307
0308 }
0309
0310 template <typename T, std::size_t E>
0311 class QSpan
0312 #ifndef Q_QDOC
0313 : private QSpanPrivate::QSpanBase<T, E>
0314 #endif
0315 {
0316 using Base = QSpanPrivate::QSpanBase<T, E>;
0317 Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
0318 [[maybe_unused]] qsizetype n = 1) const
0319 {
0320 Q_ASSERT(pos >= 0);
0321 Q_ASSERT(pos <= size());
0322 Q_ASSERT(n >= 0);
0323 Q_ASSERT(n <= size() - pos);
0324 }
0325
0326 template <std::size_t N>
0327 static constexpr bool subspan_always_succeeds_v = N <= E && E != q20::dynamic_extent;
0328 public:
0329
0330 using value_type = std::remove_cv_t<T>;
0331 #ifdef QT_COMPILER_HAS_LWG3346
0332 using iterator_concept = std::contiguous_iterator_tag;
0333 using element_type = T;
0334 #endif
0335 using size_type = qsizetype;
0336 using difference_type = qptrdiff;
0337 using pointer = T*;
0338 using const_pointer = const T*;
0339 using reference = T&;
0340 using const_reference = const T&;
0341 using iterator = pointer;
0342 using const_iterator = const_pointer;
0343 using reverse_iterator = std::reverse_iterator<iterator>;
0344 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0345 static constexpr std::size_t extent = E;
0346
0347
0348 using Base::Base;
0349 #ifdef Q_QDOC
0350 template <typename It> using if_compatible_iterator = bool;
0351 template <typename S> using if_qualification_conversion = bool;
0352 template <typename Range> using if_compatible_range = bool;
0353 template <typename It, if_compatible_iterator<It> = true> constexpr QSpan(It first, qsizetype count);
0354 template <typename It, if_compatible_iterator<It> = true> constexpr QSpan(It first, It last);
0355 template <size_t N> constexpr QSpan(q20::type_identity_t<T> (&arr)[N]) noexcept;
0356 template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::array<S, N> &arr) noexcept;
0357 template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(const std::array<S, N> &arr) noexcept;
0358 template <typename Range, if_compatible_range<Range> = true> constexpr QSpan(Range &&r);
0359 template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(QSpan<S, N> other) noexcept;
0360 template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::span<S, N> other) noexcept;
0361 constexpr QSpan(std::initializer_list<value_type> il);
0362 #endif
0363
0364
0365 [[nodiscard]] constexpr size_type size() const noexcept { return this->m_size; }
0366 [[nodiscard]] constexpr size_type size_bytes() const noexcept { return size() * sizeof(T); }
0367 [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
0368
0369
0370 [[nodiscard]] constexpr reference operator[](size_type idx) const
0371 { verify(idx); return data()[idx]; }
0372 [[nodiscard]] constexpr reference front() const { verify(); return *data(); }
0373 [[nodiscard]] constexpr reference back() const { verify(); return data()[size() - 1]; }
0374 [[nodiscard]] constexpr pointer data() const noexcept { return this->m_data; }
0375
0376
0377 [[nodiscard]] constexpr iterator begin() const noexcept { return data(); }
0378 [[nodiscard]] constexpr iterator end() const noexcept { return data() + size(); }
0379 [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return begin(); }
0380 [[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); }
0381 [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
0382 [[nodiscard]] constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
0383 [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
0384 [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); }
0385
0386
0387 template <std::size_t Count>
0388 [[nodiscard]] constexpr QSpan<T, Count> first() const
0389 noexcept(subspan_always_succeeds_v<Count>)
0390 {
0391 static_assert(Count <= E,
0392 "Count cannot be larger than the span's extent.");
0393 verify(0, Count);
0394 return QSpan<T, Count>{data(), Count};
0395 }
0396
0397 template <std::size_t Count>
0398 [[nodiscard]] constexpr QSpan<T, Count> last() const
0399 noexcept(subspan_always_succeeds_v<Count>)
0400 {
0401 static_assert(Count <= E,
0402 "Count cannot be larger than the span's extent.");
0403 verify(0, Count);
0404 return QSpan<T, Count>{data() + (size() - Count), Count};
0405 }
0406
0407 template <std::size_t Offset>
0408 [[nodiscard]] constexpr auto subspan() const
0409 noexcept(subspan_always_succeeds_v<Offset>)
0410 {
0411 static_assert(Offset <= E,
0412 "Offset cannot be larger than the span's extent.");
0413 verify(Offset, 0);
0414 if constexpr (E == q20::dynamic_extent)
0415 return QSpan<T>{data() + Offset, qsizetype(size() - Offset)};
0416 else
0417 return QSpan<T, E - Offset>{data() + Offset, qsizetype(E - Offset)};
0418 }
0419
0420 template <std::size_t Offset, std::size_t Count>
0421 [[nodiscard]] constexpr auto subspan() const
0422 noexcept(subspan_always_succeeds_v<Offset + Count>)
0423 { return subspan<Offset>().template first<Count>(); }
0424
0425 [[nodiscard]] constexpr QSpan<T> first(size_type n) const { verify(0, n); return {data(), n}; }
0426 [[nodiscard]] constexpr QSpan<T> last(size_type n) const { verify(0, n); return {data() + (size() - n), n}; }
0427 [[nodiscard]] constexpr QSpan<T> subspan(size_type pos) const { verify(pos, 0); return {data() + pos, size() - pos}; }
0428 [[nodiscard]] constexpr QSpan<T> subspan(size_type pos, size_type n) const { return subspan(pos).first(n); }
0429
0430
0431 [[nodiscard]] bool isEmpty() const noexcept { return empty(); }
0432
0433 [[nodiscard]] constexpr QSpan<T> sliced(size_type pos) const { return subspan(pos); }
0434 [[nodiscard]] constexpr QSpan<T> sliced(size_type pos, size_type n) const { return subspan(pos, n); }
0435
0436 };
0437
0438
0439 template <class It, class EndOrSize>
0440 QSpan(It, EndOrSize) -> QSpan<std::remove_reference_t<q20::iter_reference_t<It>>>;
0441 template <class T, std::size_t N>
0442 QSpan(T (&)[N]) -> QSpan<T, N>;
0443 template <class T, std::size_t N>
0444 QSpan(std::array<T, N> &) -> QSpan<T, N>;
0445 template <class T, std::size_t N>
0446 QSpan(const std::array<T, N> &) -> QSpan<const T, N>;
0447 template <class R>
0448 QSpan(R&&) -> QSpan<std::remove_reference_t<QSpanPrivate::range_reference_t<R>>>;
0449
0450 QT_END_NAMESPACE
0451
0452 #endif