Line data Source code
1 : /*! 2 : * \file esys/repo/queuemt.h 3 : * \brief Thread-safe queue 4 : * 5 : * \cond 6 : * __legal_b__ 7 : * 8 : * Copyright (c) 2020 Michel Gillet 9 : * Distributed under the MIT License. 10 : * (See accompanying file LICENSE.txt or 11 : * copy at https://opensource.org/licenses/MIT) 12 : * 13 : * __legal_e__ 14 : * \endcond 15 : * 16 : */ 17 : 18 : #pragma once 19 : 20 : #include "esys/repo/esysrepo_defs.h" 21 : 22 : #include <mutex> 23 : #include <deque> 24 : #include <functional> 25 : 26 : namespace esys 27 : { 28 : 29 : namespace repo 30 : { 31 : 32 : /*! \class QueueMT esys/repo/queuemt.h "esys/repo/queuemt.h" 33 : * \brief Thread-safe queue 34 : */ 35 : /*! \tparam T the element type */ 36 : template<typename T> 37 : class QueueMT 38 : { 39 : public: 40 : //! Constructor 41 : QueueMT(); 42 : 43 : //! Destructor 44 : ~QueueMT(); 45 : 46 : //! Push an element at back of the queue 47 : /*! 48 : * \param[in] val the element to add to the queue 49 : */ 50 : void push_back(const T &val); 51 : 52 : //! Push an element at front of the queue 53 : /*! 54 : * \param[in] val the element to add to the queue 55 : */ 56 : void push_front(const T &val); 57 : 58 : //! Pop an element from the back of the queue 59 : /*! 60 : * \param[out] val if the queue is not empty, the element at the back of the queue 61 : * \return 0 if successful, < 0 otherwise 62 : */ 63 : int pop_back(T &val); 64 : 65 : //! Pop an element from the front of the queue 66 : /*! 67 : * \param[out] val if the queue is not empty, the element at the front of the queue 68 : * \return 0 if successful, < 0 otherwise 69 : */ 70 : int pop_front(T &val); 71 : 72 : //! Return the size of the queue 73 : /*! 74 : * \return the size of the queue 75 : */ 76 : std::size_t size(); 77 : 78 : //! Tells if the queue is empty or not 79 : /*! 80 : * \return true if the queue is empty, false otherwise 81 : */ 82 : bool empty(); 83 : 84 : //! Erase elements matching the given condition 85 : /*! 86 : * \param[in] fct erase the element if this function return true 87 : * \return true if the queue is empty, false otherwise 88 : */ 89 : int remove_if(std::function<bool(const T &val)> fct); 90 : 91 : void for_each(std::function<void(const T &val)> fct); 92 : 93 : //! Clear all data 94 : void clear(); 95 : 96 : private: 97 : //!< \cond DOXY_IMPL 98 : std::mutex m_mutex; //!< The mutex to use 99 : std::deque<T> m_queue; //!< The actual queue 100 : //!< \endcond 101 : }; 102 : 103 : template<typename T> 104 276 : QueueMT<T>::QueueMT() 105 : { 106 220 : } 107 : 108 : template<typename T> 109 221 : QueueMT<T>::~QueueMT() 110 : { 111 221 : m_queue.clear(); 112 111 : } 113 : 114 : template<typename T> 115 447 : void QueueMT<T>::push_back(const T &val) 116 : { 117 : //! lock 118 : /*! 119 : * \param[in] m_mutex the m mutex 120 : */ 121 447 : std::lock_guard lock(m_mutex); 122 : 123 447 : m_queue.push_back(val); 124 447 : } 125 : 126 : template<typename T> 127 : void QueueMT<T>::push_front(const T &val) 128 : { 129 : //! lock 130 : /*! 131 : * \param[in] m_mutex the m mutex 132 : */ 133 : std::lock_guard lock(m_mutex); 134 : 135 : m_queue.push_front(val); 136 : } 137 : 138 : template<typename T> 139 1 : int QueueMT<T>::pop_back(T &val) 140 : { 141 : //! lock 142 : /*! 143 : * \param[in] m_mutex the m mutex 144 : */ 145 1 : std::lock_guard lock(m_mutex); 146 : 147 1 : val = nullptr; 148 : 149 1 : if (m_queue.size() == 0) return -1; 150 : 151 0 : val = m_queue.back(); 152 0 : m_queue.pop_back(); 153 : 154 0 : return 0; 155 1 : } 156 : 157 : template<typename T> 158 199 : int QueueMT<T>::pop_front(T &val) 159 : { 160 : //! lock 161 : /*! 162 : * \param[in] m_mutex the m mutex 163 : */ 164 199 : std::lock_guard lock(m_mutex); 165 : 166 199 : val = nullptr; 167 : 168 199 : if (m_queue.size() == 0) return -1; 169 : 170 123 : val = m_queue.front(); 171 123 : m_queue.pop_front(); 172 : 173 123 : return 0; 174 199 : } 175 : 176 : template<typename T> 177 1317 : std::size_t QueueMT<T>::size() 178 : { 179 : //! lock 180 : /*! 181 : * \param[in] m_mutex the m mutex 182 : */ 183 1317 : std::lock_guard lock(m_mutex); 184 : 185 1317 : return m_queue.size(); 186 1317 : } 187 : 188 : template<typename T> 189 : bool QueueMT<T>::empty() 190 : { 191 : //! lock 192 : /*! 193 : * \param[in] m_mutex the m mutex 194 : */ 195 : std::lock_guard lock(m_mutex); 196 : 197 : return m_queue.empty(); 198 : } 199 : 200 : template<typename T> 201 199 : int QueueMT<T>::remove_if(std::function<bool(const T &val)> fct) 202 : { 203 : //! lock 204 : /*! 205 : * \param[in] m_mutex the m mutex 206 : */ 207 199 : std::lock_guard lock(m_mutex); 208 : 209 199 : typename std::deque<T>::iterator it; 210 : bool remove; 211 199 : int result = -1; 212 : 213 199 : it = m_queue.begin(); 214 : 215 657 : while (it != m_queue.end()) 216 : { 217 458 : remove = fct(*it); 218 458 : if (remove) 219 : { 220 199 : it = m_queue.erase(it); 221 199 : result = 0; 222 : } 223 : else 224 259 : ++it; 225 : } 226 199 : return result; 227 199 : } 228 : 229 : template<typename T> 230 1 : void QueueMT<T>::for_each(std::function<void(const T &val)> fct) 231 : { 232 : //! lock 233 : /*! 234 : * \param[in] m_mutex the m mutex 235 : */ 236 1 : std::lock_guard lock(m_mutex); 237 : 238 7 : for (auto item : m_queue) fct(item); 239 1 : } 240 : 241 : template<typename T> 242 90 : void QueueMT<T>::clear() 243 : { 244 : //! lock 245 : /*! 246 : * \param[in] m_mutex the m mutex 247 : */ 248 90 : std::lock_guard lock(m_mutex); 249 : 250 90 : m_queue.clear(); 251 90 : } 252 : 253 : } // namespace repo 254 : 255 : } // namespace esys