| 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 | |