From e0c46adca627dfe37a82e44806d003003407b47c Mon Sep 17 00:00:00 2001 From: tscholb Date: Mon, 21 Nov 2022 17:34:48 +0900 Subject: [PATCH] Add AsyncTaskManager Change-Id: I0a455873e747c36a8404a380dbfca72a00f529d5 --- .../system/common/async-task-manager-impl.cpp | 367 +++++++++++++++++++++ .../system/common/async-task-manager-impl.h | 238 +++++++++++++ dali/internal/system/file.list | 1 + .../adaptor-framework/async-task-manager.cpp | 60 ++++ .../adaptor-framework/async-task-manager.h | 149 +++++++++ .../adaptor-framework/round-robin-container-view.h | 128 +++++++ dali/public-api/file.list | 4 +- 7 files changed, 946 insertions(+), 1 deletion(-) create mode 100644 dali/internal/system/common/async-task-manager-impl.cpp create mode 100644 dali/internal/system/common/async-task-manager-impl.h create mode 100644 dali/public-api/adaptor-framework/async-task-manager.cpp create mode 100644 dali/public-api/adaptor-framework/async-task-manager.h create mode 100644 dali/public-api/adaptor-framework/round-robin-container-view.h diff --git a/dali/internal/system/common/async-task-manager-impl.cpp b/dali/internal/system/common/async-task-manager-impl.cpp new file mode 100644 index 0000000..22e274c --- /dev/null +++ b/dali/internal/system/common/async-task-manager-impl.cpp @@ -0,0 +1,367 @@ +/* + * 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 +#include +#include +#include +#include + +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(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::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::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::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(new AsyncTaskThread(asyncTaskManager)), asyncTaskManager) +{ +} + +AsyncTaskManager::TaskHelper::TaskHelper(TaskHelper&& rhs) +: TaskHelper(std::move(rhs.mProcessor), rhs.mAsyncTaskManager) +{ +} + +AsyncTaskManager::TaskHelper::TaskHelper(std::unique_ptr processor, AsyncTaskManager& asyncTaskManager) +: mProcessor(std::move(processor)), + mAsyncTaskManager(asyncTaskManager) +{ +} + +bool AsyncTaskManager::TaskHelper::Request() +{ + return mProcessor->Request(); +} +} // namespace Adaptor + +} // namespace Internal + +} // namespace Dali diff --git a/dali/internal/system/common/async-task-manager-impl.h b/dali/internal/system/common/async-task-manager-impl.h new file mode 100644 index 0000000..2007779 --- /dev/null +++ b/dali/internal/system/common/async-task-manager-impl.h @@ -0,0 +1,238 @@ +#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 +#include +#include +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +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 processor, AsyncTaskManager& asyncTaskManager); + + private: + std::unique_ptr mProcessor; + AsyncTaskManager& mAsyncTaskManager; + }; + +private: + // Undefined + AsyncTaskManager(const AsyncTaskManager& manager); + + // Undefined + AsyncTaskManager& operator=(const AsyncTaskManager& manager); + +private: + std::vector mWaitingTasks; //The queue of the tasks waiting to async process + std::vector mCompletedTasks; //The queue of the tasks with the async process + + using AsyncTaskPair = std::pair; + std::vector mRunningTasks; ///< The queue of the running tasks + + RoundRobinContainerView mTasks; + + Dali::Mutex mMutex; + std::unique_ptr 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(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(handle); +} + +} // namespace Dali + +#endif diff --git a/dali/internal/system/file.list b/dali/internal/system/file.list index 07ca29c..d366736 100644 --- a/dali/internal/system/file.list +++ b/dali/internal/system/file.list @@ -23,6 +23,7 @@ SET( adaptor_system_common_src_files ${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 diff --git a/dali/public-api/adaptor-framework/async-task-manager.cpp b/dali/public-api/adaptor-framework/async-task-manager.cpp new file mode 100644 index 0000000..20a1a6c --- /dev/null +++ b/dali/public-api/adaptor-framework/async-task-manager.cpp @@ -0,0 +1,60 @@ +/* + * 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 + +namespace Dali +{ + +AsyncTask::AsyncTask(CallbackBase* callback) +: mCompletedCallback(std::unique_ptr(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 diff --git a/dali/public-api/adaptor-framework/async-task-manager.h b/dali/public-api/adaptor-framework/async-task-manager.h new file mode 100644 index 0000000..02021c1 --- /dev/null +++ b/dali/public-api/adaptor-framework/async-task-manager.h @@ -0,0 +1,149 @@ +#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 +#include +#include +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Internal DALI_INTERNAL +{ +namespace Adaptor +{ +class AsyncTaskManager; +} +} // namespace DALI_INTERNAL + +class AsyncTask; +using AsyncTaskPtr = IntrusivePtr; + +/** + * 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 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 diff --git a/dali/public-api/adaptor-framework/round-robin-container-view.h b/dali/public-api/adaptor-framework/round-robin-container-view.h new file mode 100644 index 0000000..66d1e32 --- /dev/null +++ b/dali/public-api/adaptor-framework/round-robin-container-view.h @@ -0,0 +1,128 @@ +#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 +#include + +namespace Dali +{ +/** + * @brief RoundRobinContainerView is a view to a container that allows iterating through the elements cyclically. + */ +template +class RoundRobinContainerView +{ +public: + using ContainerType = std::vector; + + /** + * @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 + 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 diff --git a/dali/public-api/file.list b/dali/public-api/file.list index cd52e1f..f13b5ff 100644 --- a/dali/public-api/file.list +++ b/dali/public-api/file.list @@ -11,6 +11,7 @@ SET( adaptor_public_api_src_files ${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 ) @@ -38,9 +39,10 @@ SET( public_api_adaptor_framework_header_files ${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 ) -- 2.7.4