libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
thread_safe_adaptors_impl.hpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2004 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE { namespace ppd { namespace private_ {
20 /*
21  This is a hack to reduce the amount of reference counting we have to do in pop_front_1_nochk_nolk().
22 */
23 template<class Cont>
24 struct pop_front_t {
25  Cont &cont;
26 
27  explicit constexpr pop_front_t(Cont &c) noexcept(true) FORCE_INLINE
28  : cont(c) {}
29  ~pop_front_t() noexcept(true) FORCE_INLINE {
30  cont.pop_front();
31  }
32 };
33 /*
34  This is a hack to reduce the amount of reference counting we have to do in pop_front_1_nochk_nolk().
35 */
36 template<class Cont>
37 struct pop_t {
38  Cont &cont;
39 
40  constexpr pop_t(Cont &c) noexcept(true) FORCE_INLINE
41  : cont(c) {}
42  ~pop_t() noexcept(true) FORCE_INLINE {
43  cont.pop();
44  }
45 };
46 
47 } }
48 
49 template<class Lk> inline typename ppd::signalling<Lk>::atomic_t::lock_result_type
50 ppd::signalling<Lk>::remove() noexcept(noexcept(have_work_->lock(0))) {
51  assert(dynamic_cast<atomic_t *>(have_work_));
52  // This uses try_lock(), which won't block if the signalled size is empty. Note that the signalled size and the actual number of items in the collection is not an invariant under multi-threading conditions.
53  return have_work_->lock(0);
54 }
55 
56 template<class Lk> inline void
57 ppd::signalling<Lk>::remove(typename atomic_t::count_type const c) noexcept(false) {
58  for (typename atomic_t::count_type i=0; i<c; ++i) {
59  [[maybe_unused]] const typename atomic_t::lock_result_type ret=remove();
60  assert(ret.second!=atomic_t::lock_result_type::second_type::atom_abandoned);
61  }
62 }
63 
64 template<class Lk> inline typename ppd::signalling<Lk>::atomic_t::lock_result_type
65 ppd::signalling<Lk>::try_remove() noexcept(noexcept(have_work_->try_lock())) {
66  assert(dynamic_cast<atomic_t *>(have_work_));
67  return have_work_->try_lock();
68 }
69 
70 template<class Lk> inline void
71 ppd::signalling<Lk>::clear() noexcept(noexcept(have_work_->clear())) {
72  assert(dynamic_cast<atomic_t *>(have_work_));
73  have_work_->clear();
74 }
75 
76 template<class Lk> inline typename ppd::signalling<Lk>::atomic_t::count_type
77 ppd::signalling<Lk>::count() const noexcept(noexcept(have_work_->count())) {
78  assert(dynamic_cast<atomic_t const *>(have_work_));
79  return have_work_->count();
80 }
81 
82 template<typename C, typename M, typename WL, class Sig, class MLk> inline
83 ppd::safe_colln<C, M, WL, Sig, MLk>::safe_colln() noexcept(noexcept(container_type()) && noexcept(have_work_type()))
85 }
86 
87 template<typename C, typename M, typename WL, class Sig, class MLk> inline
88 ppd::safe_colln<C, M, WL, Sig, MLk>::safe_colln(typename have_work_type::atomic_t &ev)
89 : container_type(), have_work(ev) {
90 }
91 
92 template<typename C, typename M, typename WL, class Sig, class MLk> inline
93 ppd::safe_colln<C, M, WL, Sig, MLk>::safe_colln(std::initializer_list<value_type> v)
94 : container_type(v), have_work() {
95 }
96 
97 template<typename C, typename M, typename WL, class Sig, class MLk> inline
98 ppd::safe_colln<C, M, WL, Sig, MLk>::safe_colln(size_type const sz, value_type const &v)
99 : container_type(sz, v), have_work() {
100 }
101 
102 template<typename C, typename M, typename WL, class Sig, class MLk>
103 template<class T1, class T2> inline
104 ppd::safe_colln<C, M, WL, Sig, MLk>::safe_colln(size_type const sz, T1 const &, T2 const &)
105 : container_type(sz), have_work() {
106  have_work.add(container_type::size());
107 }
108 
109 template<typename C, typename M, typename WL, class Sig, class MLk> inline
110 ppd::safe_colln<C, M, WL, Sig, MLk>::safe_colln(const container_type &t)
111 : container_type(t), have_work() {
112  have_work.add(container_type::size());
113 }
114 
115 template<typename C, typename M, typename WL, class Sig, class MLk> inline
116 ppd::safe_colln<C, M, WL, Sig, MLk>::safe_colln(const safe_colln &t) noexcept(false)
117 : container_type(), have_work(t.have_work) {
118  const read_lock_type lk(t.pop_lock(), lock_traits::infinite_timeout());
119  container_type::insert(container_type::begin(), t.begin(), t.end());
120  have_work.add(container_type::size());
121 }
122 
123 template<typename C, typename M, typename WL, class Sig, class MLk> inline
124 ppd::safe_colln<C, M, WL, Sig, MLk>::~safe_colln() {
125 }
126 
127 template<typename C, typename M, typename WL, class Sig, class MLk> inline ppd::safe_colln<C, M, WL, Sig, MLk> &
128 ppd::safe_colln<C, M, WL, Sig, MLk>::operator=(const safe_colln &t) noexcept(false) {
129  const read_lock_type lock1(t.pop_lock(), lock_traits::infinite_timeout());
130  const write_lock_type lock2(push_lock(), lock_traits::infinite_timeout());
131  have_work.clear();
132  container_type::operator=(t);
133  have_work.add(container_type::size());
134  return *this;
135 }
136 
137 template<typename C, typename M, typename WL, class Sig, class MLk> inline
138 bool
139 ppd::safe_colln<C, M, WL, Sig, MLk>::empty() const noexcept(true) {
140  const read_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
141  return container_type::empty();
142 }
143 
144 template<typename C, typename M, typename WL, class Sig, class MLk> inline
145 typename ppd::safe_colln<C, M, WL, Sig, MLk>::size_type
146 ppd::safe_colln<C, M, WL, Sig, MLk>::sync_size() const noexcept(false) {
147  const read_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
148  if (static_cast<size_type>(have_work.count())<container_type::size()) {
149  have_work.add(container_type::size()-have_work.count());
150  }
151  return container_type::size();
152 }
153 
154 template<typename C, typename M, typename WL, class Sig, class MLk> inline
155 typename ppd::safe_colln<C, M, WL, Sig, MLk>::size_type
156 ppd::safe_colln<C, M, WL, Sig, MLk>::size() const noexcept(true) {
157  const read_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
158  return container_type::size();
159 }
160 
161 template<typename C, typename M, typename WL, class Sig, class MLk> inline
162 typename ppd::safe_colln<C, M, WL, Sig, MLk>::value_type
163 ppd::safe_colln<C, M, WL, Sig, MLk>::operator[](size_type s) const noexcept(false) {
164  const write_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
165  return container_type::operator[](s);
166 }
167 
168 template<typename C, typename M, typename WL, class Sig, class MLk> inline void
169 ppd::safe_colln<C, M, WL, Sig, MLk>::push_back(value_type const &v) noexcept(false) {
170  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
171  container_type::push_back(v);
172  have_work.add();
173 }
174 
175 template<typename C, typename M, typename WL, class Sig, class MLk> inline void
176 ppd::safe_colln<C, M, WL, Sig, MLk>::push_back(value_type &&v) noexcept(false) {
177  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
178  container_type::push_back(v);
179  have_work.add();
180 }
181 
182 template<typename C, typename M, typename WL, class Sig, class MLk> inline void
183 ppd::safe_colln<C, M, WL, Sig, MLk>::push_front(const value_type &v) noexcept(false) {
184  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
185  container_type::push_front(v);
186  have_work.add();
187 }
188 
189 template<typename C, typename M, typename WL, class Sig, class MLk> inline void
190 ppd::safe_colln<C, M, WL, Sig, MLk>::push_front(value_type &&v) noexcept(false) {
191  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
192  container_type::push_front(v);
193  have_work.add();
194 }
195 
196 template<typename C, typename M, typename WL, class Sig, class MLk> inline
197 typename ppd::safe_colln<C, M, WL, Sig, MLk>::size_type
198 ppd::safe_colln<C, M, WL, Sig, MLk>::erase(const value_type &v) noexcept(false) {
199  const write_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
200  size_type elems_erased=0;
201  typename container_type::container_type::iterator b;
202  while ((b=std::find(this->c.begin(), this->c.end(), v))!=this->c.end()) {
203  this->c.erase(b);
204  ++elems_erased;
205  }
206  have_work.remove(elems_erased);
207  return elems_erased;
208 }
209 
210 template<typename C, typename M, typename WL, class Sig, class MLk> inline void
211 ppd::safe_colln<C, M, WL, Sig, MLk>::reserve(size_type sz) noexcept(false) {
212  const write_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
213  container_type::reserve(sz);
214 }
215 
216 template<typename C, typename M, typename WL, class Sig, class MLk> inline void
217 ppd::safe_colln<C, M, WL, Sig, MLk>::clear() noexcept(false) {
218  const write_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
219  if (!container_type::empty()) {
220  have_work.clear();
221  container_type().swap(*this);
222  }
223 }
224 
225 template<typename C, typename M, typename WL, class Sig, class MLk> inline bool
226 ppd::safe_colln<C, M, WL, Sig, MLk>::operator==(safe_colln const &sc) const noexcept(true) {
227  const read_lock_type lk(sc.pop_lock(), lock_traits::infinite_timeout());
228  const read_lock_type lk1(pop_lock(), lock_traits::infinite_timeout());
229  return this->colln()==sc.colln();
230 }
231 
232 template<typename C, typename M, typename WL, class Sig, class MLk>
233 template<typename M1, typename WL1, class Sig1, class MLk1>
234 inline bool
235 ppd::safe_colln<C, M, WL, Sig, MLk>::operator==(safe_colln<C, M1, WL1, Sig1, MLk1> const &sc) const noexcept(true) {
236  const typename safe_colln<C, M1, WL1, Sig1, MLk1>::read_lock_type lk(sc.pop_lock(), safe_colln<C, M1, WL1, Sig1, MLk1>::lock_traits::infinite_timeout());
237  const read_lock_type lk1(pop_lock(), lock_traits::infinite_timeout());
238  return this->colln()==sc.colln();
239 }
240 
241 template<typename C, typename M, typename WL, class Sig, class MLk> inline void
242 ppd::safe_colln<C, M, WL, Sig, MLk>::resize_noinit_nolk(const size_type sz) noexcept(false) {
243  const size_type cont_sz=container_type::size();
244  if (cont_sz<sz) {
245  container_type::reserve(sz);
246  std::fill_n(std::back_inserter(colln()), sz-cont_sz, value_type());
247  have_work.add(sz-cont_sz);
248  } else if (cont_sz>sz) {
249  have_work.remove(cont_sz-sz);
250  const typename container_type::iterator new_end(std::next(container_type::begin(), sz));
251  container_type::erase(new_end, container_type::end());
252  }
253 }
254 
255 template<typename C, typename M, typename WL, class Sig, class MLk> inline void
256 ppd::safe_colln<C, M, WL, Sig, MLk>::resize(const size_type sz) noexcept(false) {
257  const write_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
258  container_type::resize(sz);
259  const size_type cont_sz=container_type::size();
260  if (cont_sz<sz) {
261  have_work.add(sz-cont_sz);
262  } else if (cont_sz>sz) {
263  have_work.remove(cont_sz-sz);
264  }
265 }
266 
267 template<typename C, typename M, typename WL, class Sig, class MLk> inline void
268 ppd::safe_colln<C, M, WL, Sig, MLk>::swap(safe_colln &t) noexcept(false) {
269  // TODO
270 }
271 
272 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline
273 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::queue() noexcept(noexcept(container_type()) && noexcept(have_work_type())) : container_type(), have_work() {
274 }
275 
276 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline
277 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::queue(typename have_work_type::atomic_t &ev) : container_type(), have_work(ev) {
278 }
279 
280 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline
281 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::queue(const queue &t) noexcept(false)
282 : container_type(), have_work(t.have_work) {
283  const read_lock_type lock2(t.pop_lock(), lock_traits::infinite_timeout());
284  const read_lock_type lock1(t.push_lock(), lock_traits::infinite_timeout());
285  container_type::insert(container_type::begin(), t.begin(), t.end());
286  have_work.add(container_type::size());
287 }
288 
289 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline
290 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::~queue() noexcept(true) {
291 }
292 
293 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline ppd::queue<QT, M, WL, Sig, ValRet, MLk> &
294 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::operator=(const queue &t) noexcept(false) {
295  const read_lock_type lock1(t.pop_lock(), atomic_t::lock_traits::infinite_timeout());
296  const write_lock_type lock2(pop_lock(), atomic_t::lock_traits::infinite_timeout());
297  have_work.clear();
298  container_type::operator=(t);
299  have_work.add(container_type::size());
300  return *this;
301 }
302 
303 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline bool
304 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::empty() const noexcept(true) {
305  const read_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
306  return container_type::empty();
307 }
308 
309 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::queue<QT, M, WL, Sig, ValRet, MLk>::size_type
310 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::sync_size() const noexcept(false) {
311  const read_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
312  if (have_work.count()<container_type::size()) {
313  have_work.add(container_type::size()-have_work.count());
314  }
315  return container_type::size();
316 }
317 
318 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::queue<QT, M, WL, Sig, ValRet, MLk>::size_type
319 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::size() const noexcept(true) {
320  const read_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
321  return container_type::size();
322 }
323 
324 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::queue<QT, M, WL, Sig, ValRet, MLk>::value_type
325 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::front() const noexcept(false) {
326  // Guarantee that only one item at a time can be removed.
327  const write_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
328  if (!container_type::empty()) {
329  return container_type::front();
330  } else {
331  throw exception_type(
332  _T("Collection empty."),
333  info::function(
334  __LINE__,
335  __PRETTY_FUNCTION__,
336  typeid(*this)
337  ),
339  );
340  }
341 }
342 
343 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
344 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::push_back(value_type const &v) noexcept(false) {
345  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
346  container_type::push_back(v);
347  have_work.add();
348 }
349 
350 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
351 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::push_back(value_type &&v) noexcept(false) {
352  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
353  container_type::push_back(std::move(v));
354  have_work.add();
355 }
356 
357 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
358 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::push_front(const value_type &v) noexcept(false) {
359  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
360  container_type::push_front(v);
361  have_work.add();
362 }
363 
364 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
365 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::push_front(value_type &&v) noexcept(false) {
366  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
367  container_type::push_front(std::forward<value_ret_type>(v));
368  have_work.add();
369 }
370 
371 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::queue<QT, M, WL, Sig, ValRet, MLk>::size_type
372 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::erase(const value_type &v) noexcept(false) {
373  const write_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
374  const size_type elems_erased(container_type::erase(v));
375  have_work.remove(elems_erased);
376  return elems_erased;
377 }
378 
379 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
380 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::clear() noexcept(false) {
381  const write_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
382  if (!container_type::empty()) {
383  have_work.clear();
384  }
385  container_type::clear();
386 }
387 
388 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::queue<QT, M, WL, Sig, ValRet, MLk>::value_type
389 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::pop_front_1_nochk_nolk() noexcept(noexcept(have_work.remove())) {
390  typedef private_::pop_front_t<container_type> pop_t;
391 
392  have_work.remove();
393  const pop_t pop(*this);
394  return container_type::front();
395 }
396 
397 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::queue<QT, M, WL, Sig, ValRet, MLk>::value_type
398 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::pop_front_1_nochk_nosig() noexcept(true) {
399  typedef private_::pop_front_t<container_type> pop_t;
400 
401  const write_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
402  const pop_t pop(*this);
403  return container_type::front();
404 }
405 
406 #pragma GCC diagnostic push
407 // There's no sensible way to provide a simple specialisation that can remove the warning, which is due to possible use of GSS(k) batching in the queue, so we have to just ignore this warning.
408 #pragma GCC diagnostic ignored "-Wmissing-braces"
409 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::queue<QT, M, WL, Sig, ValRet, MLk>::value_ret_type
410 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::pop_front_nochk_nolk() noexcept(false) {
411  return value_ret_type{
413  };
414 }
415 #pragma GCC diagnostic pop
416 
417 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::queue<QT, M, WL, Sig, ValRet, MLk>::value_ret_type
418 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::pop_front_nolk() noexcept(false) {
419  if (!container_type::empty()) {
420  return this->pop_front_nochk_nolk();
421  } else {
422  throw exception_type(
423  _T("Collection empty."),
424  info::function(
425  __LINE__,
426  __PRETTY_FUNCTION__,
427  typeid(&ppd::queue<QT, M, WL, Sig, ValRet, MLk>::pop_front_nolk)
428  ),
430  );
431  }
432 }
433 
434 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::queue<QT, M, WL, Sig, ValRet, MLk>::value_ret_type
435 ppd::queue<QT, M, WL, Sig, ValRet, MLk>::pop_front() noexcept(false) {
436  const write_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
437  return pop_front_nolk();
438 }
439 
440 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline
441 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::funky_queue() noexcept(noexcept(container_type()) && noexcept(have_work_type())) : container_type(), have_work() {
442 }
443 
444 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline
445 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::funky_queue(typename have_work_type::atomic_t & ev) : container_type(), have_work(ev) {
446 }
447 
448 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline
449 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::funky_queue(const funky_queue &t) noexcept(false)
450 : container_type(), have_work(t.have_work) {
451  const read_lock_type lock2(t.pop_lock(), lock_traits::infinite_timeout());
452  const read_lock_type lock1(t.push_lock(), lock_traits::infinite_timeout());
453  container_type::insert(container_type::begin(), t.begin(), t.end());
454  have_work.add(container_type::size());
455 }
456 
457 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline
458 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::~funky_queue() {
459 }
460 
461 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk> &
462 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::operator=(const funky_queue &t) noexcept(false) {
463  const scoped_lock<atomic_t, atomic_t, atomic_t, atomic_t> wait(t.push_lock(), t.pop_lock(), push_lock(), pop_lock());
464  have_work.clear();
465  container_type::operator=(t);
466  have_work.add(container_type::size());
467  return *this;
468 }
469 
470 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline bool
471 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::empty() const noexcept(true) {
472  const read_lock_type lock2(pop_lock(), lock_traits::infinite_timeout());
473  const read_lock_type lock1(push_lock(), lock_traits::infinite_timeout());
474  return container_type::empty();
475 }
476 
477 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::size_type
478 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::sync_size() const noexcept(false) {
479  const read_lock_type lock2(pop_lock(), lock_traits::infinite_timeout());
480  const read_lock_type lock1(push_lock(), lock_traits::infinite_timeout());
481  if (have_work.count()<container_type::size()) {
482  have_work.add(container_type::size()-have_work.count());
483  }
484  return container_type::size();
485 }
486 
487 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::size_type
488 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::size() const noexcept(true) {
489  const read_lock_type lk(pop_lock(), lock_traits::infinite_timeout());
490  return container_type::size();
491 }
492 
493 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
494 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::clear() noexcept(false) {
495  // Note that this takes out write locks on the funky_queue.
496  const scoped_lock<atomic_t, atomic_t> wait(push_lock(), pop_lock());
497  have_work.clear();
498  container_type::clear();
499 }
500 
501 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline bool
502 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::erase(value_type const &v) noexcept(false) {
503  // Note that this takes out write locks on the funky_queue.
504  const scoped_lock<atomic_t, atomic_t> wait(push_lock(), pop_lock());
505  const typename container_type::iterator it(std::find(container_type::begin(), container_type::end(), v));
506  if (it!=container_type::end()) {
507  [[maybe_unused]] const typename have_work_type::atomic_t::lock_result_type ret=have_work.remove();
508  assert(ret.second!=have_work_type::lock_traits::atom_abandoned);
509  container_type::erase(it);
510  return true;
511  } else {
512  return false;
513  }
514 }
515 
516 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_type
517 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::front() const noexcept(false) {
518  // Guarantee that only one item at a time can be removed.
519  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
520  if (container_type::size()>=serialise_size) {
521  return container_type::front();
522  } else {
523  const write_lock_type lk1(pop_lock(), lock_traits::infinite_timeout());
524  if (!container_type::empty()) {
525  return container_type::front();
526  } else {
527  throw exception_type(
528  _T("Collection empty."),
529  info::function(
530  __LINE__,
531  __PRETTY_FUNCTION__,
532  typeid(*this)
533  ),
535  );
536  }
537  }
538 }
539 
540 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_type
541 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::back() const noexcept(false) {
542  // Guarantee that only one item at a time can be removed.
543  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
544  if (container_type::size()>=serialise_size) {
545  return container_type::back();
546  } else {
547  const write_lock_type lk1(pop_lock(), lock_traits::infinite_timeout());
548  if (!container_type::empty()) {
549  return container_type::back();
550  } else {
551  throw exception_type(
552  _T("Collection empty."),
553  info::function(
554  __LINE__,
555  __PRETTY_FUNCTION__,
556  typeid(&ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::back)
557  ),
559  );
560  }
561  }
562 }
563 
564 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
565 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::push(value_type const &v) noexcept(false) {
566  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
567  if (container_type::size()>=serialise_size) {
568  container_type::push(v);
569  } else {
570  const write_lock_type lk1(pop_lock(), lock_traits::infinite_timeout());
571  container_type::push(v);
572  }
573  have_work.add();
574 }
575 
576 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
577 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::push(value_type &&v) noexcept(false) {
578  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
579  if (container_type::size()>=serialise_size) {
580  container_type::push(v);
581  } else {
582  const write_lock_type lk1(pop_lock(), lock_traits::infinite_timeout());
583  container_type::push(v);
584  }
585  have_work.add();
586 }
587 
588 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
589 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::push_back(value_type const &v) noexcept(false) {
590  if (size()>=serialise_size) {
591  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
592  container_type::push_back(v);
593  } else {
594  const scoped_lock<atomic_t, atomic_t> wait(push_lock(), pop_lock());
595  container_type::push_back(v);
596  }
597  have_work.add();
598 }
599 
600 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
601 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::push_back(value_type &&v) noexcept(false) {
602  if (size()>=serialise_size) {
603  const write_lock_type lk(push_lock(), lock_traits::infinite_timeout());
604  container_type::push_back(v);
605  } else {
606  const scoped_lock<atomic_t, atomic_t> wait(push_lock(), pop_lock());
607  container_type::push_back(v);
608  }
609  have_work.add();
610 }
611 
612 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_type &
613 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::back_nolk() noexcept(true) {
614  return container_type::back();
615 }
616 
617 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_type const &
618 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::back_nolk() const noexcept(true) {
619  return container_type::back();
620 }
621 
622 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
623 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::push_back_nolk(const value_type &e) noexcept(false) {
624  container_type::push_back(e);
625  assert(!empty());
626  have_work.add();
627 }
628 
629 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
630 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::push_back_nolk(value_type &&e) noexcept(false) {
631  container_type::push_back(e);
632  assert(!empty());
633  have_work.add();
634 }
635 
636 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
637 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::push_nolk(const value_type &e) noexcept(false) {
638  container_type::push(e);
639  assert(!empty());
640  have_work.add();
641 }
642 
643 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
644 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::push_nolk(value_type &&e) noexcept(false) {
645  container_type::push(e);
646  assert(!empty());
647  have_work.add();
648 }
649 
650 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline void
651 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::pop_nochk_nolk() noexcept(false) {
652  [[maybe_unused]] const typename have_work_type::atomic_t::lock_result_type ret=have_work.remove();
653  assert(ret.second!=have_work_type::lock_traits::atom_abandoned);
654  container_type::pop();
655 }
656 
657 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_type
658 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::pop_front_1_nochk_nolk() noexcept(noexcept(have_work.remove())) {
659  typedef private_::pop_front_t<container_type> pop_t;
660 
661  have_work.remove();
662  const pop_t pop(*this);
663  return container_type::front();
664 }
665 
666 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_type
667 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::pop_front_1_nochk_nosig() noexcept(true) {
668  typedef private_::pop_front_t<container_type> pop_t;
669 
670  const write_lock_type excl_push_lk(pop_lock(), lock_traits::infinite_timeout());
671  const pop_t pop(*this);
672  return container_type::front();
673 }
674 
675 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_ret_type
676 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::pop_front_nochk_nolk() noexcept(false) {
677  return value_ret_type{
679  };
680 }
681 
682 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_ret_type
683 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::pop_nolk() noexcept(false) {
684  typedef private_::pop_t<container_type> pop_t;
685 
686  [[maybe_unused]] const typename have_work_type::atomic_t::lock_result_type ret=have_work.remove();
687  assert(ret.second!=have_work_type::lock_traits::atom_abandoned);
688  const pop_t pop(*this);
689  return container_type::front();
690 }
691 
692 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_ret_type
693 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::pop_front_nolk() noexcept(false) {
694  if (container_type::size()>=serialise_size) {
695  return this->pop_front_nochk_nolk();
696  } else {
697  const write_lock_type excl_push_lk(push_lock(), lock_traits::infinite_timeout());
698  if (!container_type::empty()) {
699  return this->pop_front_nochk_nolk();
700  } else {
701  throw exception_type(
702  _T("Collection empty."),
703  info::function(
704  __LINE__,
705  __PRETTY_FUNCTION__,
706  typeid(&ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::pop_front_nolk)
707  ),
709  );
710  }
711  }
712 }
713 
714 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_ret_type
715 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::pop() noexcept(false) {
716  const write_lock_type excl_pop_lk(pop_lock(), lock_traits::infinite_timeout());
717  if (container_type::size()>=serialise_size) {
718  return pop_nolk();
719  } else {
720  const write_lock_type excl_push_lk(push_lock(), lock_traits::infinite_timeout());
721  return pop_nolk();
722  }
723 }
724 
725 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline typename ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::value_ret_type
726 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::pop_front() noexcept(false) {
727  const write_lock_type excl_pop_lk(pop_lock(), lock_traits::infinite_timeout());
728  if (container_type::size()>=serialise_size) {
729  return this->pop_front_nochk_nolk();
730  } else {
731  const write_lock_type excl_push_lk(push_lock(), lock_traits::infinite_timeout());
732  if (!container_type::empty()) {
733  return this->pop_front_nochk_nolk();
734  } else {
735  throw exception_type(
736  _T("Collection empty."),
737  info::function(
738  __LINE__,
739  __PRETTY_FUNCTION__,
740  typeid(&ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::pop_front)
741  ),
743  );
744  }
745  }
746 }
747 
748 template<typename QT, typename M, typename WL, class Sig, class ValRet, class MLk> inline
749 void
750 ppd::funky_queue<QT, M, WL, Sig, ValRet, MLk>::remove(const value_type &e) noexcept(false) {
751  // Note that this takes out write locks on the queue.
752  const scoped_lock<atomic_t, atomic_t> wait(push_lock(), pop_lock());
753  assert(!container_type::empty());
754  [[maybe_unused]] const typename have_work_type::atomic_t::atomic_state_type ret=have_work.remove();
755  assert(ret!=have_work_type::atomic_t::atom_abandoned);
756  container_type::remove(e);
757 }
758 
759 } }