Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package qt6-tasktree for openSUSE:Factory 
checked in at 2026-10-18 19:22:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/qt6-tasktree (Old)
 and      /work/SRC/openSUSE:Factory/.qt6-tasktree.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "qt6-tasktree"

Sun Oct 18 19:22:50 2026 rev:4 rq:1384416 version:6.12.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/qt6-tasktree/qt6-tasktree.changes        
2026-08-21 16:54:18.848064940 +0200
+++ /work/SRC/openSUSE:Factory/.qt6-tasktree.new.3698736/qt6-tasktree.changes   
2026-10-18 19:23:19.227749576 +0200
@@ -1,0 +2,6 @@
+Wed Sep 30 16:16:35 UTC 2026 - Christophe Marin <[email protected]>
+
+- Update to 6.12.0
+  https://www.qt.io/blog/qt-6.12-released
+
+-------------------------------------------------------------------

Old:
----
  qttasktree-everywhere-src-6.11.2.tar.xz

New:
----
  qttasktree-everywhere-src-6.12.0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ qt6-tasktree.spec ++++++
--- /var/tmp/diff_new_pack.0Vh6AO/_old  2026-10-18 19:23:20.032782912 +0200
+++ /var/tmp/diff_new_pack.0Vh6AO/_new  2026-10-18 19:23:20.034782995 +0200
@@ -16,8 +16,8 @@
 #
 
 
-%define real_version 6.11.2
-%define short_version 6.11
+%define real_version 6.12.0
+%define short_version 6.12
 %define tar_name qttasktree-everywhere-src
 %define tar_suffix %{nil}
 #
@@ -27,7 +27,7 @@
 %endif
 #
 Name:           qt6-tasktree%{?pkg_suffix}
-Version:        6.11.2
+Version:        6.12.0
 Release:        0
 Summary:        Generic framework for automatic management of asynchronous 
tasks
 License:        GPL-2.0-only OR LGPL-3.0-only OR GPL-3.0-only

