--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "async-task-manager-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
+#include <dali/devel-api/adaptor-framework/thread-settings.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+namespace
+{
+constexpr auto DEFAULT_NUMBER_OF_ASYNC_THREADS = size_t{8u};
+constexpr auto NUMBER_OF_ASYNC_THREADS_ENV = "DALI_ASYNC_MANAGER_THREAD_POOL_SIZE";
+
+size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue)
+{
+ auto numberString = EnvironmentVariable::GetEnvironmentVariable(environmentVariable);
+ auto numberOfThreads = numberString ? std::strtoul(numberString, nullptr, 10) : 0;
+ constexpr auto MAX_NUMBER_OF_THREADS = 10u;
+ DALI_ASSERT_DEBUG(numberOfThreads < MAX_NUMBER_OF_THREADS);
+ return (numberOfThreads > 0 && numberOfThreads < MAX_NUMBER_OF_THREADS) ? numberOfThreads : defaultValue;
+}
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAsyncTasksManagerLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ASYNC_TASK_MANAGER");
+#endif
+
+} // unnamed namespace
+
+AsyncTaskThread::AsyncTaskThread(AsyncTaskManager& asyncTaskManager)
+: mConditionalWait(),
+ mAsyncTaskManager(asyncTaskManager),
+ mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+ mDestroyThread(false),
+ mIsThreadStarted(false),
+ mIsThreadIdle(true)
+{
+}
+
+AsyncTaskThread::~AsyncTaskThread()
+{
+ // Stop the thread
+ {
+ ConditionalWait::ScopedLock lock(mConditionalWait);
+ mDestroyThread = true;
+ mConditionalWait.Notify(lock);
+ }
+
+ Join();
+}
+
+bool AsyncTaskThread::Request()
+{
+ if(!mIsThreadStarted)
+ {
+ Start();
+ mIsThreadStarted = true;
+ }
+
+ {
+ // Lock while adding task to the queue
+ ConditionalWait::ScopedLock lock(mConditionalWait);
+
+ if(mIsThreadIdle)
+ {
+ mIsThreadIdle = false;
+
+ // wake up the thread
+ mConditionalWait.Notify(lock);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void AsyncTaskThread::Run()
+{
+ SetThreadName("AsyncTaskThread");
+ mLogFactory.InstallLogFunction();
+
+ while(!mDestroyThread)
+ {
+ AsyncTaskPtr task = mAsyncTaskManager.PopNextTaskToProcess();
+ if(!task)
+ {
+ ConditionalWait::ScopedLock lock(mConditionalWait);
+ mIsThreadIdle = true;
+ mConditionalWait.Wait(lock);
+ }
+ else
+ {
+ task->Process();
+ mAsyncTaskManager.CompleteTask(task);
+ }
+ }
+}
+
+Dali::AsyncTaskManager AsyncTaskManager::Get()
+{
+ Dali::AsyncTaskManager manager;
+ SingletonService singletonService(SingletonService::Get());
+ if(singletonService)
+ {
+ // Check whether the async task manager is already created
+ Dali::BaseHandle handle = singletonService.GetSingleton(typeid(Dali::AsyncTaskManager));
+ if(handle)
+ {
+ // If so, downcast the handle of singleton
+ manager = Dali::AsyncTaskManager(dynamic_cast<Internal::Adaptor::AsyncTaskManager*>(handle.GetObjectPtr()));
+ }
+
+ if(!manager)
+ {
+ // If not, create the async task manager and register it as a singleton
+ Internal::Adaptor::AsyncTaskManager* internalAsyncTaskManager = new Internal::Adaptor::AsyncTaskManager();
+ manager = Dali::AsyncTaskManager(internalAsyncTaskManager);
+ singletonService.Register(typeid(manager), manager);
+ }
+ }
+ return manager;
+}
+
+AsyncTaskManager::AsyncTaskManager()
+: mTasks(GetNumberOfThreads(NUMBER_OF_ASYNC_THREADS_ENV, DEFAULT_NUMBER_OF_ASYNC_THREADS), [&]() { return TaskHelper(*this); }),
+ mTrigger(new EventThreadCallback(MakeCallback(this, &AsyncTaskManager::TasksCompleted))),
+ mProcessorRegistered(false)
+{
+}
+
+AsyncTaskManager::~AsyncTaskManager()
+{
+ if(mProcessorRegistered)
+ {
+ Dali::Adaptor::Get().UnregisterProcessor(*this);
+ }
+
+ mTasks.Clear();
+}
+
+void AsyncTaskManager::AddTask(AsyncTaskPtr task)
+{
+ {
+ // Lock while adding task to the queue
+ Mutex::ScopedLock lock(mMutex);
+ mWaitingTasks.push_back(task);
+
+ // Finish all Running threads are working
+ if(mRunningTasks.size() >= mTasks.GetElementCount())
+ {
+ return;
+ }
+ }
+
+ size_t count = mTasks.GetElementCount();
+ size_t index = 0;
+ while(index++ < count)
+ {
+ auto processHelperIt = mTasks.GetNext();
+ DALI_ASSERT_ALWAYS(processHelperIt != mTasks.End());
+ if(processHelperIt->Request())
+ {
+ break;
+ }
+ // If all threads are busy, then it's ok just to push the task because they will try to get the next job.
+ }
+
+ if(!mProcessorRegistered)
+ {
+ Dali::Adaptor::Get().RegisterProcessor(*this);
+ mProcessorRegistered = true;
+ }
+
+ return;
+}
+
+void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
+{
+ {
+ // Lock while remove task from the queue
+ Mutex::ScopedLock lock(mMutex);
+ if(!mWaitingTasks.empty())
+ {
+ for(std::vector<AsyncTaskPtr>::iterator it = mWaitingTasks.begin(); it != mWaitingTasks.end();)
+ {
+ if((*it) && (*it) == task)
+ {
+ it = mWaitingTasks.erase(it);
+ }
+ else
+ {
+ it++;
+ }
+ }
+ }
+
+ if(!mRunningTasks.empty())
+ {
+ for(auto iter = mRunningTasks.begin(), endIter = mRunningTasks.end(); iter != endIter; ++iter)
+ {
+ if((*iter).first == task)
+ {
+ (*iter).second = true;
+ }
+ }
+ }
+
+ if(!mCompletedTasks.empty())
+ {
+ for(std::vector<AsyncTaskPtr>::iterator it = mCompletedTasks.begin(); it != mCompletedTasks.end();)
+ {
+ if((*it) && (*it) == task)
+ {
+ it = mCompletedTasks.erase(it);
+ }
+ else
+ {
+ it++;
+ }
+ }
+ }
+ }
+
+ UnregisterProcessor();
+}
+
+AsyncTaskPtr AsyncTaskManager::PopNextTaskToProcess()
+{
+ // Lock while popping task out from the queue
+ Mutex::ScopedLock lock(mMutex);
+
+ // pop out the next task from the queue
+ AsyncTaskPtr nextTask = nullptr;
+
+ for(auto iter = mWaitingTasks.begin(), endIter = mWaitingTasks.end(); iter != endIter; ++iter)
+ {
+ if((*iter)->IsReady())
+ {
+ nextTask = *iter;
+
+ // Add Running queue
+ mRunningTasks.push_back(std::make_pair(nextTask, false));
+ mWaitingTasks.erase(iter);
+ break;
+ }
+ }
+
+ return nextTask;
+}
+
+AsyncTaskPtr AsyncTaskManager::PopNextCompletedTask()
+{
+ // Lock while popping task out from the queue
+ Mutex::ScopedLock lock(mMutex);
+
+ if(mCompletedTasks.empty())
+ {
+ return AsyncTaskPtr();
+ }
+
+ std::vector<AsyncTaskPtr>::iterator next = mCompletedTasks.begin();
+ AsyncTaskPtr nextTask = *next;
+ mCompletedTasks.erase(next);
+
+ return nextTask;
+}
+
+void AsyncTaskManager::CompleteTask(AsyncTaskPtr task)
+{
+ // Lock while adding task to the queue
+ Mutex::ScopedLock lock(mMutex);
+ for(auto iter = mRunningTasks.begin(), endIter = mRunningTasks.end(); iter != endIter; ++iter)
+ {
+ if((*iter).first == task)
+ {
+ if(!(*iter).second)
+ {
+ mCompletedTasks.push_back(task);
+ }
+
+ // Delete this task in running queue
+ mRunningTasks.erase(iter);
+ break;
+ }
+ }
+
+ // wake up the main thread
+ mTrigger->Trigger();
+}
+
+void AsyncTaskManager::UnregisterProcessor()
+{
+ if(mProcessorRegistered)
+ {
+ Mutex::ScopedLock lock(mMutex);
+ if(mWaitingTasks.empty() && mCompletedTasks.empty() && mRunningTasks.empty())
+ {
+ Dali::Adaptor::Get().UnregisterProcessor(*this);
+ mProcessorRegistered = false;
+ }
+ }
+}
+
+void AsyncTaskManager::TasksCompleted()
+{
+ while(AsyncTaskPtr task = PopNextCompletedTask())
+ {
+ CallbackBase::Execute(*(task->GetCompletedCallback()),task);
+ }
+
+ UnregisterProcessor();
+}
+
+void AsyncTaskManager::Process(bool postProcessor)
+{
+ TasksCompleted();
+}
+
+AsyncTaskManager::TaskHelper::TaskHelper(AsyncTaskManager& asyncTaskManager)
+: TaskHelper(std::unique_ptr<AsyncTaskThread>(new AsyncTaskThread(asyncTaskManager)), asyncTaskManager)
+{
+}
+
+AsyncTaskManager::TaskHelper::TaskHelper(TaskHelper&& rhs)
+: TaskHelper(std::move(rhs.mProcessor), rhs.mAsyncTaskManager)
+{
+}
+
+AsyncTaskManager::TaskHelper::TaskHelper(std::unique_ptr<AsyncTaskThread> processor, AsyncTaskManager& asyncTaskManager)
+: mProcessor(std::move(processor)),
+ mAsyncTaskManager(asyncTaskManager)
+{
+}
+
+bool AsyncTaskManager::TaskHelper::Request()
+{
+ return mProcessor->Request();
+}
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_ASYNC_TASK_MANAGER_H
+#define DALI_INTERNAL_ASYNC_TASK_MANAGER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/event-thread-callback.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/devel-api/threading/thread.h>
+#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+#include <dali/integration-api/processor-interface.h>
+#include <dali/public-api/object/base-object.h>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
+#include <dali/public-api/adaptor-framework/round-robin-container-view.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class AsyncTaskManager;
+
+/**
+ * The worker thread for async process
+ */
+class AsyncTaskThread : public Thread
+{
+public:
+ /**
+ * Constructor.
+ */
+ AsyncTaskThread(AsyncTaskManager& asyncTaskManager);
+
+ /**
+ * Destructor.
+ */
+ ~AsyncTaskThread() override;
+
+ /**
+ * @brief Request the thread to process the task.
+ * @return True if the request is successed, otherwise false.
+ */
+ bool Request();
+
+protected:
+ /**
+ * The entry function of the worker thread.
+ */
+ void Run() override;
+
+private:
+ // Undefined
+ AsyncTaskThread(const AsyncTaskThread& thread) = delete;
+
+ // Undefined
+ AsyncTaskThread& operator=(const AsyncTaskThread& thread) = delete;
+
+private:
+ ConditionalWait mConditionalWait;
+ AsyncTaskManager& mAsyncTaskManager;
+ const Dali::LogFactoryInterface& mLogFactory; ///< The log factory
+ bool mDestroyThread;
+ bool mIsThreadStarted;
+ bool mIsThreadIdle;
+};
+
+/**
+ * The manager for async task
+ */
+class AsyncTaskManager : public Dali::BaseObject, public Integration::Processor
+{
+public:
+ /**
+ * Singleton access
+ *
+ * @return The AsyncTaskManager object
+ */
+ static Dali::AsyncTaskManager Get();
+
+ /**
+ * Constructor.
+ */
+ AsyncTaskManager();
+
+ /**
+ * Destructor.
+ */
+ ~AsyncTaskManager() override;
+
+ /**
+ * @copydoc Dali::AsyncTaskManager::AddTask()
+ */
+ void AddTask(AsyncTaskPtr task);
+
+ /**
+ * @copydoc Dali::AsyncTaskManager::RemoveTask()
+ */
+ void RemoveTask(AsyncTaskPtr task);
+
+ /**
+ * Pop the next task out from the queue.
+ *
+ * @return The next task to be processed.
+ */
+ AsyncTaskPtr PopNextTaskToProcess();
+
+ /**
+ * Pop the next task out from the completed queue, called by main thread.
+ *
+ * @return The next task in the completed queue.
+ */
+ AsyncTaskPtr PopNextCompletedTask();
+
+ /**
+ * Pop the next task out from the running queue and add this task to the completed queue.
+ *
+ * @param[in] task The task added to the queue.
+ */
+ void CompleteTask(AsyncTaskPtr task);
+
+ /**
+ * @brief Unregister a previously registered processor
+ */
+ void UnregisterProcessor();
+
+ /**
+ * Execute the callback registered by tasks in the completed queue
+ */
+ void TasksCompleted();
+
+ /**
+ * @copydoc Dali::Integration::Processor::Process()
+ */
+ void Process(bool postProcessor) override;
+
+private:
+ /**
+ * @brief Helper class to keep the relation between AsyncTaskThread and corresponding container
+ */
+ class TaskHelper
+ {
+ public:
+ /**
+ * @brief Create an TaskHelper.
+ *
+ * @param[in] asyncTaskManager Reference to the AsyncTaskManager
+ */
+ TaskHelper(AsyncTaskManager& asyncTaskManager);
+
+ /**
+ * @brief Request the thread to process the task.
+ * @return True if the request succeeds, otherwise false.
+ */
+ bool Request();
+
+ public:
+ TaskHelper(const TaskHelper&) = delete;
+ TaskHelper& operator=(const TaskHelper&) = delete;
+
+ TaskHelper(TaskHelper&& rhs);
+ TaskHelper& operator=(TaskHelper&& rhs) = delete;
+
+ private:
+ /**
+ * @brief Main constructor that used by all other constructors
+ */
+ TaskHelper(std::unique_ptr<AsyncTaskThread> processor, AsyncTaskManager& asyncTaskManager);
+
+ private:
+ std::unique_ptr<AsyncTaskThread> mProcessor;
+ AsyncTaskManager& mAsyncTaskManager;
+ };
+
+private:
+ // Undefined
+ AsyncTaskManager(const AsyncTaskManager& manager);
+
+ // Undefined
+ AsyncTaskManager& operator=(const AsyncTaskManager& manager);
+
+private:
+ std::vector<AsyncTaskPtr> mWaitingTasks; //The queue of the tasks waiting to async process
+ std::vector<AsyncTaskPtr> mCompletedTasks; //The queue of the tasks with the async process
+
+ using AsyncTaskPair = std::pair<AsyncTaskPtr, bool>;
+ std::vector<AsyncTaskPair> mRunningTasks; ///< The queue of the running tasks
+
+ RoundRobinContainerView<TaskHelper> mTasks;
+
+ Dali::Mutex mMutex;
+ std::unique_ptr<EventThreadCallback> mTrigger;
+ bool mProcessorRegistered;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+inline Internal::Adaptor::AsyncTaskManager& GetImplementation(Dali::AsyncTaskManager& obj)
+{
+ DALI_ASSERT_ALWAYS(obj && "AsyncTaskManager is empty");
+
+ Dali::BaseObject& handle = obj.GetBaseObject();
+
+ return static_cast<Internal::Adaptor::AsyncTaskManager&>(handle);
+}
+
+inline const Internal::Adaptor::AsyncTaskManager& GetImplementation(const Dali::AsyncTaskManager& obj)
+{
+ DALI_ASSERT_ALWAYS(obj && "AsyncTaskManager is empty");
+
+ const Dali::BaseObject& handle = obj.GetBaseObject();
+
+ return static_cast<const Internal::Adaptor::AsyncTaskManager&>(handle);
+}
+
+} // namespace Dali
+
+#endif
${adaptor_system_dir}/common/thread-controller.cpp
${adaptor_system_dir}/common/update-status-logger.cpp
${adaptor_system_dir}/common/widget-application-impl.cpp
+ ${adaptor_system_dir}/common/async-task-manager-impl.cpp
)
# module: system, backend: linux
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include "async-task-manager.h"
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/async-task-manager-impl.h>
+
+namespace Dali
+{
+
+AsyncTask::AsyncTask(CallbackBase* callback)
+: mCompletedCallback(std::unique_ptr<CallbackBase>(callback))
+{
+}
+
+CallbackBase* AsyncTask::GetCompletedCallback()
+{
+ return mCompletedCallback.get();
+}
+
+AsyncTaskManager::AsyncTaskManager() = default;
+
+AsyncTaskManager::~AsyncTaskManager() = default;
+
+AsyncTaskManager AsyncTaskManager::Get()
+{
+ return Internal::Adaptor::AsyncTaskManager::Get();
+}
+
+void AsyncTaskManager::AddTask(AsyncTaskPtr task)
+{
+ GetImplementation(*this).AddTask(task);
+}
+
+void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
+{
+ GetImplementation(*this).RemoveTask(task);
+}
+
+AsyncTaskManager::AsyncTaskManager(Internal::Adaptor::AsyncTaskManager* impl)
+: BaseHandle(impl)
+{
+}
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_ASYNC_TASK_MANAGER_H
+#define DALI_ASYNC_TASK_MANAGER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/callback.h>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class AsyncTaskManager;
+}
+} // namespace DALI_INTERNAL
+
+class AsyncTask;
+using AsyncTaskPtr = IntrusivePtr<AsyncTask>;
+
+/**
+ * The async tasks to be processed in the worker thread.
+ * @SINCE_2_2.3
+ */
+class DALI_ADAPTOR_API AsyncTask : public RefObject
+{
+public:
+ /**
+ * Constructor
+ * @SINCE_2_2.3
+ * @param[in] callback The callback to up the main thread. The ownership of callback is taken by this class
+ */
+ AsyncTask(CallbackBase* callback);
+
+ /**
+ * Get the complated callback
+ * @SINCE_2_2.3
+ */
+ CallbackBase* GetCompletedCallback();
+
+ /**
+ * Destructor.
+ * @SINCE_2_2.3
+ */
+ virtual ~AsyncTask() = default;
+
+ /**
+ * Process the task
+ * @SINCE_2_2.3
+ */
+ virtual void Process() = 0;
+
+ /**
+ * Whether the task is ready to process.
+ * @SINCE_2_2.3
+ * @return True if the task is ready to process.
+ */
+ virtual bool IsReady() = 0;
+
+private:
+ std::unique_ptr<CallbackBase> mCompletedCallback;
+
+ // Undefined
+ AsyncTask(const AsyncTask& task) = delete;
+
+ // Undefined
+ AsyncTask& operator=(const AsyncTask& task) = delete;
+};
+
+/**
+ * The manager for async task
+ * @SINCE_2_2.3
+ */
+class DALI_ADAPTOR_API AsyncTaskManager : public BaseHandle
+{
+public:
+ /**
+ * Constructor.
+ * @SINCE_2_2.3
+ */
+ AsyncTaskManager();
+
+ /**
+ * Destructor.
+ * @SINCE_2_2.3
+ */
+ ~AsyncTaskManager();
+
+ /**
+ * @brief Gets the singleton of AsyncTaskManager object.
+ *
+ * @SINCE_2_2.3
+ * @return A handle to the AsyncTaskManager
+ */
+ static AsyncTaskManager Get();
+
+ /**
+ * @brief Add the async task into the waiting queue, called by main thread.
+ *
+ * @SINCE_2_2.3
+ * @param[in] task The task added to the queue.
+ */
+ void AddTask(AsyncTaskPtr task);
+
+ /**
+ * @brief Remove the task from the waiting queue, called by main thread.
+ *
+ * @SINCE_2_2.3
+ * @param[in] task The task pointer.
+ */
+ void RemoveTask(AsyncTaskPtr task);
+
+public:
+ /// @cond internal
+ /**
+ * @brief Allows the creation of a AsyncTaskManager handle from an internal pointer.
+ *
+ * @note Not intended for application developers
+ * @SINCE_2_2.3
+ * @param[in] impl A pointer to the object
+ */
+ explicit DALI_INTERNAL AsyncTaskManager(Internal::Adaptor::AsyncTaskManager* impl);
+ /// @endcond
+};
+
+} // namespace Dali
+
+#endif
--- /dev/null
+#ifndef DALI_ROUND_ROBIN_CONTAINER_VIEW_H
+#define DALI_ROUND_ROBIN_CONTAINER_VIEW_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <cstddef>
+#include <vector>
+
+namespace Dali
+{
+/**
+ * @brief RoundRobinContainerView is a view to a container that allows iterating through the elements cyclically.
+ */
+template<typename T>
+class RoundRobinContainerView
+{
+public:
+ using ContainerType = std::vector<T>;
+
+ /**
+ * @brief Constructs a new RoundRobinControlView with the given number elements using the provided factory.
+ * @param[in] numberOfElements The number of elements in the container
+ * @param[in] factory Factory function of functor that will be used to create instances of the elements
+ */
+ template<typename FactoryType>
+ RoundRobinContainerView(size_t numberOfElements, const FactoryType& factory)
+ : mElements(),
+ mNextIndex{}
+ {
+ mElements.reserve(numberOfElements);
+ for(unsigned i = {}; i < numberOfElements; ++i)
+ {
+ mElements.push_back(factory());
+ }
+ }
+
+ /**
+ * @brief Clear all elements.
+ */
+ void Clear()
+ {
+ mElements.clear();
+ }
+
+ /**
+ * @brief Reset the position of the iterator returned by GetNext() to the first element.
+ */
+ void Reset()
+ {
+ mNextIndex = 0u;
+ }
+
+ /**
+ * @brief Returns the next element on the container.
+ * @return Iterator for the next element
+ */
+ typename ContainerType::iterator GetNext()
+ {
+ SetValidNextIndex();
+
+ return mElements.begin() + mNextIndex++;
+ }
+
+ /**
+ * @brief Returns the iterator to the end of the container.
+ *
+ * Can be used to compare against GetNext() to check if the container is empty.
+ *
+ * @return The container end() element
+ */
+ typename ContainerType::const_iterator End() const
+ {
+ return mElements.cend();
+ }
+
+ /**
+ * @brief Returns the element count.
+ * @return The element count
+ */
+ size_t GetElementCount() const
+ {
+ return mElements.size();
+ }
+
+ // default members
+ ~RoundRobinContainerView() = default;
+
+ RoundRobinContainerView(const RoundRobinContainerView&) = delete;
+ RoundRobinContainerView& operator=(const RoundRobinContainerView&) = delete;
+ RoundRobinContainerView(RoundRobinContainerView&&) = default;
+ RoundRobinContainerView& operator=(RoundRobinContainerView&&) = default;
+
+private:
+ /**
+ * @brief Check the current index and reset if necessary.
+ */
+ void SetValidNextIndex()
+ {
+ if(mNextIndex >= mElements.size())
+ {
+ Reset();
+ }
+ }
+
+private:
+ ContainerType mElements; //< container of elements
+ size_t mNextIndex; //< index to the next element to be viewed
+};
+
+} // namespace Dali
+
+#endif // DALI_ROUND_ROBIN_CONTAINER_VIEW_H
${adaptor_public_api_dir}/adaptor-framework/widget.cpp
${adaptor_public_api_dir}/adaptor-framework/widget-application.cpp
${adaptor_public_api_dir}/adaptor-framework/widget-impl.cpp
+ ${adaptor_public_api_dir}/adaptor-framework/async-task-manager.cpp
${adaptor_public_api_dir}/capture/capture.cpp
${adaptor_public_api_dir}/dali-adaptor-version.cpp
)
${adaptor_public_api_dir}/adaptor-framework/widget-application.h
${adaptor_public_api_dir}/adaptor-framework/widget-impl.h
${adaptor_public_api_dir}/adaptor-framework/window-enumerations.h
+ ${adaptor_public_api_dir}/adaptor-framework/round-robin-container-view.h
+ ${adaptor_public_api_dir}/adaptor-framework/async-task-manager.h
)
-
SET( public_dali_capture_header_files
${adaptor_public_api_dir}/capture/capture.h
)