1 | // Copyright (C) 2022 The Qt Company Ltd. |
2 | // Copyright (C) 2019 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 QFOREACH_H |
6 | #define QFOREACH_H |
7 | |
8 | #include <QtCore/qtclasshelpermacros.h> |
9 | #include <QtCore/qtconfigmacros.h> |
10 | #include <QtCore/qtdeprecationmarkers.h> |
11 | #include <QtCore/qttypetraits.h> |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | #if 0 |
16 | #pragma qt_class(QForeach) |
17 | #pragma qt_sync_stop_processing |
18 | #endif |
19 | |
20 | #ifndef QT_NO_FOREACH |
21 | |
22 | namespace QtPrivate { |
23 | |
24 | template <typename T> |
25 | class QForeachContainer { |
26 | Q_DISABLE_COPY_MOVE(QForeachContainer) |
27 | public: |
28 | QForeachContainer(const T &t) : c(t), i(std::as_const(c).begin()), e(std::as_const(c).end()) {} |
29 | QForeachContainer(T &&t) : c(std::move(t)), i(std::as_const(c).begin()), e(std::as_const(c).end()) {} |
30 | |
31 | T c; |
32 | typename T::const_iterator i, e; |
33 | }; |
34 | |
35 | // Containers that have a detach function are considered shared, and are OK in a foreach loop |
36 | template <typename T, typename = decltype(std::declval<T>().detach())> |
37 | inline void warnIfContainerIsNotShared(int) {} |
38 | |
39 | #if QT_DEPRECATED_SINCE(6, 0) |
40 | // Other containers will copy themselves if used in foreach, this use is deprecated |
41 | template <typename T> |
42 | QT_DEPRECATED_VERSION_X_6_0("Do not use foreach/Q_FOREACH with containers which are not implicitly shared. " |
43 | "Prefer using a range-based for loop with these containers: `for (const auto &it : container)`, " |
44 | "keeping in mind that range-based for doesn't copy the container as Q_FOREACH does" ) |
45 | inline void warnIfContainerIsNotShared(...) {} |
46 | #endif |
47 | |
48 | template<typename T> |
49 | QForeachContainer<typename std::decay<T>::type> qMakeForeachContainer(T &&t) |
50 | { |
51 | warnIfContainerIsNotShared<typename std::decay<T>::type>(0); |
52 | return QForeachContainer<typename std::decay<T>::type>(std::forward<T>(t)); |
53 | } |
54 | |
55 | } |
56 | |
57 | // Use C++17 if statement with initializer. User's code ends up in a else so |
58 | // scoping of different ifs is not broken |
59 | #define Q_FOREACH_IMPL(variable, name, container) \ |
60 | for (auto name = QtPrivate::qMakeForeachContainer(container); name.i != name.e; ++name.i) \ |
61 | if (variable = *name.i; false) {} else |
62 | |
63 | #define Q_FOREACH_JOIN(A, B) Q_FOREACH_JOIN_IMPL(A, B) |
64 | #define Q_FOREACH_JOIN_IMPL(A, B) A ## B |
65 | |
66 | #define Q_FOREACH(variable, container) \ |
67 | Q_FOREACH_IMPL(variable, Q_FOREACH_JOIN(_container_, __LINE__), container) |
68 | #endif // QT_NO_FOREACH |
69 | |
70 | #define Q_FOREVER for(;;) |
71 | #ifndef QT_NO_KEYWORDS |
72 | # ifndef QT_NO_FOREACH |
73 | # ifndef foreach |
74 | # define foreach Q_FOREACH |
75 | # endif |
76 | # endif // QT_NO_FOREACH |
77 | # ifndef forever |
78 | # define forever Q_FOREVER |
79 | # endif |
80 | #endif |
81 | |
82 | QT_END_NAMESPACE |
83 | |
84 | #endif /* QFOREACH_H */ |
85 | |