++++++ qttasktree-everywhere-src-6.11.2.tar.xz -> 
qttasktree-everywhere-src-6.12.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qttasktree-everywhere-src-6.11.2/.cmake.conf 
new/qttasktree-everywhere-src-6.12.0/.cmake.conf
--- old/qttasktree-everywhere-src-6.11.2/.cmake.conf    2026-08-11 
19:38:16.000000000 +0200
+++ new/qttasktree-everywhere-src-6.12.0/.cmake.conf    2026-09-26 
12:11:26.000000000 +0200
@@ -1,10 +1,11 @@
-set(QT_REPO_MODULE_VERSION "6.11.2")
+set(QT_REPO_MODULE_VERSION "6.12.0")
 set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
 set(QT_REPO_PUBLIC_NAMESPACE_REGEX "^::QtTaskTree.*")
 set(QT_EXTRA_INTERNAL_TARGET_DEFINES
     "QT_ENABLE_STRICT_MODE_UP_TO=QT_VERSION_CHECK(6,11,0)"
     # not yet in strict mode:
     "QT_LEAN_HEADERS=1"
+    "QT_NO_DISCONNECT_CONST_CONNECTION=1"
     "QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD=1"
     "QT_NO_QPAIR=1"
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qttasktree-everywhere-src-6.11.2/.tag 
new/qttasktree-everywhere-src-6.12.0/.tag
--- old/qttasktree-everywhere-src-6.11.2/.tag   2026-08-11 19:38:16.000000000 
+0200
+++ new/qttasktree-everywhere-src-6.12.0/.tag   2026-09-26 12:11:26.000000000 
+0200
@@ -1 +1 @@
-0944a965a99ccc5dc494c71441e9333f1a9a17d6
+bb7e5587370bb5073e2d47123beb51ffba5c7fcd
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qttasktree-everywhere-src-6.11.2/CONTRIBUTING.md 
new/qttasktree-everywhere-src-6.12.0/CONTRIBUTING.md
--- old/qttasktree-everywhere-src-6.11.2/CONTRIBUTING.md        1970-01-01 
01:00:00.000000000 +0100
+++ new/qttasktree-everywhere-src-6.12.0/CONTRIBUTING.md        2026-09-26 
12:11:26.000000000 +0200
@@ -0,0 +1,11 @@
+## Qt contribution guidelines
+
+We welcome contributions to Qt!
+
+Note that we cannot accept pull requests on GitHub. All contributions
+to the Qt project are exclusively handled through the
+[Gerrit code review system](https://codereview.qt-project.org).
+
+See
+[contribute.qt-project.org](https://contribute.qt-project.org/) to learn
+more.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qttasktree-everywhere-src-6.11.2/REUSE.toml 
new/qttasktree-everywhere-src-6.12.0/REUSE.toml
--- old/qttasktree-everywhere-src-6.11.2/REUSE.toml     2026-08-11 
19:38:16.000000000 +0200
+++ new/qttasktree-everywhere-src-6.12.0/REUSE.toml     2026-09-26 
12:11:26.000000000 +0200
@@ -28,7 +28,7 @@
 SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause"
 
 [[annotations]]
-path = ["**/doc/**"]
+path = ["**/doc/**", "CONTRIBUTING.md"]
 comment = "documentation"
 precedence = "closest"
 SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qttasktree-everywhere-src-6.11.2/dependencies.yaml 
new/qttasktree-everywhere-src-6.12.0/dependencies.yaml
--- old/qttasktree-everywhere-src-6.11.2/dependencies.yaml      2026-08-11 
19:38:16.000000000 +0200
+++ new/qttasktree-everywhere-src-6.12.0/dependencies.yaml      2026-09-26 
12:11:26.000000000 +0200
@@ -1,4 +1,4 @@
 dependencies:
   ../qtbase:
-    ref: ef55f427f2c8b410d34f8a7681020a3000cf6866
+    ref: 025bdad181de241e81bf853c8a2d7bf3d19261a9
     required: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qttasktree-everywhere-src-6.11.2/licenseRule.json 
new/qttasktree-everywhere-src-6.12.0/licenseRule.json
--- old/qttasktree-everywhere-src-6.11.2/licenseRule.json       2026-08-11 
19:38:16.000000000 +0200
+++ new/qttasktree-everywhere-src-6.12.0/licenseRule.json       2026-09-26 
12:11:26.000000000 +0200
@@ -36,10 +36,10 @@
         }
     },
     {
-        "comment": "Files with the following endings are Documentation 
licensed.",
-        "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf", "README", 
"qt_attribution.json",
-                                 "README.md", "README.txt", "config_help.txt",
-                                 
"READ-THIS-BEFORE-MANUALLY-ADDING-FILES-TO-PACKAGE.txt"],
+        "comment": "Files with the following endings are documentation 
licensed.",
+        "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf",
+                                "README.md", "CONTRIBUTING.md",
+                                "qt_attribution.json"],
         "location":{
             "": {
                 "comment": "",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qttasktree-everywhere-src-6.11.2/src/tasktree/qtasktree.cpp 
new/qttasktree-everywhere-src-6.12.0/src/tasktree/qtasktree.cpp
--- old/qttasktree-everywhere-src-6.11.2/src/tasktree/qtasktree.cpp     
2026-08-11 19:38:16.000000000 +0200
+++ new/qttasktree-everywhere-src-6.12.0/src/tasktree/qtasktree.cpp     
2026-09-26 12:11:26.000000000 +0200
@@ -1466,7 +1466,7 @@
     \reentrant
 
     The Storage class template is responsible for dynamically creating
-    and destructing objects of the custom \c StorageStruct type.
+    and destructing objects of the custom \a StorageStruct type.
     The creation and destruction are managed by the running task tree.
     If a Storage object is placed inside a \l {QtTaskTree::} {Group}
     element, the running task tree creates the \c StorageStruct object
@@ -1876,6 +1876,19 @@
 */
 For::For(const Iterator &iterator) : d(new ForPrivate{iterator}) {}
 
+/*!
+    \overload
+    Constructs the For loop element, repeating \a count times.
+
+    This is equivalent to:
+    \code
+        For (RepeatIterator(count))
+    \endcode
+
+    \sa RepeatIterator
+*/
+For::For(qsizetype count) : For(RepeatIterator(count)) {}
+
 Iterator For::iterator() const
 {
     return d->m_iterator;
@@ -2031,7 +2044,7 @@
     The following construction:
 
     \code
-        const ExecutableItem task = Forever {
+        const Group recipe = Forever {
             task1,
             task2
         };
@@ -2040,7 +2053,7 @@
     is an equivalent to:
 
     \code
-        const ExecutableItem task = For (ForeverIterator()) >> Do {
+        const Group recipe = For (ForeverIterator()) >> Do {
             task1,
             task2
         };
@@ -2062,6 +2075,11 @@
     addChildren({ For (ForeverIterator()) >> Do { children } } );
 }
 
+Forever::operator Group() const
+{
+    return Group { *this };
+}
+
 /*!
     Creates QTimeoutTask with \a timeout duration, after which the task
     finishes with \a result.
@@ -2125,27 +2143,36 @@
 
 public:
     IteratorThreadData() = default;
-    void pushIteration(qsizetype index)
+    void push(qsizetype index, void *list)
     {
-        m_activeIteratorStack.push_back(index);
+        m_activeStack.push_back({index, list});
     }
-    void popIteration()
+    void pop()
     {
-        QT_TASKTREE_ASSERT(m_activeIteratorStack.size(), return);
-        m_activeIteratorStack.pop_back();
+        QT_TASKTREE_ASSERT(m_activeStack.size(), return);
+        m_activeStack.pop_back();
     }
     qsizetype iteration() const
     {
-        QT_TASKTREE_ASSERT(m_activeIteratorStack.size(), qWarning(
+        QT_TASKTREE_ASSERT(m_activeStack.size(), qWarning(
             "The referenced iterator is not reachable in the running tree. "
             "A -1 will be returned which might lead to a crash in the calling 
code. "
             "It is possible that no iterator was added to the tree, "
             "or the iterator is not reachable from where it is referenced."); 
return -1);
-        return m_activeIteratorStack.last();
+        return m_activeStack.last().iterationIndex;
+    }
+    void *activeList() const
+    {
+        QT_TASKTREE_ASSERT(m_activeStack.size(), return nullptr);
+        return m_activeStack.last().list;
     }
 
 private:
-    QList<qsizetype> m_activeIteratorStack;
+    struct Entry {
+        qsizetype iterationIndex;
+        void *list;
+    };
+    QList<Entry> m_activeStack;
 };
 
 class IteratorPrivate : public QSharedData
@@ -2159,12 +2186,16 @@
     explicit IteratorPrivate(const Iterator::Condition &condition)
         : m_condition(condition)
     {}
+    explicit IteratorPrivate(Iterator::LazyList &&lazyList)
+        : m_lazyList(std::move(lazyList))
+    {}
 
     IteratorThreadData &threadData() { return m_threadData.data(); }
 
     const std::optional<qsizetype> m_loopCount = std::nullopt;
     const Iterator::ValueGetter m_valueGetter = {};
     const Iterator::Condition m_condition = {};
+    const std::optional<Iterator::LazyList> m_lazyList = std::nullopt;
     LocalThreadStorage<IteratorThreadData> m_threadData = {};
 };
 
@@ -2190,6 +2221,10 @@
     : d(new IteratorPrivate{condition})
 {}
 
+Iterator::Iterator(LazyList &&lazyList)
+    : d(new IteratorPrivate{std::move(lazyList)})
+{}
+
 /*!
     Returns the iteration index of the currently executing handler inside
     a \l Do body of the \l For (\l Iterator) >> \l Do {} construct.
@@ -2261,6 +2296,8 @@
 
 const void *Iterator::valuePtr() const
 {
+    if (d->m_lazyList)
+        return d->m_lazyList->m_valueGetter(d->threadData().activeList(), 
iteration());
     return d->m_valueGetter(iteration());
 }
 
@@ -2459,6 +2496,9 @@
     \brief The list iterator to be used inside For element.
     \reentrant
 
+    The template parameter \a T specifies the element type of the list
+    being iterated.
+
     \sa Iterator, ForeverIterator, RepeatIterator, UntilIterator
 */
 
@@ -2466,10 +2506,44 @@
     \fn template <typename T> ListIterator<T>::ListIterator<T>(const QList<T> 
&list)
 
     Constructs the list iterator for the
-    For (ListIterator(list)) >> Do {} construct.
+    \c {For (ListIterator(list)) >> Do {}} construct.
     The iterator will iterate over each element from the passed \a list.
 
-    \sa Iterator::iteration()
+    \sa Iterator::iteration(), operator*(), operator->()
+*/
+
+/*!
+    \fn template <typename T> template <typename RangeGetter, 
ListIterator<T>::if_compatible_range<RangeGetter> = true, typename RangeType> 
ListIterator<T>::ListIterator<T>(RangeGetter &&rangeGetter)
+
+    Constructs the list iterator for the
+    \c {For (ListIterator(rangeGetter)) >> Do {}} construct.
+    The \a rangeGetter is a callable with no arguments returning a contiguous
+    range whose \c value_type is \c T. The returned range does not need to be
+    a QList<T>. Any contiguous range type supporting \c std::data() is accepted
+    — for example, a getter returning QString is valid for
+    \c ListIterator<QChar>.
+    The getter called once when the \l Group containing this iterator is 
entered,
+    with all relevant storages and parent iterations activated.
+    The call might be skipped if the possible Group's onSetupHandler()
+    returned a value other than SetupResult::Continue.
+    The iterator will iterate over each element of the returned range.
+
+    This is a convenient pattern for iterating over nested loops:
+
+    \code
+        const ListIterator outer(QStringList{"12", "34"});
+        const ListIterator inner([outer] { return *outer; });
+
+        const Group recipe {
+            For (outer) >> Do {
+                For (inner) >> Do {
+                    QSyncTask([inner] { qDebug() << *inner; })
+                }
+            }
+        };
+    \endcode
+
+    \sa Iterator::iteration(), operator*(), operator->()
 */
 
 /*!
@@ -2492,7 +2566,7 @@
     Make sure that ListIterator is passed to the For element.
 */
 
-using StoragePtr = void *;
+using StoragePtr = std::shared_ptr<void>;
 
 static constexpr QLatin1StringView s_activeStorageWarning =
     "The referenced storage is not reachable in the running tree. "
@@ -2532,25 +2606,22 @@
 class StorageBasePrivate : public QSharedData
 {
 public:
-    StorageBasePrivate(const StorageBase::StorageConstructor &ctor,
-                       const StorageBase::StorageDestructor &dtor)
-        : m_constructor(ctor)
-        , m_destructor(dtor)
+    StorageBasePrivate(const StorageBase::StorageCreator &creator)
+        : m_creator(creator)
     {}
     StorageThreadData &threadData() { return m_threadData.data(); }
 
-    const StorageBase::StorageConstructor m_constructor = {};
-    const StorageBase::StorageDestructor m_destructor = {};
+    const StorageBase::StorageCreator m_creator = {};
     LocalThreadStorage<StorageThreadData> m_threadData = {};
 };
 
-StorageBase::StorageBase(const StorageConstructor &ctor, const 
StorageDestructor &dtor)
-    : d(new StorageBasePrivate{ctor, dtor})
+StorageBase::StorageBase(const StorageBase::StorageCreator &creator)
+    : d(new StorageBasePrivate{creator})
 {}
 
-StoragePtr StorageBase::activeStorageVoid() const
+void *StorageBase::activeStorageVoid() const
 {
-    return d->threadData().activeStorage();
+    return d->threadData().activeStorage().get();
 }
 
 class GroupItemPrivate : public QSharedData
@@ -2692,7 +2763,7 @@
             }
             break;
         case Type::TaskHandler:
-            QT_TASKTREE_ASSERT(child.d->m_taskHandler.m_taskAdapterConstructor,
+            QT_TASKTREE_ASSERT(child.d->m_taskHandler.m_taskAdapterCreator,
                       qWarning("Task create handler can't be null, 
skipping..."); return);
             d->m_children.append(child);
             break;
@@ -3136,7 +3207,7 @@
         for (int i = m_activeStorages.size() - 1; i >= 0; --i) // iterate in 
reverse order
             m_activeStorages[i].d->threadData().popStorage();
         for (int i = m_activeIterators.size() - 1; i >= 0; --i) // iterate in 
reverse order
-            m_activeIterators[i].d->threadData().popIteration();
+            m_activeIterators[i].d->threadData().pop();
         QT_TASKTREE_ASSERT(s_activeTaskTrees.size(), return);
         s_activeTaskTrees.pop_back();
     }
@@ -3180,7 +3251,7 @@
         , m_container(taskTreePrivate, task)
     {}
 
-    bool isTask() const { return bool(m_taskHandler.m_taskAdapterConstructor); 
}
+    bool isTask() const { return bool(m_taskHandler.m_taskAdapterCreator); }
     qsizetype taskCount() const { return isTask() ? 1 : 
m_container.m_taskCount; }
 
     const GroupItem::TaskHandler m_taskHandler;
@@ -3219,7 +3290,7 @@
         const StorageHandler storageHandler = *it;
         if (storageHandler.*ptr) {
             GuardLocker locker(m_guard);
-            (storageHandler.*ptr)(storagePtr);
+            (storageHandler.*ptr)(storagePtr.get());
         }
     }
 
@@ -3323,12 +3394,13 @@
 
     ~RuntimeContainer()
     {
+        if (!m_callStorageDoneHandlersOnDestruction)
+            return;
+
         for (int i = m_containerNode.m_storageList.size() - 1; i >= 0; --i) { 
// iterate in reverse order
             const StorageBase storage = m_containerNode.m_storageList[i];
             StoragePtr storagePtr = m_storages.value(i);
-            if (m_callStorageDoneHandlersOnDestruction)
-                m_containerNode.m_taskTreePrivate->callDoneHandler(storage, 
storagePtr);
-            storage.d->m_destructor(storagePtr);
+            m_containerNode.m_taskTreePrivate->callDoneHandler(storage, 
storagePtr);
         }
     }
 
@@ -3354,6 +3426,7 @@
     int m_nextToStart = 0;
     int m_runningChildren = 0;
     bool m_shouldIterate = true;
+    std::shared_ptr<void> m_lazyList;
     std::vector<std::unique_ptr<RuntimeIteration>> m_iterations; // Owning.
 };
 
@@ -3361,14 +3434,11 @@
 {
 public:
     TaskInterfaceAdapter(const GroupItem::TaskHandler &taskHandler)
-        : m_taskAdapter(taskHandler.m_taskAdapterConstructor())
-        , m_taskAdapterDestructor(taskHandler.m_taskAdapterDestructor)
+        : m_taskAdapter(taskHandler.m_taskAdapterCreator())
     {}
-    ~TaskInterfaceAdapter() { m_taskAdapterDestructor(m_taskAdapter); }
 
     QTaskInterface m_taskInterface;
-    GroupItem::TaskAdapterPtr m_taskAdapter = nullptr; // Owning.
-    GroupItem::TaskAdapterDestructor m_taskAdapterDestructor;
+    std::shared_ptr<void> m_taskAdapter;
 };
 
 class RuntimeTask
@@ -3416,7 +3486,8 @@
 {
     const std::optional<Iterator> it = iteration->iterator();
     if (it) {
-        it->d->threadData().pushIteration(iteration->m_iterationIndex);
+        it->d->threadData().push(iteration->m_iterationIndex,
+                                 iteration->m_container->m_lazyList.get());
         m_activeIterators.append(*it);
     }
     activateContext(iteration->m_container);
@@ -3547,7 +3618,7 @@
 {
     QList<StoragePtr> storages;
     for (const StorageBase &storage : container.m_storageList) {
-        StoragePtr storagePtr = storage.d->m_constructor();
+        StoragePtr storagePtr = storage.d->m_creator();
         storages.append(storagePtr);
         container.m_taskTreePrivate->callSetupHandler(storage, storagePtr);
     }
@@ -3732,6 +3803,10 @@
         const IteratorPrivate *p = 
container->m_containerNode.m_iterator->d.get();
         if (p->m_loopCount) {
             container->m_shouldIterate = container->m_iterationCount < 
p->m_loopCount;
+        } else if (p->m_lazyList) {
+            QT_TASKTREE_CHECK(container->m_lazyList);
+            const qsizetype size = 
p->m_lazyList->m_listSizer(container->m_lazyList.get());
+            container->m_shouldIterate = container->m_iterationCount < size;
         } else if (p->m_condition) {
             container->m_shouldIterate = invokeHandler(container, 
p->m_condition,
                                                        
container->m_iterationCount);
@@ -3755,6 +3830,13 @@
                 container->m_successBit = 
container->m_parentTask->m_setupResult == SetupResult::StopWithSuccess;
             }
         }
+        if (container->m_parentTask->m_setupResult == SetupResult::Continue) {
+            if (containerNode.m_iterator) {
+                const IteratorPrivate *iterData = 
containerNode.m_iterator->d.get();
+                if (iterData->m_lazyList)
+                    container->m_lazyList = invokeHandler(container, 
iterData->m_lazyList->m_listGetter);
+            }
+        }
         continueContainer(container);
         return;
     }
@@ -3762,7 +3844,8 @@
     const GroupItem::TaskHandler &handler = node->m_taskNode.m_taskHandler;
     node->m_taskInterfaceAdapter.reset(new TaskInterfaceAdapter(handler));
     node->m_setupResult = handler.m_taskAdapterSetupHandler
-        ? invokeHandler(node->m_parentIteration, 
handler.m_taskAdapterSetupHandler, node->m_taskInterfaceAdapter->m_taskAdapter)
+        ? invokeHandler(node->m_parentIteration, 
handler.m_taskAdapterSetupHandler,
+                        node->m_taskInterfaceAdapter->m_taskAdapter.get())
         : SetupResult::Continue;
     if (node->m_setupResult != SetupResult::Continue) {
         if (node->m_parentIteration->m_isProgressive)
@@ -3783,7 +3866,7 @@
         childDone(parentIteration, result);
         bumpAsyncCount();
     }, Qt::SingleShotConnection);
-    handler.m_taskAdapterStarter(node->m_taskInterfaceAdapter->m_taskAdapter,
+    
handler.m_taskAdapterStarter(node->m_taskInterfaceAdapter->m_taskAdapter.get(),
                                  
&node->m_taskInterfaceAdapter->m_taskInterface);
 }
 
@@ -3809,7 +3892,7 @@
     const GroupItem::TaskHandler &handler = node->m_taskNode.m_taskHandler;
     if (handler.m_taskAdapterDoneHandler && 
shouldCallDone(handler.m_callDoneFlags, doneWith)) {
         result = invokeHandler(node->m_parentIteration, 
handler.m_taskAdapterDoneHandler,
-                               node->m_taskInterfaceAdapter->m_taskAdapter, 
doneWith);
+                               
node->m_taskInterfaceAdapter->m_taskAdapter.get(), doneWith);
     }
     if (node->m_parentIteration->m_isProgressive)
         advanceProgress(1);
@@ -3865,6 +3948,9 @@
     \brief A class template providing default task adapter used in QCustomTask.
     \reentrant
 
+    QDefaultTaskAdapter\<Task\> is a template class where \a Task specifies
+    the task type to adapt.
+
     The QDefaultTaskAdapter adapting Task may be used when the following
     conditions are met:
 
@@ -3891,7 +3977,7 @@
     Describes custom task items within task tree recipes.
 
     Custom task names are aliased with unique names using the
-    QCustomTask template with a given Task, Adapter and Deleter.
+    QCustomTask template with a given \a Task, \a Adapter and \a Deleter.
     For example, QThreadFunctionTask<T> is an alias to the QCustomTask
     that is defined to work with QThreadFunction<T> as an associated task 
class.
     The following table contains custom tasks provided by the TaskTree library
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qttasktree-everywhere-src-6.11.2/src/tasktree/qtasktree.h 
new/qttasktree-everywhere-src-6.12.0/src/tasktree/qtasktree.h
--- old/qttasktree-everywhere-src-6.11.2/src/tasktree/qtasktree.h       
2026-08-11 19:38:16.000000000 +0200
+++ new/qttasktree-everywhere-src-6.12.0/src/tasktree/qtasktree.h       
2026-09-26 12:11:26.000000000 +0200
@@ -140,16 +140,25 @@
     Q_TASKTREE_EXPORT qsizetype iteration() const;
 
 private:
+    struct LazyList {
+        std::function<std::shared_ptr<void>()> m_listGetter;
+        const void *(*m_valueGetter)(const void *, qsizetype);
+        qsizetype (*m_listSizer)(const void *);
+    };
+
     Q_TASKTREE_EXPORT Iterator(); // ForeverIterator
-    Q_TASKTREE_EXPORT Iterator(qsizetype count, const ValueGetter &valueGetter 
= {}); // RepeatIterator, ListIterator
+    Q_TASKTREE_EXPORT Iterator(qsizetype count, const ValueGetter &valueGetter 
= {}); // RepeatIterator, ListIterator (direct list)
     Q_TASKTREE_EXPORT Iterator(const Condition &condition); // UntilIterator
+    Q_TASKTREE_EXPORT Iterator(LazyList &&lazyList); // ListIterator (LazyList)
 
     Q_TASKTREE_EXPORT const void *valuePtr() const;
 
     friend class ExecutionContextActivator;
-    friend class QTaskTreePrivate;
     friend class ForeverIterator;
+    friend class IteratorPrivate;
+    friend class QTaskTreePrivate;
     friend class RepeatIterator;
+    friend class RuntimeContainer;
     friend class UntilIterator;
     template <typename T> friend class ListIterator;
     QExplicitlySharedDataPointer<IteratorPrivate> d;
@@ -176,24 +185,56 @@
 template <typename T>
 class ListIterator final : public Iterator
 {
+    // std::void_t makes the specialisation a SFINAE failure (rather than a 
hard error) when
+    // G is not invocable, its return type has no value_type matching T, or it 
is not a
+    // contiguous range (std::data() not supported).
+    template <typename, typename = void>
+    struct is_compatible_range_getter : std::false_type {};
+    template <typename G>
+    struct is_compatible_range_getter<G, std::void_t<
+        std::enable_if_t<std::is_same_v<typename 
std::invoke_result_t<G>::value_type, T>>,
+        decltype(std::data(std::declval<const std::invoke_result_t<G>>()))
+    >> : std::true_type {};
+
+    template <typename RangeGetter>
+    using if_compatible_range = 
std::enable_if_t<is_compatible_range_getter<std::decay_t<RangeGetter>>::value, 
bool>;
+
 public:
     explicit ListIterator(const QList<T> &list)
         : Iterator(list.size(), [list](qsizetype i) { return 
std::addressof(list.at(i)); }) {}
+    template <typename RangeGetter,
+              if_compatible_range<RangeGetter> = true,
+              typename RangeType = 
std::invoke_result_t<std::decay_t<RangeGetter>>>
+    explicit ListIterator(RangeGetter &&rangeGetter)
+        : Iterator({
+            [rangeGetter = std::forward<RangeGetter>(rangeGetter)] {
+                return std::make_shared<RangeType>(rangeGetter());
+            },
+            [](const void *list, qsizetype i) -> const void * {
+                return std::data(*static_cast<const RangeType *>(list)) + i;
+            },
+            [](const void *list) -> qsizetype {
+                return static_cast<const RangeType *>(list)->size();
+            },
+        }) {}
     const T *operator->() const { return static_cast<const T *>(valuePtr()); }
     const T &operator*() const { return *static_cast<const T *>(valuePtr()); }
 };
 
