Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 09:04:24

0001 // Copyright (C) 2016 The Qt Company Ltd.
0002 // Copyright (C) 2016 Intel Corporation.
0003 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0004 
0005 #ifndef QDEBUG_H
0006 #define QDEBUG_H
0007 
0008 #if 0
0009 #pragma qt_class(QtDebug)
0010 #endif
0011 
0012 #include <QtCore/qcompare.h>
0013 #include <QtCore/qcontainerfwd.h>
0014 #include <QtCore/qfloat16.h>
0015 #include <QtCore/qtextstream.h>
0016 #include <QtCore/qttypetraits.h>
0017 #include <QtCore/qtypes.h>
0018 #include <QtCore/qstring.h>
0019 #include <QtCore/qcontiguouscache.h>
0020 #include <QtCore/qsharedpointer.h>
0021 
0022 // all these have already been included by various headers above, but don't rely on indirect includes:
0023 #include <array>
0024 #include <chrono>
0025 #include <list>
0026 #include <map>
0027 #include <memory>
0028 #include <optional>
0029 #include <string>
0030 #include <string_view>
0031 #include <set>
0032 #include <tuple>
0033 #include <QtCore/q20type_traits.h>
0034 #include <utility>
0035 #include <unordered_map>
0036 #include <unordered_set>
0037 #include <vector>
0038 
0039 #if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 1
0040 #  include <QtCore/qlist.h>
0041 #  include <QtCore/qmap.h>
0042 #  include <QtCore/qset.h>
0043 #  include <QtCore/qvarlengtharray.h>
0044 #endif
0045 
0046 QT_BEGIN_NAMESPACE
0047 
0048 class QT6_ONLY(Q_CORE_EXPORT) QDebug : public QIODeviceBase
0049 {
0050     friend class QMessageLogger;
0051     friend class QDebugStateSaver;
0052     friend class QDebugStateSaverPrivate;
0053     struct Stream {
0054         enum { VerbosityShift = 29, VerbosityMask = 0x7 };
0055 
0056         explicit Stream(QIODevice *device)
0057             : ts(device)
0058         {}
0059         explicit Stream(QString *string)
0060             : ts(string, WriteOnly)
0061         {}
0062         explicit Stream(QByteArray *ba)
0063             : ts(ba, WriteOnly)
0064         {}
0065         explicit Stream(QtMsgType t)
0066             : ts(&buffer, WriteOnly),
0067               type(t),
0068               message_output(true)
0069         {}
0070         QTextStream ts;
0071         QString buffer;
0072         int ref = 1;
0073         QtMsgType type = QtDebugMsg;
0074         bool space = true;
0075         bool noQuotes = false;
0076         bool message_output = false;
0077         int verbosity = DefaultVerbosity;
0078         QMessageLogContext context;
0079     } *stream;
0080 
0081     enum Latin1Content { ContainsBinary = 0, ContainsLatin1 };
0082 
0083     QT7_ONLY(Q_CORE_EXPORT) void putUcs4(uint ucs4);
0084     QT7_ONLY(Q_CORE_EXPORT) void putString(const QChar *begin, size_t length);
0085     QT7_ONLY(Q_CORE_EXPORT) void putByteArray(const char *begin, size_t length, Latin1Content content);
0086     QT7_ONLY(Q_CORE_EXPORT) void putTimeUnit(qint64 num, qint64 den);
0087     QT7_ONLY(Q_CORE_EXPORT) void putInt128(const void *i);
0088     QT7_ONLY(Q_CORE_EXPORT) void putUInt128(const void *i);
0089     QT7_ONLY(Q_CORE_EXPORT) void putQtOrdering(QtOrderingPrivate::QtOrderingTypeFlag flags,
0090                                                Qt::partial_ordering order);
0091 
0092     template <typename...Ts>
0093     using if_streamable = std::enable_if_t<
0094             std::conjunction_v<QTypeTraits::has_ostream_operator<QDebug, Ts>...>
0095         , bool>;
0096 public:
0097     explicit QDebug(QIODevice *device) : stream(new Stream(device)) {}
0098     explicit QDebug(QString *string) : stream(new Stream(string)) {}
0099     explicit QDebug(QByteArray *bytes) : stream(new Stream(bytes)) {}
0100     explicit QDebug(QtMsgType t) : stream(new Stream(t)) {}
0101     QDebug(const QDebug &o) : stream(o.stream) { ++stream->ref; }
0102     QDebug(QDebug &&other) noexcept : stream{std::exchange(other.stream, nullptr)} {}
0103     inline QDebug &operator=(const QDebug &other);
0104     QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QDebug)
0105     ~QDebug();
0106     void swap(QDebug &other) noexcept { qt_ptr_swap(stream, other.stream); }
0107 
0108     QT7_ONLY(Q_CORE_EXPORT) QDebug &resetFormat();
0109 
0110     inline QDebug &space() { stream->space = true; stream->ts << ' '; return *this; }
0111     inline QDebug &nospace() { stream->space = false; return *this; }
0112     inline QDebug &maybeSpace() { if (stream->space) stream->ts << ' '; return *this; }
0113     inline QDebug &verbosity(int verbosityLevel) { stream->verbosity = verbosityLevel; return *this; }
0114     int verbosity() const { return stream->verbosity; }
0115     void setVerbosity(int verbosityLevel) { stream->verbosity = verbosityLevel; }
0116     enum VerbosityLevel { MinimumVerbosity = 0, DefaultVerbosity = 2, MaximumVerbosity = 7 };
0117 
0118     bool autoInsertSpaces() const { return stream->space; }
0119     void setAutoInsertSpaces(bool b) { stream->space = b; }
0120 
0121     [[nodiscard]] bool quoteStrings() const noexcept { return !stream->noQuotes; }
0122     void setQuoteStrings(bool b) { stream->noQuotes = !b; }
0123 
0124     inline QDebug &quote() { stream->noQuotes = false; return *this; }
0125     inline QDebug &noquote() { stream->noQuotes = true; return *this; }
0126     inline QDebug &maybeQuote(char c = '"') { if (!stream->noQuotes) stream->ts << c; return *this; }
0127 
0128     inline QDebug &operator<<(QChar t) { putUcs4(t.unicode()); return maybeSpace(); }
0129     inline QDebug &operator<<(bool t) { stream->ts << (t ? "true" : "false"); return maybeSpace(); }
0130     inline QDebug &operator<<(char t) { stream->ts << t; return maybeSpace(); }
0131     inline QDebug &operator<<(signed short t) { stream->ts << t; return maybeSpace(); }
0132     inline QDebug &operator<<(unsigned short t) { stream->ts << t; return maybeSpace(); }
0133     inline QDebug &operator<<(char16_t t) { return *this << QChar(t); }
0134     inline QDebug &operator<<(char32_t t) { putUcs4(t); return maybeSpace(); }
0135     inline QDebug &operator<<(signed int t) { stream->ts << t; return maybeSpace(); }
0136     inline QDebug &operator<<(unsigned int t) { stream->ts << t; return maybeSpace(); }
0137     inline QDebug &operator<<(signed long t) { stream->ts << t; return maybeSpace(); }
0138     inline QDebug &operator<<(unsigned long t) { stream->ts << t; return maybeSpace(); }
0139     inline QDebug &operator<<(qint64 t) { stream->ts << t; return maybeSpace(); }
0140     inline QDebug &operator<<(quint64 t) { stream->ts << t; return maybeSpace(); }
0141     inline QDebug &operator<<(qfloat16 t) { stream->ts << t; return maybeSpace(); }
0142     inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); }
0143     inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); }
0144     inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(t); return maybeSpace(); }
0145     inline QDebug &operator<<(const char16_t *t)  { stream->ts << QStringView(t); return maybeSpace(); }
0146     inline QDebug &operator<<(const QString & t) { putString(t.constData(), size_t(t.size())); return maybeSpace(); }
0147     inline QDebug &operator<<(QStringView s) { putString(s.data(), size_t(s.size())); return maybeSpace(); }
0148     inline QDebug &operator<<(QUtf8StringView s) { putByteArray(reinterpret_cast<const char*>(s.data()), s.size(), ContainsBinary); return maybeSpace(); }
0149     inline QDebug &operator<<(QLatin1StringView t) { putByteArray(t.latin1(), t.size(), ContainsLatin1); return maybeSpace(); }
0150     inline QDebug &operator<<(const QByteArray & t) { putByteArray(t.constData(), t.size(), ContainsBinary); return maybeSpace(); }
0151     inline QDebug &operator<<(QByteArrayView t) { putByteArray(t.constData(), t.size(), ContainsBinary); return maybeSpace(); }
0152     inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); }
0153     inline QDebug &operator<<(std::nullptr_t) { stream->ts << "(nullptr)"; return maybeSpace(); }
0154     inline QDebug &operator<<(std::nullopt_t) { stream->ts << "nullopt"; return maybeSpace(); }
0155     inline QDebug &operator<<(QTextStreamFunction f) {
0156         stream->ts << f;
0157         return *this;
0158     }
0159 
0160     inline QDebug &operator<<(QTextStreamManipulator m)
0161     { stream->ts << m; return *this; }
0162 
0163 #ifdef Q_QDOC
0164     template <typename Char, typename...Args>
0165     QDebug &operator<<(const std::basic_string<Char, Args...> &s);
0166 
0167     template <typename Char, typename...Args>
0168     QDebug &operator<<(std::basic_string_view<Char, Args...> s);
0169 #else
0170     template <typename...Args>
0171     QDebug &operator<<(const std::basic_string<char, Args...> &s)
0172     { return *this << QUtf8StringView(s); }
0173 
0174     template <typename...Args>
0175     QDebug &operator<<(std::basic_string_view<char, Args...> s)
0176     { return *this << QUtf8StringView(s); }
0177 
0178 #ifdef __cpp_char8_t
0179     template <typename...Args>
0180     QDebug &operator<<(const std::basic_string<char8_t, Args...> &s)
0181     { return *this << QUtf8StringView(s); }
0182 
0183     template <typename...Args>
0184     QDebug &operator<<(std::basic_string_view<char8_t, Args...> s)
0185     { return *this << QUtf8StringView(s); }
0186 #endif // __cpp_char8_t
0187 
0188     template <typename...Args>
0189     QDebug &operator<<(const std::basic_string<char16_t, Args...> &s)
0190     { return *this << QStringView(s); }
0191 
0192     template <typename...Args>
0193     QDebug &operator<<(std::basic_string_view<char16_t, Args...> s)
0194     { return *this << QStringView(s); }
0195 
0196     template <typename...Args>
0197     QDebug &operator<<(const std::basic_string<wchar_t, Args...> &s)
0198     {
0199         if constexpr (sizeof(wchar_t) == 2)
0200             return *this << QStringView(s);
0201         else
0202             return *this << QString::fromWCharArray(s.data(), s.size()); // ### optimize
0203     }
0204 
0205     template <typename...Args>
0206     QDebug &operator<<(std::basic_string_view<wchar_t, Args...> s)
0207     {
0208         if constexpr (sizeof(wchar_t) == 2)
0209             return *this << QStringView(s);
0210         else
0211             return *this << QString::fromWCharArray(s.data(), s.size()); // ### optimize
0212     }
0213 
0214     template <typename...Args>
0215     QDebug &operator<<(const std::basic_string<char32_t, Args...> &s)
0216     { return *this << QString::fromUcs4(s.data(), s.size()); }
0217 
0218     template <typename...Args>
0219     QDebug &operator<<(std::basic_string_view<char32_t, Args...> s)
0220     { return *this << QString::fromUcs4(s.data(), s.size()); }
0221 #endif // !Q_QDOC
0222 
0223     template <typename Rep, typename Period>
0224     QDebug &operator<<(std::chrono::duration<Rep, Period> duration)
0225     {
0226         stream->ts << duration.count();
0227         putTimeUnit(Period::num, Period::den);
0228         return maybeSpace();
0229     }
0230 
0231 #ifdef QT_SUPPORTS_INT128
0232 private:
0233     // Constrained templates so they only match q(u)int128 without conversions.
0234     // Also keeps these operators out of the ABI.
0235     template <typename T>
0236     using if_qint128 = std::enable_if_t<std::is_same_v<T, qint128>, bool>;
0237     template <typename T>
0238     using if_quint128 = std::enable_if_t<std::is_same_v<T, quint128>, bool>;
0239 public:
0240     template <typename T, if_qint128<T> = true>
0241     QDebug &operator<<(T i128) { putInt128(&i128); return maybeSpace(); }
0242     template <typename T, if_quint128<T> = true>
0243     QDebug &operator<<(T u128) { putUInt128(&u128); return maybeSpace(); }
0244 #endif // QT_SUPPORTS_INT128
0245 
0246 private:
0247     template <typename T>
0248     static void streamTypeErased(QDebug &d, const void *obj)
0249     {
0250         d << *static_cast<const T*>(obj);
0251     }
0252     using StreamTypeErased = void(*)(QDebug&, const void*);
0253     QT7_ONLY(Q_CORE_EXPORT) static QString toStringImpl(StreamTypeErased s, const void *obj);
0254     QT7_ONLY(Q_CORE_EXPORT) static QByteArray toBytesImpl(StreamTypeErased s, const void *obj);
0255     QT7_ONLY(Q_CORE_EXPORT) QDebug &putTupleLikeImplImpl(const char *ns, const char *what, size_t n,
0256                                                          StreamTypeErased *ops, const void **data);
0257 
0258     template <typename TupleLike, size_t...Is>
0259     QDebug &putTupleLikeImpl(const char *ns, const char *what, const TupleLike &t,
0260                              std::index_sequence<Is...>)
0261     {
0262         if constexpr (sizeof...(Is)) {
0263             StreamTypeErased ops[] = {
0264                 &streamTypeErased<q20::remove_cvref_t<std::tuple_element_t<Is, TupleLike>>>...
0265             };
0266             const void *data[] = {
0267                 std::addressof(std::get<Is>(t))...
0268             };
0269             return putTupleLikeImplImpl(ns, what, sizeof...(Is), ops, data);
0270         } else {
0271             return putTupleLikeImplImpl(ns, what, 0, nullptr, nullptr);
0272         }
0273     }
0274 
0275     template <typename TupleLike>
0276     QDebug &putTupleLike(const char *ns, const char *what, const TupleLike &t)
0277     {
0278         using Indexes = std::make_index_sequence<std::tuple_size_v<TupleLike>>;
0279         return putTupleLikeImpl(ns, what, t, Indexes{});
0280     }
0281 public:
0282     template <typename T>
0283     static QString toString(const T &object)
0284     {
0285         return toStringImpl(&streamTypeErased<T>, std::addressof(object));
0286     }
0287 
0288     template <typename T>
0289     static QByteArray toBytes(const T &object)
0290     {
0291         return toBytesImpl(&streamTypeErased<T>, std::addressof(object));
0292     }
0293 
0294     template <typename...Ts, if_streamable<Ts...> = true>
0295     QDebug &operator<<(const std::tuple<Ts...> &t)
0296     {
0297         return putTupleLike("std", "tuple", t);
0298     }
0299 
0300     template <typename T, if_streamable<T> = true>
0301     QDebug &operator<<(const std::optional<T> &o)
0302     {
0303         if (!o)
0304             return *this << std::nullopt;
0305         StreamTypeErased s = &streamTypeErased<std::remove_cv_t<T>>;
0306         const void *d = std::addressof(*o);
0307         return putTupleLikeImplImpl("std", "optional", 1, &s, &d);
0308     }
0309 
0310 private:
0311     template <typename T>
0312     using if_ordering_type = std::enable_if_t<QtOrderingPrivate::is_ordering_type_v<T>, bool>;
0313 
0314     template <typename T, if_ordering_type<T> = true>
0315     friend QDebug operator<<(QDebug debug, T t)
0316     {
0317         debug.putQtOrdering(QtOrderingPrivate::orderingFlagsFor(t), Qt::partial_ordering(t));
0318         return debug;
0319     }
0320 };
0321 
0322 Q_DECLARE_SHARED(QDebug)
0323 
0324 class QDebugStateSaverPrivate;
0325 class QDebugStateSaver
0326 {
0327 public:
0328     Q_NODISCARD_CTOR Q_CORE_EXPORT
0329     QDebugStateSaver(QDebug &dbg);
0330     Q_CORE_EXPORT
0331     ~QDebugStateSaver();
0332 private:
0333     Q_DISABLE_COPY(QDebugStateSaver)
0334     std::unique_ptr<QDebugStateSaverPrivate> d;
0335 };
0336 
0337 class QNoDebug
0338 {
0339 public:
0340     inline QNoDebug &operator<<(QTextStreamFunction) { return *this; }
0341     inline QNoDebug &operator<<(QTextStreamManipulator) { return *this; }
0342     inline QNoDebug &space() { return *this; }
0343     inline QNoDebug &nospace() { return *this; }
0344     inline QNoDebug &maybeSpace() { return *this; }
0345     inline QNoDebug &quote() { return *this; }
0346     inline QNoDebug &noquote() { return *this; }
0347     inline QNoDebug &maybeQuote(const char = '"') { return *this; }
0348     inline QNoDebug &verbosity(int) { return *this; }
0349 
0350     template<typename T>
0351     inline QNoDebug &operator<<(const T &) { return *this; }
0352 };
0353 
0354 inline QDebug &QDebug::operator=(const QDebug &other)
0355 {
0356     QDebug{other}.swap(*this);
0357     return *this;
0358 }
0359 
0360 namespace QtPrivate {
0361 
0362 template <typename SequentialContainer>
0363 inline QDebug printSequentialContainer(QDebug debug, const char *which, const SequentialContainer &c)
0364 {
0365     const QDebugStateSaver saver(debug);
0366     debug.nospace() << which << '(';
0367     typename SequentialContainer::const_iterator it = c.begin(), end = c.end();
0368     if (it != end) {
0369         debug << *it;
0370         ++it;
0371     }
0372     while (it != end) {
0373         debug << ", " << *it;
0374         ++it;
0375     }
0376     debug << ')';
0377     return debug;
0378 }
0379 
0380 template <typename AssociativeContainer>
0381 inline QDebug printAssociativeContainer(QDebug debug, const char *which, const AssociativeContainer &c)
0382 {
0383     const QDebugStateSaver saver(debug);
0384     debug.nospace() << which << "(";
0385     for (typename AssociativeContainer::const_iterator it = c.constBegin();
0386          it != c.constEnd(); ++it) {
0387         debug << '(' << it.key() << ", " << it.value() << ')';
0388     }
0389     debug << ')';
0390     return debug;
0391 }
0392 
0393 } // namespace QtPrivate
0394 
0395 template<typename ...T>
0396 using QDebugIfHasDebugStream =
0397     std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator<QDebug, T>...>, QDebug>;
0398 
0399 template<typename Container, typename ...T>
0400 using QDebugIfHasDebugStreamContainer =
0401     std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator_container<QDebug, Container, T>...>, QDebug>;
0402 
0403 #ifndef Q_QDOC
0404 
0405 template<typename T>
0406 inline QDebugIfHasDebugStreamContainer<QList<T>, T> operator<<(QDebug debug, const QList<T> &vec)
0407 {
0408     return QtPrivate::printSequentialContainer(std::move(debug), "QList", vec);
0409 }
0410 
0411 template<typename T, qsizetype P>
0412 inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QVarLengthArray<T, P> &vec)
0413 {
0414     return QtPrivate::printSequentialContainer(std::move(debug), "QVarLengthArray", vec);
0415 }
0416 
0417 template <typename T, typename Alloc>
0418 inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::vector<T, Alloc> &vec)
0419 {
0420     return QtPrivate::printSequentialContainer(std::move(debug), "std::vector", vec);
0421 }
0422 
0423 template <typename T, std::size_t N>
0424 inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::array<T, N> &array)
0425 {
0426     return QtPrivate::printSequentialContainer(std::move(debug), "std::array", array);
0427 }
0428 
0429 template <typename T, typename Alloc>
0430 inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::list<T, Alloc> &vec)
0431 {
0432     return QtPrivate::printSequentialContainer(std::move(debug), "std::list", vec);
0433 }
0434 
0435 template <typename T>
0436 inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, std::initializer_list<T> list)
0437 {
0438     return QtPrivate::printSequentialContainer(std::move(debug), "std::initializer_list", list);
0439 }
0440 
0441 template <typename Key, typename T, typename Compare, typename Alloc>
0442 inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::map<Key, T, Compare, Alloc> &map)
0443 {
0444     return QtPrivate::printSequentialContainer(std::move(debug), "std::map", map); // yes, sequential: *it is std::pair
0445 }
0446 
0447 template <typename Key, typename T, typename Compare, typename Alloc>
0448 inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::multimap<Key, T, Compare, Alloc> &map)
0449 {
0450     return QtPrivate::printSequentialContainer(std::move(debug), "std::multimap", map); // yes, sequential: *it is std::pair
0451 }
0452 
0453 template <typename Key, typename Compare, typename Alloc>
0454 inline QDebugIfHasDebugStream<Key> operator<<(QDebug debug, const std::multiset<Key, Compare, Alloc> &multiset)
0455 {
0456     return QtPrivate::printSequentialContainer(std::move(debug), "std::multiset", multiset);
0457 }
0458 
0459 template <typename Key, typename Compare, typename Alloc>
0460 inline QDebugIfHasDebugStream<Key> operator<<(QDebug debug, const std::set<Key, Compare, Alloc> &set)
0461 {
0462     return QtPrivate::printSequentialContainer(std::move(debug), "std::set", set);
0463 }
0464 
0465 template <typename Key, typename T, typename Hash, typename KeyEqual, typename Alloc>
0466 inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::unordered_map<Key, T, Hash, KeyEqual, Alloc> &unordered_map)
0467 {
0468     return QtPrivate::printSequentialContainer(std::move(debug), "std::unordered_map", unordered_map); // yes, sequential: *it is std::pair
0469 }
0470 
0471 template <typename Key, typename Hash, typename KeyEqual, typename Alloc>
0472 inline QDebugIfHasDebugStream<Key> operator<<(QDebug debug, const std::unordered_set<Key, Hash, KeyEqual, Alloc> &unordered_set)
0473 {
0474     return QtPrivate::printSequentialContainer(std::move(debug), "std::unordered_set", unordered_set);
0475 }
0476 
0477 template <class Key, class T>
0478 inline QDebugIfHasDebugStreamContainer<QMap<Key, T>, Key, T> operator<<(QDebug debug, const QMap<Key, T> &map)
0479 {
0480     return QtPrivate::printAssociativeContainer(std::move(debug), "QMap", map);
0481 }
0482 
0483 template <class Key, class T>
0484 inline QDebugIfHasDebugStreamContainer<QMultiMap<Key, T>, Key, T> operator<<(QDebug debug, const QMultiMap<Key, T> &map)
0485 {
0486     return QtPrivate::printAssociativeContainer(std::move(debug), "QMultiMap", map);
0487 }
0488 
0489 template <class Key, class T>
0490 inline QDebugIfHasDebugStreamContainer<QHash<Key, T>, Key, T> operator<<(QDebug debug, const QHash<Key, T> &hash)
0491 {
0492     return QtPrivate::printAssociativeContainer(std::move(debug), "QHash", hash);
0493 }
0494 
0495 template <class Key, class T>
0496 inline QDebugIfHasDebugStreamContainer<QMultiHash<Key, T>, Key, T> operator<<(QDebug debug, const QMultiHash<Key, T> &hash)
0497 {
0498     return QtPrivate::printAssociativeContainer(std::move(debug), "QMultiHash", hash);
0499 }
0500 
0501 template <class T1, class T2>
0502 inline QDebugIfHasDebugStream<T1, T2> operator<<(QDebug debug, const std::pair<T1, T2> &pair)
0503 {
0504     const QDebugStateSaver saver(debug);
0505     debug.nospace() << "std::pair(" << pair.first << ", " << pair.second << ')';
0506     return debug;
0507 }
0508 
0509 template <typename T>
0510 inline QDebugIfHasDebugStreamContainer<QSet<T>, T> operator<<(QDebug debug, const QSet<T> &set)
0511 {
0512     return QtPrivate::printSequentialContainer(std::move(debug), "QSet", set);
0513 }
0514 
0515 template <class T>
0516 inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QContiguousCache<T> &cache)
0517 {
0518     const QDebugStateSaver saver(debug);
0519     debug.nospace() << "QContiguousCache(";
0520     for (qsizetype i = cache.firstIndex(); i <= cache.lastIndex(); ++i) {
0521         debug << cache[i];
0522         if (i != cache.lastIndex())
0523             debug << ", ";
0524     }
0525     debug << ')';
0526     return debug;
0527 }
0528 
0529 #else
0530 template <class T>
0531 QDebug operator<<(QDebug debug, const QList<T> &list);
0532 
0533 template <class T, qsizetype P>
0534 QDebug operator<<(QDebug debug, const QVarLengthArray<T, P> &array);
0535 
0536 template <typename T, typename Alloc>
0537 QDebug operator<<(QDebug debug, const std::vector<T, Alloc> &vec);
0538 
0539 template <typename T, std::size_t N>
0540 QDebug operator<<(QDebug debug, const std::array<T, N> &array);
0541 
0542 template <typename T, typename Alloc>
0543 QDebug operator<<(QDebug debug, const std::list<T, Alloc> &vec);
0544 
0545 template <typename Key, typename T, typename Compare, typename Alloc>
0546 QDebug operator<<(QDebug debug, const std::map<Key, T, Compare, Alloc> &map);
0547 
0548 template <typename Key, typename T, typename Compare, typename Alloc>
0549 QDebug operator<<(QDebug debug, const std::multimap<Key, T, Compare, Alloc> &map);
0550 
0551 template <class Key, class T>
0552 QDebug operator<<(QDebug debug, const QMap<Key, T> &map);
0553 
0554 template <class Key, class T>
0555 QDebug operator<<(QDebug debug, const QMultiMap<Key, T> &map);
0556 
0557 template <class Key, class T>
0558 QDebug operator<<(QDebug debug, const QHash<Key, T> &hash);
0559 
0560 template <class Key, class T>
0561 QDebug operator<<(QDebug debug, const QMultiHash<Key, T> &hash);
0562 
0563 template <typename T>
0564 QDebug operator<<(QDebug debug, const QSet<T> &set);
0565 
0566 template <class T1, class T2>
0567 QDebug operator<<(QDebug debug, const std::pair<T1, T2> &pair);
0568 
0569 template <typename T>
0570 QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache);
0571 
0572 template <typename Key, typename Compare, typename Alloc>
0573 QDebug operator<<(QDebug debug, const std::multiset<Key, Compare, Alloc> &multiset);
0574 
0575 template <typename Key, typename Compare, typename Alloc>
0576 QDebug operator<<(QDebug debug, const std::set<Key, Compare, Alloc> &set);
0577 
0578 template <typename Key, typename T, typename Hash, typename KeyEqual, typename Alloc>
0579 QDebug operator<<(QDebug debug, const std::unordered_map<Key, T, Hash, KeyEqual, Alloc> &unordered_map);
0580 
0581 template <typename Key, typename Hash, typename KeyEqual, typename Alloc>
0582 QDebug operator<<(QDebug debug, const std::unordered_set<Key, Hash, KeyEqual, Alloc> &unordered_set);
0583 
0584 #endif // Q_QDOC
0585 
0586 template <class T>
0587 inline QDebug operator<<(QDebug debug, const QSharedPointer<T> &ptr)
0588 {
0589     QDebugStateSaver saver(debug);
0590     debug.nospace() << "QSharedPointer(" << ptr.data() << ")";
0591     return debug;
0592 }
0593 
0594 template <typename T, typename Tag> class QTaggedPointer;
0595 
0596 template <typename T, typename Tag>
0597 inline QDebug operator<<(QDebug debug, const QTaggedPointer<T, Tag> &ptr)
0598 {
0599     QDebugStateSaver saver(debug);
0600     debug.nospace() << "QTaggedPointer(" << ptr.pointer() << ", " << ptr.tag() << ")";
0601     return debug;
0602 }
0603 
0604 Q_CORE_EXPORT QDebug qt_QMetaEnum_debugOperator(QDebug&, qint64 value, const QMetaObject *meta, const char *name);
0605 Q_CORE_EXPORT QDebug qt_QMetaEnum_flagDebugOperator(QDebug &dbg, quint64 value, const QMetaObject *meta, const char *name);
0606 Q_CORE_EXPORT void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, uint value);
0607 Q_CORE_EXPORT void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, quint64 value);
0608 
0609 template <typename Int>
0610 void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, Int value)
0611 {
0612     static_assert(std::is_unsigned_v<Int>,
0613             "Cast value to an unsigned type before calling this function");
0614     const QDebugStateSaver saver(debug);
0615     debug.resetFormat();
0616     debug.nospace() << "QFlags(" << Qt::hex << Qt::showbase;
0617     bool needSeparator = false;
0618     for (size_t i = 0; i < sizeofT * 8; ++i) {
0619         if (value & (Int(1) << i)) {
0620             if (needSeparator)
0621                 debug << '|';
0622             else
0623                 needSeparator = true;
0624             debug << (Int(1) << i);
0625         }
0626     }
0627     debug << ')';
0628 }
0629 
0630 template <class Flags,
0631           std::enable_if_t<QtPrivate::IsQFlags<Flags>::value, bool> = true>
0632 inline QDebug operator<<(QDebug debug, Flags flags)
0633 {
0634     using T = typename Flags::enum_type;
0635     using UInt = typename QIntegerForSizeof<T>::Unsigned;
0636 #if !defined(QT_NO_QOBJECT)
0637     if constexpr (QtPrivate::IsQEnumHelper<T>::Value || QtPrivate::IsQEnumHelper<Flags>::Value) {
0638         // if QFlags<T> is a Q_FLAG, we always zero-extend; if not, we need to
0639         // allow it to sign-extend if it is signed (see QMetaEnum::valueToKeys)
0640         using Int = std::conditional_t<QtPrivate::IsQEnumHelper<Flags>::Value, UInt,
0641                                        std::underlying_type_t<T>>;
0642         const QMetaObject *obj = qt_getEnumMetaObject(T());
0643         const char *name = qt_getEnumName(T());
0644         return qt_QMetaEnum_flagDebugOperator(debug, Int(flags.toInt()), obj, name);
0645     } else
0646 #endif
0647     {
0648         qt_QMetaEnum_flagDebugOperator(debug, sizeof(T), UInt(flags.toInt()));
0649         return debug;
0650     }
0651 }
0652 
0653 #ifdef Q_QDOC
0654 template <typename T>
0655 QDebug operator<<(QDebug debug, const QFlags<T> &flags);
0656 #endif // Q_QDOC
0657 
0658 #if !defined(QT_NO_QOBJECT) && !defined(Q_QDOC)
0659 // Debugging of plain enums. There are three cases:
0660 //  1) the enum is part of a Q_DECLARE_FLAGS and there's a Q_FLAG for that
0661 //     -> debugs as that QFlags (even if a Q_ENUM is present)
0662 //  2) the enum is declared a Q_ENUM but is not part of a Q_DECLARE_FLAGS
0663 //     -> debugs via qt_QMetaEnum_debugOperator()
0664 //  3) the enum is not associated with a QMetaObject
0665 //     -> no streaming
0666 // To avoid ambiguity in overload resolution, the template conditions are
0667 // mutually exclusive.
0668 
0669 namespace QtPrivate {
0670 template <typename T, bool IsEnum = std::is_enum_v<T>, bool = sizeof(T) <= sizeof(quint64)>
0671 struct EnumHasQFlag { static constexpr bool Value = false; };
0672 template <typename T> struct EnumHasQFlag<T, true, true> : QtPrivate::IsQEnumHelper<QFlags<T>> {};
0673 
0674 template <typename T, bool IsEnum = std::is_enum_v<T>, bool HasQFlag = EnumHasQFlag<T>::Value>
0675 struct EnumHasQEnum { static constexpr bool Value = false; };
0676 template <typename T> struct EnumHasQEnum<T, true, false> : QtPrivate::IsQEnumHelper<T> {};
0677 }
0678 
0679 template <typename T>
0680 std::enable_if_t<QtPrivate::EnumHasQFlag<T>::Value, QDebug> // case 1
0681 operator<<(QDebug debug, T flag)
0682 {
0683     return debug << QFlags(flag);
0684 }
0685 
0686 template<typename T>
0687 std::enable_if_t<QtPrivate::EnumHasQEnum<T>::Value, QDebug> // case 2
0688 operator<<(QDebug dbg, T value)
0689 {
0690     const QMetaObject *obj = qt_getEnumMetaObject(value);
0691     const char *name = qt_getEnumName(value);
0692     return qt_QMetaEnum_debugOperator(dbg, static_cast<typename std::underlying_type<T>::type>(value), obj, name);
0693 }
0694 #endif // !QT_NO_QOBJECT && !Q_QDOC
0695 
0696 inline QDebug operator<<(QDebug debug, QKeyCombination combination)
0697 {
0698     QDebugStateSaver saver(debug);
0699     debug.nospace() << "QKeyCombination("
0700                     << combination.keyboardModifiers()
0701                     << ", "
0702                     << combination.key()
0703                     << ")";
0704     return debug;
0705 }
0706 
0707 #ifdef Q_OS_DARWIN
0708 
0709 // We provide QDebug stream operators for commonly used Core Foundation
0710 // and Core Graphics types, as well as NSObject. Additional CF/CG types
0711 // may be added by the user, using Q_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE.
0712 
0713 #define QT_FOR_EACH_CORE_FOUNDATION_TYPE(F) \
0714     F(CFArray) \
0715     F(CFURL) \
0716     F(CFData) \
0717     F(CFNumber) \
0718     F(CFDictionary) \
0719     F(CFLocale) \
0720     F(CFDate) \
0721     F(CFBoolean) \
0722     F(CFTimeZone) \
0723 
0724 #define QT_FOR_EACH_MUTABLE_CORE_FOUNDATION_TYPE(F) \
0725     F(CFError) \
0726     F(CFBundle) \
0727 
0728 #define QT_FOR_EACH_CORE_GRAPHICS_TYPE(F) \
0729     F(CGPath) \
0730 
0731 #define QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(F) \
0732     F(CGColorSpace) \
0733     F(CGImage) \
0734     F(CGFont) \
0735     F(CGColor) \
0736 
0737 #define QT_FORWARD_DECLARE_CF_TYPE(type) Q_FORWARD_DECLARE_CF_TYPE(type);
0738 #define QT_FORWARD_DECLARE_MUTABLE_CF_TYPE(type) Q_FORWARD_DECLARE_MUTABLE_CF_TYPE(type);
0739 #define QT_FORWARD_DECLARE_CG_TYPE(type) Q_FORWARD_DECLARE_CG_TYPE(type);
0740 #define QT_FORWARD_DECLARE_MUTABLE_CG_TYPE(type) Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(type);
0741 
0742 QT_END_NAMESPACE
0743 Q_FORWARD_DECLARE_CF_TYPE(CFString);
0744 struct objc_object;
0745 Q_FORWARD_DECLARE_OBJC_CLASS(NSObject);
0746 QT_FOR_EACH_CORE_FOUNDATION_TYPE(QT_FORWARD_DECLARE_CF_TYPE)
0747 QT_FOR_EACH_MUTABLE_CORE_FOUNDATION_TYPE(QT_FORWARD_DECLARE_MUTABLE_CF_TYPE)
0748 QT_FOR_EACH_CORE_GRAPHICS_TYPE(QT_FORWARD_DECLARE_CG_TYPE)
0749 QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_FORWARD_DECLARE_MUTABLE_CG_TYPE)
0750 QT_BEGIN_NAMESPACE
0751 
0752 #define QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType) \
0753     Q_CORE_EXPORT QDebug operator<<(QDebug, CFType##Ref);
0754 
0755 #define Q_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType) \
0756     QDebug operator<<(QDebug debug, CFType##Ref ref) \
0757     { \
0758         if (!ref) \
0759             return debug << QT_STRINGIFY(CFType) "Ref(0x0)"; \
0760         if (CFStringRef description = CFCopyDescription(ref)) { \
0761             QDebugStateSaver saver(debug); \
0762             debug.noquote() << description; \
0763             CFRelease(description); \
0764         } \
0765         return debug; \
0766     }
0767 
0768 // Defined in qcore_mac_objc.mm
0769 #if defined(__OBJC__)
0770 Q_CORE_EXPORT QDebug operator<<(QDebug, id);
0771 #endif
0772 Q_CORE_EXPORT QDebug operator<<(QDebug, objc_object *);
0773 Q_CORE_EXPORT QDebug operator<<(QDebug, const NSObject *);
0774 Q_CORE_EXPORT QDebug operator<<(QDebug, CFStringRef);
0775 
0776 QT_FOR_EACH_CORE_FOUNDATION_TYPE(QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE)
0777 QT_FOR_EACH_MUTABLE_CORE_FOUNDATION_TYPE(QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE)
0778 QT_FOR_EACH_CORE_GRAPHICS_TYPE(QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE)
0779 QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE)
0780 
0781 #undef QT_FORWARD_DECLARE_CF_TYPE
0782 #undef QT_FORWARD_DECLARE_MUTABLE_CF_TYPE
0783 #undef QT_FORWARD_DECLARE_CG_TYPE
0784 #undef QT_FORWARD_DECLARE_MUTABLE_CG_TYPE
0785 
0786 #endif // Q_OS_DARWIN
0787 
0788 QT_END_NAMESPACE
0789 
0790 #endif // QDEBUG_H