Back to home page

EIC code displayed by LXR

 
 

    


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 // Copyright (C) 2023 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
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 // like std::dynamic_extent
0025 namespace q20 {
0026     inline constexpr auto dynamic_extent = std::size_t(-1);
0027 } // namespace q20
0028 
0029 QT_BEGIN_INCLUDE_NAMESPACE
0030 #ifdef __cpp_lib_span
0031 #ifdef __cpp_lib_concepts
0032 namespace std::ranges {
0033 // Officially, these are defined in <ranges>, but that is a heavy-hitter header.
0034 // OTOH, <span> must specialize these variable templates, too, so we assume that
0035 // <span> includes some meaningful subset of <ranges> and just go ahead and use them:
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 } // namespace std::ranges
0041 #endif // __cpp_lib_concepts
0042 #endif // __cpp_lib_span
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 // __cpp_lib_span
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(*)[]>; // https://eel.is/c++draft/span.cons#note-1
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; /* bring into scope */ \
0083     template <typename T> using what ## _result = decltype( what (std::declval<T&&>())); \
0084     /* end */
0085 MAKE_ADL_TEST(begin)
0086 MAKE_ADL_TEST(data)
0087 MAKE_ADL_TEST(size)
0088 #undef MAKE_ADL_TEST
0089 }
0090 
0091 // Replacements for std::ranges::XXX(), but only bringing in ADL XXX()s,
0092 // not doing the extra work C++20 requires
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 // Replacement for std::ranges::iterator_t (which depends on C++20 std::ranges::begin)
0101 // This one uses adl_begin() instead.
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             // ### C++20: extend to contiguous_iteratorss
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             // ### C++20: extend to contiguous_iterators and real sentinels
0125             is_compatible_iterator<Iterator>,
0126             std::negation<std::is_convertible<End, std::size_t>>
0127         >;
0128     template <typename Range, typename = void> // wrap use of SFINAE-unfriendly iterator_t:
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             // ### C++20: extend to contiguous_iterators
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     // constraints
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 }; // class QSpanCommon
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     // data members:
0178     T *m_data;
0179     static constexpr qsizetype m_size = qsizetype(E);
0180 
0181     // types and constants:
0182     // (in QSpan only)
0183 
0184     // constructors (need to be public d/t the way ctor inheriting works):
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),  // no forward<>() here (std doesn't have it, either)
0215                     qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>()
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 // __cpp_lib_span
0244 }; // class QSpanBase (fixed extent)
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     // data members:
0257     T *m_data;
0258     qsizetype m_size;
0259 
0260     // constructors (need to be public d/t the way ctor inheriting works):
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),  // no forward<>() here (std doesn't have it, either)
0287                     qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>()
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 // __cpp_lib_span
0306 }; // class QSpanBase (dynamic extent)
0307 
0308 } // namespace QSpanPrivate
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     // constants and types
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;               // difference to std::span
0336     using difference_type = qptrdiff;          // difference to std::span
0337     using pointer = T*;
0338     using const_pointer = const T*;
0339     using reference = T&;
0340     using const_reference = const T&;
0341     using iterator = pointer;                  // implementation-defined choice
0342     using const_iterator = const_pointer;      // implementation-defined choice
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     // [span.cons], constructors, copy, and assignment
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 // Q_QDOC
0363 
0364     // [span.obs]
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     // [span.elem]
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     // [span.iterators]
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     // [span.sub]
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     // Qt-compatibility API:
0431     [[nodiscard]] bool isEmpty() const noexcept { return empty(); }
0432     // nullary first()/last() clash with first<>() and last<>(), so they're not provided for QSpan
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 }; // class QSpan
0437 
0438 // [span.deduct]
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 // QSPAN_H