+// C++17 deduction guide: deduces T from RangeGetter's return type value_type.
+template <typename RangeGetter>
+ListIterator(RangeGetter &&) -> ListIterator<typename 
std::invoke_result_t<RangeGetter>::value_type>;
+
 class StorageBase
 {
 public:
     QT_TASKTREE_DECLARE_SMFS(StorageBase, Q_TASKTREE_EXPORT)
 
 private:
-    using StorageConstructor = std::function<void *(void)>;
-    using StorageDestructor = std::function<void(void *)>;
+    using StorageCreator = std::function<std::shared_ptr<void>()>;
     using StorageHandler = std::function<void(void *)>;
 
-    Q_TASKTREE_EXPORT StorageBase(const StorageConstructor &ctor, const 
StorageDestructor &dtor);
+    Q_TASKTREE_EXPORT StorageBase(const StorageCreator &creator);
 
     Q_TASKTREE_EXPORT void *activeStorageVoid() const;
 
@@ -220,23 +261,17 @@
 class Storage final : public StorageBase
 {
 public:
-    Storage() : StorageBase(Storage::ctor(), Storage::dtor()) {}
+    Storage() : StorageBase([] { return std::make_shared<StorageStruct>(); }) 
{}
     template <typename FirstArg, typename ...Args,
              std::enable_if_t<!std::is_same_v<q20::remove_cvref_t<FirstArg>, 
Storage<StorageStruct>>, bool> = true>
     explicit Storage(const FirstArg &firstArg, const Args &...args)
-        : StorageBase([=] { return new StorageStruct{firstArg, args...}; }, 
Storage::dtor()) {}
+        : StorageBase([=] { return std::make_shared<StorageStruct>(firstArg, 
args...); }) {}
 
     StorageStruct &operator*() const noexcept { return *activeStorage(); }
     StorageStruct *operator->() const noexcept { return activeStorage(); }
     StorageStruct *activeStorage() const {
         return static_cast<StorageStruct *>(activeStorageVoid());
     }
-
-private:
-    static StorageConstructor ctor() { return [] { return new StorageStruct(); 
}; }
-    static StorageDestructor dtor() {
-        return [](void *storage) { delete static_cast<StorageStruct 
*>(storage); };
-    }
 };
 
 class GroupItem
@@ -261,9 +296,7 @@
 
     using TaskAdapterPtr = void *;
     // Internal, provided by QCustomTask
-    using TaskAdapterConstructor = std::function<TaskAdapterPtr(void)>;
-    // Internal, provided by QCustomTask
-    using TaskAdapterDestructor = std::function<void(TaskAdapterPtr)>;
+    using TaskAdapterCreator = std::function<std::shared_ptr<void>(void)>;
     //
     using TaskAdapterStarter = std::function<void(TaskAdapterPtr, 
QTaskInterface *)>;
     // Called prior to task start, just after createHandler
@@ -272,8 +305,7 @@
     using TaskAdapterDoneHandler = std::function<DoneResult(TaskAdapterPtr, 
DoneWith)>;
 
     struct TaskHandler { // TODO: Make it a pimpled value type?
-        TaskAdapterConstructor m_taskAdapterConstructor;
-        TaskAdapterDestructor m_taskAdapterDestructor;
+        TaskAdapterCreator m_taskAdapterCreator;
         TaskAdapterStarter m_taskAdapterStarter;
         TaskAdapterSetupHandler m_taskAdapterSetupHandler = {};
         TaskAdapterDoneHandler m_taskAdapterDoneHandler = {};
@@ -516,6 +548,7 @@
 {
 public:
     Q_TASKTREE_EXPORT explicit For(const Iterator &loop);
+    Q_TASKTREE_EXPORT explicit For(qsizetype count);
 
     QT_TASKTREE_DECLARE_SMFS(For, Q_TASKTREE_EXPORT)
 
@@ -549,6 +582,8 @@
 public:
     Q_TASKTREE_EXPORT explicit Forever(const GroupItems &children);
     Q_TASKTREE_EXPORT explicit Forever(std::initializer_list<GroupItem> 
children);
+
+    Q_TASKTREE_EXPORT operator Group() const;
 };
 
 Q_TASKTREE_EXPORT ExecutableItem timeoutTask(const std::chrono::milliseconds 
&timeout,
@@ -656,7 +691,7 @@
     explicit QCustomTask(SetupHandler &&setup = TaskSetupHandler(),
                          DoneHandler &&done = TaskDoneHandler(),
                          CallDone callDone = CallDoneFlag::Always)
-        : ExecutableItem(TaskHandler{&taskAdapterConstructor, 
&taskAdapterDestructor, &taskAdapterStarter,
+        : ExecutableItem(TaskHandler{&taskAdapterCreator, &taskAdapterStarter,
                           wrapSetup(std::forward<SetupHandler>(setup)),
                           wrapDone(std::forward<DoneHandler>(done)), callDone})
     {}
@@ -681,11 +716,7 @@
         Adapter adapter;
     };
 
-    static TaskAdapter *taskAdapterConstructor() { return new TaskAdapter; }
-
-    static void taskAdapterDestructor(TaskAdapterPtr voidAdapter) {
-        delete static_cast<TaskAdapter *>(voidAdapter);
-    }
+    static std::shared_ptr<void> taskAdapterCreator() { return 
std::make_shared<TaskAdapter>(); }
 
     static void taskAdapterStarter(TaskAdapterPtr voidAdapter, QTaskInterface 
*iface) {
         TaskAdapter *taskAdapter = static_cast<TaskAdapter *>(voidAdapter);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qttasktree-everywhere-src-6.11.2/src/tasktree/qtasktreerunner.cpp 
new/qttasktree-everywhere-src-6.12.0/src/tasktree/qtasktreerunner.cpp
--- old/qttasktree-everywhere-src-6.11.2/src/tasktree/qtasktreerunner.cpp       
2026-08-11 19:38:16.000000000 +0200
+++ new/qttasktree-everywhere-src-6.12.0/src/tasktree/qtasktreerunner.cpp       
2026-09-26 12:11:26.000000000 +0200
@@ -363,7 +363,7 @@
     \inmodule QtTaskTree
     \brief A mapped task tree execution controller with a given Key type.
 
-    Manages mapped task tree execution using \c Key type.
+    Manages mapped task tree execution using the \a Key type.
     Use the start() method to execute a recipe for a given key unconditionally,
     resetting a possibly running task tree with the same key,
     and keeping other possibly running task trees with different keys
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qttasktree-everywhere-src-6.11.2/src/tasktree/qthreadfunctiontask.cpp 
new/qttasktree-everywhere-src-6.12.0/src/tasktree/qthreadfunctiontask.cpp
--- old/qttasktree-everywhere-src-6.11.2/src/tasktree/qthreadfunctiontask.cpp   
2026-08-11 19:38:16.000000000 +0200
+++ new/qttasktree-everywhere-src-6.12.0/src/tasktree/qthreadfunctiontask.cpp   
2026-09-26 12:11:26.000000000 +0200
@@ -85,7 +85,8 @@
            separate thread via QtConcurrent::run().
     \reentrant
 
-    A QThreadFunction is a convenient class template that combines a stored
+    A QThreadFunction is a convenient class template, where \a ResultType
+    specifies the return type of the stored function, that combines a stored
     function to be called later via QtConcurrent::run() with an internal
     QFutureWatcher monitoring the function execution. Use QThreadFunctionTask
     to execute the QThreadFunction inside the QTaskTree recipe.
@@ -391,7 +392,8 @@
     \typedef QtTaskTree::QThreadFunctionTask
     \relates QtTaskTree::QCustomTask
 
-    Type alias for the QCustomTask<QThreadFunction<ResultType>>,
+    Type alias for QCustomTask<QThreadFunction<ResultType>>,
+    where \a ResultType specifies the return type of the thread function,
     to be used inside recipes.
 */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qttasktree-everywhere-src-6.11.2/tests/auto/tasktree/tst_qttasktree.cpp 
new/qttasktree-everywhere-src-6.12.0/tests/auto/tasktree/tst_qttasktree.cpp
--- old/qttasktree-everywhere-src-6.11.2/tests/auto/tasktree/tst_qttasktree.cpp 
2026-08-11 19:38:16.000000000 +0200
+++ new/qttasktree-everywhere-src-6.12.0/tests/auto/tasktree/tst_qttasktree.cpp 
2026-09-26 12:11:26.000000000 +0200
@@ -54,6 +54,7 @@
     Timeout,
     Storage,
     Iteration,
+    IteratorRangeGetter,
 };
 Q_ENUM_NS(Handler);
 
@@ -102,6 +103,54 @@
 
 std::atomic_int CustomStorage::s_count = 0;
 
+// Compile-time CTAD tests for ListIterator.
+// Verifies that the deduction guide's forwarding-reference overload does not 
steal
+// QList arguments from the const QList<T> & constructor (the 
underconstrained-guide hazard).
+namespace {
+[[maybe_unused]] void testListIteratorCTAD()
+{
+    // --- QList constructor overload ---
+
+    // const lvalue: baseline case.
+    const QList<int> constList{1, 2, 3};
+    auto a = ListIterator(constList);
+    static_assert(std::is_same_v<decltype(a), ListIterator<int>>);
+
+    // non-const lvalue: without the enable_if constraint on the deduction 
guide,
+    // ListGetter&& would be a perfect match and beat const QList<T> &.
+    QList<int> mutableList{1, 2, 3};
+    auto b = ListIterator(mutableList);
+    static_assert(std::is_same_v<decltype(b), ListIterator<int>>);
+
+    // rvalue: same hazard as non-const lvalue.
+    auto c = ListIterator(QList<int>{1, 2, 3});
+    static_assert(std::is_same_v<decltype(c), ListIterator<int>>);
+
+    // Different value types.
+    auto d = ListIterator(QList<QString>{"a", "b"});
+    static_assert(std::is_same_v<decltype(d), ListIterator<QString>>);
+
+    auto e = ListIterator(QList<double>{1.0, 2.0});
+    static_assert(std::is_same_v<decltype(e), ListIterator<double>>);
+
+    // --- Deduction guide (callable) overload ---
+
+    // Lvalue lambda: T deduced from the return type's value_type.
+    auto getter = [] { return QList<int>{1, 2, 3}; };
+    auto f = ListIterator(getter);
+    static_assert(std::is_same_v<decltype(f), ListIterator<int>>);
+
+    // Rvalue (inline) lambda.
+    auto g = ListIterator([] { return QList<QString>{"a"}; });
+    static_assert(std::is_same_v<decltype(g), ListIterator<QString>>);
+
+    // std::function.
+    std::function<QList<double>()> fn = [] { return QList<double>{1.0}; };
+    auto h = ListIterator(fn);
+    static_assert(std::is_same_v<decltype(h), ListIterator<double>>);
+}
+} // unnamed namespace
+
 struct TestData
 {
     Storage<CustomStorage> storage;
@@ -217,6 +266,22 @@
         }.withTimeout(1s)
     };
 
+    const Group group6 = Forever {
+        TestTask()
+    };
+
+    const Group group7 = Forever {
+        TestTask()
+    }.withTimeout(1s);
+
+    using GroupGetter = std::function<Group()>;
+
+    const GroupGetter getter = [] {
+        return Forever {
+            TestTask()
+        };
+    };
+
     // When turning each of below blocks on, you should see the specific 
compiler error message.
 
     // Sync handler needs to take no arguments and has to return void or bool.
@@ -3046,6 +3111,10 @@
             sequential,
             successItems
         };
+        const Group rootSequentialSuccess2 = For (2) >> Do {
+            sequential,
+            successItems
+        };
         const Log logSequentialSuccess {
             {1, Handler::Setup},
             {1, Handler::Success},
@@ -3061,6 +3130,10 @@
             parallel,
             successItems
         };
+        const Group rootParallelSuccess2 = For (2) >> Do {
+            parallel,
+            successItems
+        };
         const Log logParallelSuccess {
             {1, Handler::Setup},
             {2, Handler::Setup},
@@ -3076,6 +3149,10 @@
             ParallelLimit(2),
             successItems
         };
+        const Group rootParallelLimitSuccess2 = For (2) >> Do  {
+            ParallelLimit(2),
+            successItems
+        };
         const Log logParallelLimitSuccess {
             {1, Handler::Setup},
             {2, Handler::Setup},
@@ -3097,6 +3174,10 @@
             sequential,
             errorItems
         };
+        const Group rootSequentialError2 = For (2) >> Do {
+            sequential,
+            errorItems
+        };
         const Log logSequentialError {
             {1, Handler::Setup},
             {1, Handler::Success},
@@ -3108,6 +3189,10 @@
             parallel,
             errorItems
         };
+        const Group rootParallelError2 = For (2) >> Do {
+            parallel,
+            errorItems
+        };
         const Log logParallelError {
             {1, Handler::Setup},
             {2, Handler::Setup},
@@ -3123,6 +3208,10 @@
             ParallelLimit(2),
             errorItems
         };
+        const Group rootParallelLimitError2 = For (2) >> Do {
+            ParallelLimit(2),
+            errorItems
+        };
         const Log logParallelLimitError {
             {1, Handler::Setup},
             {2, Handler::Setup},
@@ -3144,6 +3233,19 @@
             << TestData{storage, rootParallelError, logParallelError, 4, 
DoneWith::Error, 2};
         QTest::newRow("RepeatParallelLimitError")
             << TestData{storage, rootParallelLimitError, 
logParallelLimitError, 4, DoneWith::Error, 2};
+
+        QTest::newRow("NumberSequentialSuccess")
+            << TestData{storage, rootSequentialSuccess2, logSequentialSuccess, 
4, DoneWith::Success, 4};
+        QTest::newRow("NumberParallelSuccess")
+            << TestData{storage, rootParallelSuccess2, logParallelSuccess, 4, 
DoneWith::Success, 4};
+        QTest::newRow("NumberParallelLimitSuccess")
+            << TestData{storage, rootParallelLimitSuccess2, 
logParallelLimitSuccess, 4, DoneWith::Success, 4};
+        QTest::newRow("NumberSequentialError")
+            << TestData{storage, rootSequentialError2, logSequentialError, 4, 
DoneWith::Error, 2};
+        QTest::newRow("NumberParallelError")
+            << TestData{storage, rootParallelError2, logParallelError, 4, 
DoneWith::Error, 2};
+        QTest::newRow("NumberParallelLimitError")
+            << TestData{storage, rootParallelLimitError2, 
logParallelLimitError, 4, DoneWith::Error, 2};
     }
 
     {
@@ -3585,6 +3687,115 @@
     }
 
     {
+        // Check if ListIterator work with QList.
+        const auto recipe = [storage](SetupResult result) {
+            const ListIterator iterator([storage] {
+                storage->m_log.append({0, Handler::IteratorRangeGetter});
+                return QList{1, 2, 3};
+            });
+
+            return Group {
+                storage,
+                For (iterator) >> Do {
+                    onGroupSetup([result] { return result; }),
+                    QSyncTask([storage, iterator] {
+                        storage->m_log.append({*iterator, Handler::Sync});
+                    })
+                }
+            };
+        };
+
+        const Log log {
+            {0, Handler::IteratorRangeGetter},
+            {1, Handler::Sync},
+            {2, Handler::Sync},
+            {3, Handler::Sync}
+        };
+
+        // Check if ListIterator's getter is called once when the group is 
entered,
+        // with storage accessible, and the returned list is used for 
iteration.
+        QTest::newRow("LazyListGetterExecutedOnceOnContinue")
+            << TestData{storage, recipe(SetupResult::Continue), log, 0, 
DoneWith::Success, 0};
+
+        // Check if ListIterator's getter is skipped when the group's setup 
handler
+        // returns a value other than SetupResult::Continue.
+        QTest::newRow("LazyListGetterSkippedOnStopWithSuccess")
+            << TestData{storage, recipe(SetupResult::StopWithSuccess), Log(), 
0,
+                        DoneWith::Success, 0};
+        QTest::newRow("LazyListGetterSkippedOnStopWithError")
+            << TestData{storage, recipe(SetupResult::StopWithError), Log(), 0,
+                        DoneWith::Error, 0};
+    }
+
+    {
+        // Check if ListIterator work with std::vector.
+        const auto recipe = [storage](SetupResult result) {
+            const ListIterator iterator([storage] {
+                storage->m_log.append({0, Handler::IteratorRangeGetter});
+                return std::vector{1, 2, 3};
+            });
+
+            return Group {
+                storage,
+                For (iterator) >> Do {
+                    onGroupSetup([result] { return result; }),
+                    QSyncTask([storage, iterator] {
+                        storage->m_log.append({*iterator, Handler::Sync});
+                    })
+                }
+            };
+        };
+
+        const Log log {
+            {0, Handler::IteratorRangeGetter},
+            {1, Handler::Sync},
+            {2, Handler::Sync},
+            {3, Handler::Sync}
+        };
+
+        // Check if ListIterator's getter is called once when the group is 
entered,
+        // with storage accessible, and the returned list is used for 
iteration.
+        QTest::newRow("LazyVectorGetterExecutedOnceOnContinue")
+            << TestData{storage, recipe(SetupResult::Continue), log, 0, 
DoneWith::Success, 0};
+
+        // Check if ListIterator's getter is skipped when the group's setup 
handler
+        // returns a value other than SetupResult::Continue.
+        QTest::newRow("LazyVectorGetterSkippedOnStopWithSuccess")
+            << TestData{storage, recipe(SetupResult::StopWithSuccess), Log(), 
0,
+                        DoneWith::Success, 0};
+        QTest::newRow("LazyVectorGetterSkippedOnStopWithError")
+            << TestData{storage, recipe(SetupResult::StopWithError), Log(), 0,
+                        DoneWith::Error, 0};
+    }
+
+    {
+        // Check if nested ListIterators work: the outer iterates over 
strings, the inner
+        // uses the callable overload to iterate over QChars of the current 
outer string.
+        const ListIterator outer(QStringList{"12", "34"});
+        const ListIterator inner([outer] { return *outer; });
+
+        const Group root {
+            storage,
+            For (outer) >> Do {
+                For (inner) >> Do {
+                    QSyncTask([storage, inner] {
+                        storage->m_log.append({(*inner).digitValue(), 
Handler::Sync});
+                    })
+                }
+            }
+        };
+
+        const Log log {
+            {1, Handler::Sync},
+            {2, Handler::Sync},
+            {3, Handler::Sync},
+            {4, Handler::Sync},
+        };
+
+        QTest::newRow("NestedLazyList") << TestData{storage, root, log, 0, 
DoneWith::Success, 0};
+    }
+
+    {
         // This test ensures the task done handler or onGroupDone accepts the 
DoneResult as an
         // argument.
 

Reply via email to