1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QDEBUG_H
6#define QDEBUG_H
7
8#if 0
9#pragma qt_class(QtDebug)
10#endif
11
12#include <QtCore/qcontainerfwd.h>
13#include <QtCore/qtextstream.h>
14#include <QtCore/qttypetraits.h>
15#include <QtCore/qtypes.h>
16#include <QtCore/qstring.h>
17#include <QtCore/qcontiguouscache.h>
18#include <QtCore/qsharedpointer.h>
19
20// all these have already been included by various headers above, but don't rely on indirect includes:
21#include <chrono>
22#include <list>
23#include <map>
24#include <memory>
25#include <optional>
26#include <string>
27#include <string_view>
28#include <utility>
29#include <vector>
30
31#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 1
32# include <QtCore/qlist.h>
33# include <QtCore/qmap.h>
34# include <QtCore/qset.h>
35# include <QtCore/qvarlengtharray.h>
36#endif
37
38QT_BEGIN_NAMESPACE
39
40class QT6_ONLY(Q_CORE_EXPORT) QDebug : public QIODeviceBase
41{
42 friend class QMessageLogger;
43 friend class QDebugStateSaver;
44 friend class QDebugStateSaverPrivate;
45 struct Stream {
46 enum { VerbosityShift = 29, VerbosityMask = 0x7 };
47
48 explicit Stream(QIODevice *device)
49 : ts(device)
50 {}
51 explicit Stream(QString *string)
52 : ts(string, WriteOnly)
53 {}
54 explicit Stream(QtMsgType t)
55 : ts(&buffer, WriteOnly),
56 type(t),
57 message_output(true)
58 {}
59 QTextStream ts;
60 QString buffer;
61 int ref = 1;
62 QtMsgType type = QtDebugMsg;
63 bool space = true;
64 bool noQuotes = false;
65 bool message_output = false;
66 int verbosity = DefaultVerbosity;
67 QMessageLogContext context;
68 } *stream;
69
70 enum Latin1Content { ContainsBinary = 0, ContainsLatin1 };
71
72 QT7_ONLY(Q_CORE_EXPORT) void putUcs4(uint ucs4);
73 QT7_ONLY(Q_CORE_EXPORT) void putString(const QChar *begin, size_t length);
74 QT7_ONLY(Q_CORE_EXPORT) void putByteArray(const char *begin, size_t length, Latin1Content content);
75 QT7_ONLY(Q_CORE_EXPORT) void putTimeUnit(qint64 num, qint64 den);
76 QT7_ONLY(Q_CORE_EXPORT) void putInt128(const void *i);
77 QT7_ONLY(Q_CORE_EXPORT) void putUInt128(const void *i);
78public:
79 explicit QDebug(QIODevice *device) : stream(new Stream(device)) {}
80 explicit QDebug(QString *string) : stream(new Stream(string)) {}
81 explicit QDebug(QtMsgType t) : stream(new Stream(t)) {}
82 QDebug(const QDebug &o) : stream(o.stream) { ++stream->ref; }
83 QDebug(QDebug &&other) noexcept : stream{std::exchange(obj&: other.stream, new_val: nullptr)} {}
84 inline QDebug &operator=(const QDebug &other);
85 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QDebug)
86 ~QDebug();
87 void swap(QDebug &other) noexcept { qt_ptr_swap(lhs&: stream, rhs&: other.stream); }
88
89 QT7_ONLY(Q_CORE_EXPORT) QDebug &resetFormat();
90
91 inline QDebug &space() { stream->space = true; stream->ts << ' '; return *this; }
92 inline QDebug &nospace() { stream->space = false; return *this; }
93 inline QDebug &maybeSpace() { if (stream->space) stream->ts << ' '; return *this; }
94 inline QDebug &verbosity(int verbosityLevel) { stream->verbosity = verbosityLevel; return *this; }
95 int verbosity() const { return stream->verbosity; }
96 void setVerbosity(int verbosityLevel) { stream->verbosity = verbosityLevel; }
97 enum VerbosityLevel { MinimumVerbosity = 0, DefaultVerbosity = 2, MaximumVerbosity = 7 };
98
99 bool autoInsertSpaces() const { return stream->space; }
100 void setAutoInsertSpaces(bool b) { stream->space = b; }
101
102 [[nodiscard]] bool quoteStrings() const noexcept { return !stream->noQuotes; }
103 void setQuoteStrings(bool b) { stream->noQuotes = !b; }
104
105 inline QDebug &quote() { stream->noQuotes = false; return *this; }
106 inline QDebug &noquote() { stream->noQuotes = true; return *this; }
107 inline QDebug &maybeQuote(char c = '"') { if (!stream->noQuotes) stream->ts << c; return *this; }
108
109 inline QDebug &operator<<(QChar t) { putUcs4(ucs4: t.unicode()); return maybeSpace(); }
110 inline QDebug &operator<<(bool t) { stream->ts << (t ? "true" : "false"); return maybeSpace(); }
111 inline QDebug &operator<<(char t) { stream->ts << t; return maybeSpace(); }
112 inline QDebug &operator<<(signed short t) { stream->ts << t; return maybeSpace(); }
113 inline QDebug &operator<<(unsigned short t) { stream->ts << t; return maybeSpace(); }
114 inline QDebug &operator<<(char16_t t) { return *this << QChar(t); }
115 inline QDebug &operator<<(char32_t t) { putUcs4(ucs4: t); return maybeSpace(); }
116 inline QDebug &operator<<(signed int t) { stream->ts << t; return maybeSpace(); }
117 inline QDebug &operator<<(unsigned int t) { stream->ts << t; return maybeSpace(); }
118 inline QDebug &operator<<(signed long t) { stream->ts << t; return maybeSpace(); }
119 inline QDebug &operator<<(unsigned long t) { stream->ts << t; return maybeSpace(); }
120 inline QDebug &operator<<(qint64 t) { stream->ts << t; return maybeSpace(); }
121 inline QDebug &operator<<(quint64 t) { stream->ts << t; return maybeSpace(); }
122 inline QDebug &operator<<(qfloat16 t) { stream->ts << t; return maybeSpace(); }
123 inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); }
124 inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); }
125 inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(utf8: t); return maybeSpace(); }
126 inline QDebug &operator<<(const char16_t *t) { stream->ts << QStringView(t); return maybeSpace(); }
127 inline QDebug &operator<<(const QString & t) { putString(begin: t.constData(), length: size_t(t.size())); return maybeSpace(); }
128 inline QDebug &operator<<(QStringView s) { putString(begin: s.data(), length: size_t(s.size())); return maybeSpace(); }
129 inline QDebug &operator<<(QUtf8StringView s) { putByteArray(begin: reinterpret_cast<const char*>(s.data()), length: s.size(), content: ContainsBinary); return maybeSpace(); }
130 inline QDebug &operator<<(QLatin1StringView t) { putByteArray(begin: t.latin1(), length: t.size(), content: ContainsLatin1); return maybeSpace(); }
131 inline QDebug &operator<<(const QByteArray & t) { putByteArray(begin: t.constData(), length: t.size(), content: ContainsBinary); return maybeSpace(); }
132 inline QDebug &operator<<(QByteArrayView t) { putByteArray(begin: t.constData(), length: t.size(), content: ContainsBinary); return maybeSpace(); }
133 inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); }
134 inline QDebug &operator<<(std::nullptr_t) { stream->ts << "(nullptr)"; return maybeSpace(); }
135 inline QDebug &operator<<(std::nullopt_t) { stream->ts << "nullopt"; return maybeSpace(); }
136 inline QDebug &operator<<(QTextStreamFunction f) {
137 stream->ts << f;
138 return *this;
139 }
140
141 inline QDebug &operator<<(QTextStreamManipulator m)
142 { stream->ts << m; return *this; }
143
144#ifdef Q_QDOC
145 template <typename Char, typename...Args>
146 QDebug &operator<<(const std::basic_string<Char, Args...> &s);
147
148 template <typename Char, typename...Args>
149 QDebug &operator<<(std::basic_string_view<Char, Args...> s);
150#else
151 template <typename...Args>
152 QDebug &operator<<(const std::basic_string<char, Args...> &s)
153 { return *this << QUtf8StringView(s); }
154
155 template <typename...Args>
156 QDebug &operator<<(std::basic_string_view<char, Args...> s)
157 { return *this << QUtf8StringView(s); }
158
159#ifdef __cpp_char8_t
160 template <typename...Args>
161 QDebug &operator<<(const std::basic_string<char8_t, Args...> &s)
162 { return *this << QUtf8StringView(s); }
163
164 template <typename...Args>
165 QDebug &operator<<(std::basic_string_view<char8_t, Args...> s)
166 { return *this << QUtf8StringView(s); }
167#endif // __cpp_char8_t
168
169 template <typename...Args>
170 QDebug &operator<<(const std::basic_string<char16_t, Args...> &s)
171 { return *this << QStringView(s); }
172
173 template <typename...Args>
174 QDebug &operator<<(std::basic_string_view<char16_t, Args...> s)
175 { return *this << QStringView(s); }
176
177 template <typename...Args>
178 QDebug &operator<<(const std::basic_string<wchar_t, Args...> &s)
179 {
180 if constexpr (sizeof(wchar_t) == 2)
181 return *this << QStringView(s);
182 else
183 return *this << QString::fromWCharArray(string: s.data(), size: s.size()); // ### optimize
184 }
185
186 template <typename...Args>
187 QDebug &operator<<(std::basic_string_view<wchar_t, Args...> s)
188 {
189 if constexpr (sizeof(wchar_t) == 2)
190 return *this << QStringView(s);
191 else
192 return *this << QString::fromWCharArray(string: s.data(), size: s.size()); // ### optimize
193 }
194
195 template <typename...Args>
196 QDebug &operator<<(const std::basic_string<char32_t, Args...> &s)
197 { return *this << QString::fromUcs4(s.data(), s.size()); }
198
199 template <typename...Args>
200 QDebug &operator<<(std::basic_string_view<char32_t, Args...> s)
201 { return *this << QString::fromUcs4(s.data(), s.size()); }
202#endif // !Q_QDOC
203
204 template <typename Rep, typename Period>
205 QDebug &operator<<(std::chrono::duration<Rep, Period> duration)
206 {
207 stream->ts << duration.count();
208 putTimeUnit(num: Period::num, den: Period::den);
209 return maybeSpace();
210 }
211
212#ifdef QT_SUPPORTS_INT128
213private:
214 // Constrained templates so they only match q(u)int128 without conversions.
215 // Also keeps these operators out of the ABI.
216 template <typename T>
217 using if_qint128 = std::enable_if_t<std::is_same_v<T, qint128>, bool>;
218 template <typename T>
219 using if_quint128 = std::enable_if_t<std::is_same_v<T, quint128>, bool>;
220public:
221 template <typename T, if_qint128<T> = true>
222 QDebug &operator<<(T i128) { putInt128(i: &i128); return maybeSpace(); }
223 template <typename T, if_quint128<T> = true>
224 QDebug &operator<<(T u128) { putUInt128(i: &u128); return maybeSpace(); }
225#endif // QT_SUPPORTS_INT128
226
227private:
228 template <typename T>
229 static void streamTypeErased(QDebug &d, const void *obj)
230 {
231 d << *static_cast<const T*>(obj);
232 }
233 using StreamTypeErased = void(*)(QDebug&, const void*);
234 QT7_ONLY(Q_CORE_EXPORT) static QString toStringImpl(StreamTypeErased s, const void *obj);
235public:
236 template <typename T>
237 static QString toString(const T &object)
238 {
239 return toStringImpl(s: &streamTypeErased<T>, obj: std::addressof(object));
240 }
241};
242
243Q_DECLARE_SHARED(QDebug)
244
245class QDebugStateSaverPrivate;
246class QDebugStateSaver
247{
248public:
249 Q_NODISCARD_CTOR Q_CORE_EXPORT
250 QDebugStateSaver(QDebug &dbg);
251 Q_CORE_EXPORT
252 ~QDebugStateSaver();
253private:
254 Q_DISABLE_COPY(QDebugStateSaver)
255 QScopedPointer<QDebugStateSaverPrivate> d;
256};
257
258class QNoDebug
259{
260public:
261 inline QNoDebug &operator<<(QTextStreamFunction) { return *this; }
262 inline QNoDebug &operator<<(QTextStreamManipulator) { return *this; }
263 inline QNoDebug &space() { return *this; }
264 inline QNoDebug &nospace() { return *this; }
265 inline QNoDebug &maybeSpace() { return *this; }
266 inline QNoDebug &quote() { return *this; }
267 inline QNoDebug &noquote() { return *this; }
268 inline QNoDebug &maybeQuote(const char = '"') { return *this; }
269 inline QNoDebug &verbosity(int) { return *this; }
270
271 template<typename T>
272 inline QNoDebug &operator<<(const T &) { return *this; }
273};
274
275inline QDebug &QDebug::operator=(const QDebug &other)
276{
277 QDebug{other}.swap(other&: *this);
278 return *this;
279}
280
281namespace QtPrivate {
282
283template <typename SequentialContainer>
284inline QDebug printSequentialContainer(QDebug debug, const char *which, const SequentialContainer &c)
285{
286 const QDebugStateSaver saver(debug);
287 debug.nospace() << which << '(';
288 typename SequentialContainer::const_iterator it = c.begin(), end = c.end();
289 if (it != end) {
290 debug << *it;
291 ++it;
292 }
293 while (it != end) {
294 debug << ", " << *it;
295 ++it;
296 }
297 debug << ')';
298 return debug;
299}
300
301template <typename AssociativeContainer>
302inline QDebug printAssociativeContainer(QDebug debug, const char *which, const AssociativeContainer &c)
303{
304 const QDebugStateSaver saver(debug);
305 debug.nospace() << which << "(";
306 for (typename AssociativeContainer::const_iterator it = c.constBegin();
307 it != c.constEnd(); ++it) {
308 debug << '(' << it.key() << ", " << it.value() << ')';
309 }
310 debug << ')';
311 return debug;
312}
313
314} // namespace QtPrivate
315
316template<typename ...T>
317using QDebugIfHasDebugStream =
318 std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator<QDebug, T>...>, QDebug>;
319
320template<typename Container, typename ...T>
321using QDebugIfHasDebugStreamContainer =
322 std::enable_if_t<std::conjunction_v<QTypeTraits::has_ostream_operator_container<QDebug, Container, T>...>, QDebug>;
323
324#ifndef Q_QDOC
325
326template<typename T>
327inline QDebugIfHasDebugStreamContainer<QList<T>, T> operator<<(QDebug debug, const QList<T> &vec)
328{
329 return QtPrivate::printSequentialContainer(std::move(debug), "QList", vec);
330}
331
332template<typename T, qsizetype P>
333inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QVarLengthArray<T, P> &vec)
334{
335 return QtPrivate::printSequentialContainer(std::move(debug), "QVarLengthArray", vec);
336}
337
338template <typename T, typename Alloc>
339inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::vector<T, Alloc> &vec)
340{
341 return QtPrivate::printSequentialContainer(std::move(debug), "std::vector", vec);
342}
343
344template <typename T, typename Alloc>
345inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::list<T, Alloc> &vec)
346{
347 return QtPrivate::printSequentialContainer(std::move(debug), "std::list", vec);
348}
349
350template <typename T>
351inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, std::initializer_list<T> list)
352{
353 return QtPrivate::printSequentialContainer(std::move(debug), "std::initializer_list", list);
354}
355
356template <typename Key, typename T, typename Compare, typename Alloc>
357inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::map<Key, T, Compare, Alloc> &map)
358{
359 return QtPrivate::printSequentialContainer(std::move(debug), "std::map", map); // yes, sequential: *it is std::pair
360}
361
362template <typename Key, typename T, typename Compare, typename Alloc>
363inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::multimap<Key, T, Compare, Alloc> &map)
364{
365 return QtPrivate::printSequentialContainer(std::move(debug), "std::multimap", map); // yes, sequential: *it is std::pair
366}
367
368template <class Key, class T>
369inline QDebugIfHasDebugStreamContainer<QMap<Key, T>, Key, T> operator<<(QDebug debug, const QMap<Key, T> &map)
370{
371 return QtPrivate::printAssociativeContainer(std::move(debug), "QMap", map);
372}
373
374template <class Key, class T>
375inline QDebugIfHasDebugStreamContainer<QMultiMap<Key, T>, Key, T> operator<<(QDebug debug, const QMultiMap<Key, T> &map)
376{
377 return QtPrivate::printAssociativeContainer(std::move(debug), "QMultiMap", map);
378}
379
380template <class Key, class T>
381inline QDebugIfHasDebugStreamContainer<QHash<Key, T>, Key, T> operator<<(QDebug debug, const QHash<Key, T> &hash)
382{
383 return QtPrivate::printAssociativeContainer(std::move(debug), "QHash", hash);
384}
385
386template <class Key, class T>
387inline QDebugIfHasDebugStreamContainer<QMultiHash<Key, T>, Key, T> operator<<(QDebug debug, const QMultiHash<Key, T> &hash)
388{
389 return QtPrivate::printAssociativeContainer(std::move(debug), "QMultiHash", hash);
390}
391
392template <class T>
393inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::optional<T> &opt)
394{
395 if (!opt)
396 return debug << std::nullopt;
397 const QDebugStateSaver saver(debug);
398 debug.nospace() << "std::optional(" << *opt << ')';
399 return debug;
400}
401
402template <class T1, class T2>
403inline QDebugIfHasDebugStream<T1, T2> operator<<(QDebug debug, const std::pair<T1, T2> &pair)
404{
405 const QDebugStateSaver saver(debug);
406 debug.nospace() << "std::pair(" << pair.first << ',' << pair.second << ')';
407 return debug;
408}
409
410template <typename T>
411inline QDebugIfHasDebugStreamContainer<QSet<T>, T> operator<<(QDebug debug, const QSet<T> &set)
412{
413 return QtPrivate::printSequentialContainer(std::move(debug), "QSet", set);
414}
415
416template <class T>
417inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QContiguousCache<T> &cache)
418{
419 const QDebugStateSaver saver(debug);
420 debug.nospace() << "QContiguousCache(";
421 for (qsizetype i = cache.firstIndex(); i <= cache.lastIndex(); ++i) {
422 debug << cache[i];
423 if (i != cache.lastIndex())
424 debug << ", ";
425 }
426 debug << ')';
427 return debug;
428}
429
430#else
431template <class T>
432QDebug operator<<(QDebug debug, const QList<T> &list);
433
434template <class T, qsizetype P>
435QDebug operator<<(QDebug debug, const QVarLengthArray<T, P> &array);
436
437template <typename T, typename Alloc>
438QDebug operator<<(QDebug debug, const std::vector<T, Alloc> &vec);
439
440template <typename T, typename Alloc>
441QDebug operator<<(QDebug debug, const std::list<T, Alloc> &vec);
442
443template <typename Key, typename T, typename Compare, typename Alloc>
444QDebug operator<<(QDebug debug, const std::map<Key, T, Compare, Alloc> &map);
445
446template <typename Key, typename T, typename Compare, typename Alloc>
447QDebug operator<<(QDebug debug, const std::multimap<Key, T, Compare, Alloc> &map);
448
449template <class Key, class T>
450QDebug operator<<(QDebug debug, const QMap<Key, T> &map);
451
452template <class Key, class T>
453QDebug operator<<(QDebug debug, const QMultiMap<Key, T> &map);
454
455template <class Key, class T>
456QDebug operator<<(QDebug debug, const QHash<Key, T> &hash);
457
458template <class Key, class T>
459QDebug operator<<(QDebug debug, const QMultiHash<Key, T> &hash);
460
461template <typename T>
462QDebug operator<<(QDebug debug, const QSet<T> &set);
463
464template <class T1, class T2>
465QDebug operator<<(QDebug debug, const std::pair<T1, T2> &pair);
466
467template <typename T>
468QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache);
469
470#endif // Q_QDOC
471
472template <class T>
473inline QDebug operator<<(QDebug debug, const QSharedPointer<T> &ptr)
474{
475 QDebugStateSaver saver(debug);
476 debug.nospace() << "QSharedPointer(" << ptr.data() << ")";
477 return debug;
478}
479
480template <typename T, typename Tag> class QTaggedPointer;
481
482template <typename T, typename Tag>
483inline QDebug operator<<(QDebug debug, const QTaggedPointer<T, Tag> &ptr)
484{
485 QDebugStateSaver saver(debug);
486 debug.nospace() << "QTaggedPointer(" << ptr.pointer() << ", " << ptr.tag() << ")";
487 return debug;
488}
489
490Q_CORE_EXPORT void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, uint value);
491
492template <typename Int>
493void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, Int value)
494{
495 static_assert(std::is_unsigned_v<Int>,
496 "Cast value to an unsigned type before calling this function");
497 const QDebugStateSaver saver(debug);
498 debug.resetFormat();
499 debug.nospace() << "QFlags(" << Qt::hex << Qt::showbase;
500 bool needSeparator = false;
501 for (size_t i = 0; i < sizeofT * 8; ++i) {
502 if (value & (Int(1) << i)) {
503 if (needSeparator)
504 debug << '|';
505 else
506 needSeparator = true;
507 debug << (Int(1) << i);
508 }
509 }
510 debug << ')';
511}
512
513#if !defined(QT_NO_QOBJECT) && !defined(Q_QDOC)
514Q_CORE_EXPORT QDebug qt_QMetaEnum_debugOperator(QDebug&, qint64 value, const QMetaObject *meta, const char *name);
515Q_CORE_EXPORT QDebug qt_QMetaEnum_flagDebugOperator(QDebug &dbg, quint64 value, const QMetaObject *meta, const char *name);
516
517template<typename T>
518typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, QDebug>::type
519operator<<(QDebug dbg, T value)
520{
521 const QMetaObject *obj = qt_getEnumMetaObject(value);
522 const char *name = qt_getEnumName(value);
523 return qt_QMetaEnum_debugOperator(dbg, static_cast<typename std::underlying_type<T>::type>(value), obj, name);
524}
525
526template<typename T,
527 typename A = typename std::enable_if<std::is_enum<T>::value, void>::type,
528 typename B = typename std::enable_if<sizeof(T) <= sizeof(int), void>::type,
529 typename C = typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value, void>::type,
530 typename D = typename std::enable_if<QtPrivate::IsQEnumHelper<QFlags<T>>::Value, void>::type>
531inline QDebug operator<<(QDebug dbg, T value)
532{
533 typedef QFlags<T> FlagsT;
534 const QMetaObject *obj = qt_getEnumMetaObject(FlagsT());
535 const char *name = qt_getEnumName(FlagsT());
536 return qt_QMetaEnum_debugOperator(dbg, typename FlagsT::Int(value), obj, name);
537}
538
539template <class T>
540inline typename std::enable_if<
541 QtPrivate::IsQEnumHelper<T>::Value || QtPrivate::IsQEnumHelper<QFlags<T> >::Value,
542 QDebug>::type
543qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
544{
545 using UInt = typename QIntegerForSizeof<T>::Unsigned;
546 const QMetaObject *obj = qt_getEnumMetaObject(T());
547 const char *name = qt_getEnumName(T());
548 return qt_QMetaEnum_flagDebugOperator(debug, UInt(flags.toInt()), obj, name);
549}
550
551template <class T>
552inline typename std::enable_if<
553 !QtPrivate::IsQEnumHelper<T>::Value && !QtPrivate::IsQEnumHelper<QFlags<T> >::Value,
554 QDebug>::type
555qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
556#else // !QT_NO_QOBJECT && !Q_QDOC
557template <class T>
558inline QDebug qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
559#endif
560{
561 using UInt = typename QIntegerForSizeof<T>::Unsigned;
562 qt_QMetaEnum_flagDebugOperator(debug, sizeof(T), UInt(flags.toInt()));
563 return debug;
564}
565
566template<typename T>
567inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
568{
569 // We have to use an indirection otherwise specialisation of some other overload of the
570 // operator<< the compiler would try to instantiate QFlags<T> for the std::enable_if
571 return qt_QMetaEnum_flagDebugOperator_helper(debug, flags);
572}
573
574inline QDebug operator<<(QDebug debug, QKeyCombination combination)
575{
576 QDebugStateSaver saver(debug);
577 debug.nospace() << "QKeyCombination("
578 << combination.keyboardModifiers()
579 << ", "
580 << combination.key()
581 << ")";
582 return debug;
583}
584
585#ifdef Q_OS_DARWIN
586
587// We provide QDebug stream operators for commonly used Core Foundation
588// and Core Graphics types, as well as NSObject. Additional CF/CG types
589// may be added by the user, using Q_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE.
590
591#define QT_FOR_EACH_CORE_FOUNDATION_TYPE(F) \
592 F(CFArray) \
593 F(CFURL) \
594 F(CFData) \
595 F(CFNumber) \
596 F(CFDictionary) \
597 F(CFLocale) \
598 F(CFDate) \
599 F(CFBoolean) \
600 F(CFTimeZone) \
601
602#define QT_FOR_EACH_MUTABLE_CORE_FOUNDATION_TYPE(F) \
603 F(CFError) \
604 F(CFBundle) \
605
606#define QT_FOR_EACH_CORE_GRAPHICS_TYPE(F) \
607 F(CGPath) \
608
609#define QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(F) \
610 F(CGColorSpace) \
611 F(CGImage) \
612 F(CGFont) \
613 F(CGColor) \
614
615#define QT_FORWARD_DECLARE_CF_TYPE(type) Q_FORWARD_DECLARE_CF_TYPE(type);
616#define QT_FORWARD_DECLARE_MUTABLE_CF_TYPE(type) Q_FORWARD_DECLARE_MUTABLE_CF_TYPE(type);
617#define QT_FORWARD_DECLARE_CG_TYPE(type) Q_FORWARD_DECLARE_CG_TYPE(type);
618#define QT_FORWARD_DECLARE_MUTABLE_CG_TYPE(type) Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(type);
619
620QT_END_NAMESPACE
621Q_FORWARD_DECLARE_CF_TYPE(CFString);
622struct objc_object;
623Q_FORWARD_DECLARE_OBJC_CLASS(NSObject);
624QT_FOR_EACH_CORE_FOUNDATION_TYPE(QT_FORWARD_DECLARE_CF_TYPE)
625QT_FOR_EACH_MUTABLE_CORE_FOUNDATION_TYPE(QT_FORWARD_DECLARE_MUTABLE_CF_TYPE)
626QT_FOR_EACH_CORE_GRAPHICS_TYPE(QT_FORWARD_DECLARE_CG_TYPE)
627QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_FORWARD_DECLARE_MUTABLE_CG_TYPE)
628QT_BEGIN_NAMESPACE
629
630#define QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType) \
631 Q_CORE_EXPORT QDebug operator<<(QDebug, CFType##Ref);
632
633#define Q_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType) \
634 QDebug operator<<(QDebug debug, CFType##Ref ref) \
635 { \
636 if (!ref) \
637 return debug << QT_STRINGIFY(CFType) "Ref(0x0)"; \
638 if (CFStringRef description = CFCopyDescription(ref)) { \
639 QDebugStateSaver saver(debug); \
640 debug.noquote() << description; \
641 CFRelease(description); \
642 } \
643 return debug; \
644 }
645
646// Defined in qcore_mac_objc.mm
647#if defined(__OBJC__)
648Q_CORE_EXPORT QDebug operator<<(QDebug, id);
649#endif
650Q_CORE_EXPORT QDebug operator<<(QDebug, objc_object *);
651Q_CORE_EXPORT QDebug operator<<(QDebug, const NSObject *);
652Q_CORE_EXPORT QDebug operator<<(QDebug, CFStringRef);
653
654QT_FOR_EACH_CORE_FOUNDATION_TYPE(QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE)
655QT_FOR_EACH_MUTABLE_CORE_FOUNDATION_TYPE(QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE)
656QT_FOR_EACH_CORE_GRAPHICS_TYPE(QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE)
657QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_FORWARD_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE)
658
659#undef QT_FORWARD_DECLARE_CF_TYPE
660#undef QT_FORWARD_DECLARE_MUTABLE_CF_TYPE
661#undef QT_FORWARD_DECLARE_CG_TYPE
662#undef QT_FORWARD_DECLARE_MUTABLE_CG_TYPE
663
664#endif // Q_OS_DARWIN
665
666QT_END_NAMESPACE
667
668#endif // QDEBUG_H
669

source code of qtbase/src/corelib/io/qdebug.h