density
C++11 library for paged memory management, function queues, heterogeneous queues and lifo memory management
conc_heter_queue.h
1 
2 // Copyright Giuseppe Campana (giu.campana@gmail.com) 2016-2018.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 #pragma once
8 #include <density/heter_queue.h>
9 #include <mutex>
10 
11 namespace density
12 {
34  template <typename RUNTIME_TYPE = runtime_type<>, typename ALLOCATOR_TYPE = default_allocator>
36  {
38 
40  enum class PrivateType
41  {
42  };
43 
44  public:
46  static constexpr bool concurrent_puts = true;
47 
49  static constexpr bool concurrent_consumes = true;
50 
53  static constexpr bool concurrent_put_consumes = true;
54 
56  static constexpr bool is_seq_cst = true;
57 
60  constexpr static size_t min_alignment = InnerQueue::min_alignment;
61 
62  using runtime_type = RUNTIME_TYPE;
63  using value_type = std::pair<const runtime_type &, void * const>;
64  using allocator_type = ALLOCATOR_TYPE;
65  using pointer = value_type *;
66  using const_pointer = const value_type *;
67  using reference = value_type;
68  using const_reference = const value_type &;
69  using size_type = std::size_t;
70  using difference_type = std::ptrdiff_t;
71 
72  class iterator;
73  class const_iterator;
74 
84  constexpr conc_heter_queue() noexcept = default;
85 
96  constexpr explicit conc_heter_queue(const ALLOCATOR_TYPE & i_source_allocator) noexcept
97  : m_queue(i_source_allocator)
98  {
99  }
100 
111  constexpr explicit conc_heter_queue(ALLOCATOR_TYPE && i_source_allocator) noexcept
112  : m_queue(std::move(i_source_allocator))
113  {
114  }
115 
125  conc_heter_queue(conc_heter_queue && i_source) noexcept
126  : m_queue(std::move(i_source.m_queue))
127  {
128  }
129 
143  {
144  m_queue = std::move(i_source.m_queue);
145  return *this;
146  }
147 
151  allocator_type
152  get_allocator() noexcept(std::is_nothrow_copy_constructible<allocator_type>::value)
153  {
154  return m_queue.get_allocator();
155  }
156 
160  allocator_type & get_allocator_ref() noexcept { return m_queue.get_allocator_ref(); }
161 
165  const allocator_type & get_allocator_ref() const noexcept
166  {
167  return m_queue.get_allocator_ref();
168  }
169 
173  friend void swap(
176  {
177  swap(i_first.m_queue, i_second.m_queue);
178  }
179 
185  ~conc_heter_queue() = default;
186 
193  bool empty() const noexcept
194  {
195  std::lock_guard<std::mutex> lock(m_mutex);
196  return m_queue.empty();
197  }
198 
206  void clear() noexcept
207  {
208  std::lock_guard<std::mutex> lock(m_mutex);
209  m_queue.clear();
210  }
211 
233  template <typename ELEMENT_COMPLETE_TYPE = void> class put_transaction
234  {
235  static_assert(
236  std::is_same<
237  ELEMENT_COMPLETE_TYPE,
238  typename std::decay<ELEMENT_COMPLETE_TYPE>::type>::value,
239  "");
240 
241  public:
243  put_transaction() noexcept = default;
244 
248  put_transaction(const put_transaction &) = delete;
249 
253  put_transaction & operator=(const put_transaction &) = delete;
254 
262  template <
263  typename OTHERTYPE,
264  typename = typename std::enable_if<
265  std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
266  std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
268  : m_lock(std::move(i_source.m_lock)),
269  m_put_transaction(std::move(i_source.m_put_transaction))
270  {
271  }
272 
278  template <
279  typename OTHERTYPE,
280  typename = typename std::enable_if<
281  std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
282  std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
284  {
285  if (
286  this !=
287  static_cast<void *>(
288  &i_source)) // cast to void to allow comparing pointers to unrelated types
289  {
290  if (!empty())
291  cancel();
292 
293  put_transaction source(std::move(i_source));
294 
295  using namespace density;
296  swap(m_put_transaction, source.m_put_transaction);
297  swap(m_lock, source.m_lock);
298  }
299  return *this;
300  }
301 
305  friend void swap(put_transaction & i_first, put_transaction & i_second) noexcept
306  {
307  using namespace std;
308  swap(i_first.m_put_transaction, i_second.m_put_transaction);
309  swap(i_first.m_lock, i_second.m_lock);
310  }
311 
334  void * raw_allocate(size_t i_size, size_t i_alignment)
335  {
336  return m_put_transaction.raw_allocate(i_size, i_alignment);
337  }
338 
363  template <typename INPUT_ITERATOR>
364  typename std::iterator_traits<INPUT_ITERATOR>::value_type *
365  raw_allocate_copy(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end)
366  {
367  return m_put_transaction.raw_allocate_copy(i_begin, i_end);
368  }
369 
392  template <typename INPUT_RANGE>
393  auto raw_allocate_copy(const INPUT_RANGE & i_source_range)
394  -> decltype(std::declval<put_transaction>().raw_allocate_copy(
395  std::begin(i_source_range), std::end(i_source_range)))
396  {
397  return m_put_transaction.raw_allocate_copy(
398  std::begin(i_source_range), std::end(i_source_range));
399  }
400 
409  void commit() noexcept
410  {
411  DENSITY_ASSERT(m_put_transaction && m_lock.owns_lock());
412  m_put_transaction.commit();
413  m_lock.unlock();
414  }
415 
426  void cancel() noexcept
427  {
428  DENSITY_ASSERT(m_put_transaction && m_lock.owns_lock());
429  m_put_transaction.cancel();
430  m_lock.unlock();
431  }
432 
436  bool empty() const noexcept { return m_put_transaction.empty(); }
437 
441  explicit operator bool() const noexcept { return m_put_transaction.operator bool(); }
442 
443 
455  void * element_ptr() const noexcept
456  {
457  DENSITY_ASSERT(!empty());
458  return m_put_transaction.element_ptr();
459  }
460 
474 #ifndef DOXYGEN_DOC_GENERATION
475  template <
476  typename EL = ELEMENT_COMPLETE_TYPE,
477  typename std::enable_if<!std::is_void<EL>::value>::type * = nullptr>
478  EL &
479 #else
480  ELEMENT_COMPLETE_TYPE &
481 #endif
482  element() const noexcept
483  {
484  return *static_cast<ELEMENT_COMPLETE_TYPE *>(m_put_transaction.element_ptr());
485  }
486 
493  const RUNTIME_TYPE & complete_type() const noexcept
494  {
495  return m_put_transaction.complete_type();
496  }
497 
502  {
503  if (m_lock.owns_lock())
504  {
505  m_put_transaction.cancel();
506  }
507  }
508 
511  PrivateType,
512  std::unique_lock<std::mutex> && i_lock,
513  typename InnerQueue::template put_transaction<ELEMENT_COMPLETE_TYPE> &&
514  i_put_transaction) noexcept
515  : m_lock(std::move(i_lock)), m_put_transaction(std::move(i_put_transaction))
516  {
517  if (!m_put_transaction)
518  m_lock.unlock();
519  }
520 
521  private: // data members
522  std::unique_lock<std::mutex> m_lock;
523  typename InnerQueue::template put_transaction<ELEMENT_COMPLETE_TYPE> m_put_transaction;
524  template <typename OTHERTYPE> friend class put_transaction;
525  };
526 
545  {
546  public:
550  consume_operation() noexcept = default;
551 
555  consume_operation(const consume_operation &) = delete;
556 
560  consume_operation & operator=(const consume_operation &) = delete;
561 
565  consume_operation(consume_operation && i_source) noexcept = default;
566 
571  {
572  m_lock = std::move(i_source.m_lock);
573  m_consume_operation = std::move(i_source.m_consume_operation);
574  return *this;
575  }
576 
581  {
582  if (m_lock.owns_lock())
583  cancel();
584  }
585 
589  friend void swap(consume_operation & i_first, consume_operation & i_second) noexcept
590  {
591  std::swap(i_first.m_lock, i_second.m_lock);
592  std::swap(i_first.m_consume_operation, i_second.m_consume_operation);
593  }
594 
598  bool empty() const noexcept { return m_consume_operation.empty(); }
599 
603  explicit operator bool() const noexcept { return m_consume_operation.operator bool(); }
604 
613  void commit() noexcept
614  {
615  DENSITY_ASSERT(!empty());
616  m_consume_operation.commit();
617  m_lock.unlock();
618  }
619 
637  void commit_nodestroy() noexcept
638  {
639  DENSITY_ASSERT(!empty());
640  m_consume_operation.commit_nodestroy();
641  m_lock.unlock();
642  }
643 
654  void cancel() noexcept
655  {
656  DENSITY_ASSERT(!empty());
657  m_consume_operation.cancel();
658  m_lock.unlock();
659  }
660 
666  const RUNTIME_TYPE & complete_type() const noexcept
667  {
668  return m_consume_operation.complete_type();
669  }
670 
678  void * unaligned_element_ptr() const noexcept
679  {
680  return m_consume_operation.unaligned_element_ptr();
681  }
682 
690  void * element_ptr() const noexcept { return m_consume_operation.element_ptr(); }
691 
698  template <typename COMPLETE_ELEMENT_TYPE>
699  COMPLETE_ELEMENT_TYPE & element() const noexcept
700  {
701  return m_consume_operation.template element<COMPLETE_ELEMENT_TYPE>();
702  }
703 
706  PrivateType,
707  std::unique_lock<std::mutex> && i_lock,
708  typename InnerQueue::consume_operation && i_consume_operation) noexcept
709  : m_lock(std::move(i_lock)), m_consume_operation(std::move(i_consume_operation))
710  {
711  }
712 
714  bool start_consume_impl(PrivateType, conc_heter_queue * i_queue)
715  {
716  if (m_lock.owns_lock())
717  cancel();
718 
719  m_lock = std::unique_lock<std::mutex>(i_queue->m_mutex);
720 
721  bool const result = i_queue->m_queue.try_start_consume(m_consume_operation);
722  if (!result)
723  m_lock.unlock();
724  return result;
725  }
726 
727  private:
728  std::unique_lock<std::mutex> m_lock;
729  typename InnerQueue::consume_operation m_consume_operation;
730  };
731 
749  template <typename ELEMENT_TYPE> void push(ELEMENT_TYPE && i_source)
750  {
751  return emplace<typename std::decay<ELEMENT_TYPE>::type>(
752  std::forward<ELEMENT_TYPE>(i_source));
753  }
754 
771  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
772  void emplace(CONSTRUCTION_PARAMS &&... i_construction_params)
773  {
774  start_emplace<ELEMENT_TYPE>(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...)
775  .commit();
776  }
777 
794  void dyn_push(const runtime_type & i_type) { start_dyn_push(i_type).commit(); }
795 
814  void dyn_push_copy(const runtime_type & i_type, const void * i_source)
815  {
816  start_dyn_push_copy(i_type, i_source).commit();
817  }
818 
837  void dyn_push_move(const runtime_type & i_type, void * i_source)
838  {
839  start_dyn_push_move(i_type, i_source).commit();
840  }
841 
865  template <typename ELEMENT_TYPE>
866  put_transaction<typename std::decay<ELEMENT_TYPE>::type>
867  start_push(ELEMENT_TYPE && i_source)
868  {
869  return start_emplace<typename std::decay<ELEMENT_TYPE>::type>(
870  std::forward<ELEMENT_TYPE>(i_source));
871  }
872 
895  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
896  put_transaction<ELEMENT_TYPE> start_emplace(CONSTRUCTION_PARAMS &&... i_construction_params)
897  {
898  std::unique_lock<std::mutex> lock(m_mutex);
899  return put_transaction<ELEMENT_TYPE>(
900  PrivateType(),
901  std::move(lock),
902  m_queue.template start_emplace<ELEMENT_TYPE>(
903  std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...));
904  }
905 
924  put_transaction<> start_dyn_push(const runtime_type & i_type)
925  {
926  std::unique_lock<std::mutex> lock(m_mutex);
927  return put_transaction<>(
928  PrivateType(), std::move(lock), m_queue.start_dyn_push(i_type));
929  }
930 
931 
952  put_transaction<> start_dyn_push_copy(const runtime_type & i_type, const void * i_source)
953  {
954  std::unique_lock<std::mutex> lock(m_mutex);
955  return put_transaction<>(
956  PrivateType(), std::move(lock), m_queue.start_dyn_push_copy(i_type, i_source));
957  }
958 
979  put_transaction<> start_dyn_push_move(const runtime_type & i_type, void * i_source)
980  {
981  std::unique_lock<std::mutex> lock(m_mutex);
982  return put_transaction<>(
983  PrivateType(), std::move(lock), m_queue.start_dyn_push_move(i_type, i_source));
984  }
985 
986 
1001  void pop() noexcept { try_start_consume().commit(); }
1002 
1013  bool try_pop() noexcept
1014  {
1015  if (auto operation = try_start_consume())
1016  {
1017  operation.commit();
1018  return true;
1019  }
1020  return false;
1021  }
1022 
1029  consume_operation try_start_consume() noexcept
1030  {
1031  std::unique_lock<std::mutex> lock(m_mutex);
1032  auto consume = m_queue.try_start_consume();
1033  if (!consume)
1034  lock.unlock();
1035  return consume_operation(PrivateType(), std::move(lock), std::move(consume));
1036  }
1037 
1051  bool try_start_consume(consume_operation & i_consume) noexcept
1052  {
1053  return i_consume.start_consume_impl(PrivateType(), this);
1054  }
1055 
1056 
1078  template <typename ELEMENT_COMPLETE_TYPE = void> class reentrant_put_transaction
1079  {
1080  static_assert(
1081  std::is_same<
1082  ELEMENT_COMPLETE_TYPE,
1083  typename std::decay<ELEMENT_COMPLETE_TYPE>::type>::value,
1084  "");
1085 
1086  public:
1088  reentrant_put_transaction() noexcept = default;
1089 
1094 
1099 
1107  template <
1108  typename OTHERTYPE,
1109  typename = typename std::enable_if<
1110  std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
1111  std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
1113  : m_queue(i_source.m_queue),
1114  m_put_transaction(std::move(i_source.m_put_transaction))
1115  {
1116  i_source.m_queue = nullptr;
1117  }
1118 
1124  template <
1125  typename OTHERTYPE,
1126  typename = typename std::enable_if<
1127  std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
1128  std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
1131  {
1132  m_queue = i_source.m_queue;
1133  m_put_transaction = std::move(i_source.m_put_transaction);
1134  i_source.m_queue = nullptr;
1135  return *this;
1136  }
1137 
1141  friend void swap(
1142  reentrant_put_transaction & i_first, reentrant_put_transaction & i_second) noexcept
1143  {
1144  std::swap(i_first.m_queue, i_second.m_queue);
1145  std::swap(i_first.m_put_transaction, i_second.m_put_transaction);
1146  }
1147 
1170  void * raw_allocate(size_t i_size, size_t i_alignment)
1171  {
1172  DENSITY_ASSERT(!empty());
1173  std::lock_guard<std::mutex> lock(m_queue->m_mutex);
1174  return m_put_transaction.raw_allocate(i_size, i_alignment);
1175  }
1176 
1201  template <typename INPUT_ITERATOR>
1202  typename std::iterator_traits<INPUT_ITERATOR>::value_type *
1203  raw_allocate_copy(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end)
1204  {
1205  DENSITY_ASSERT(!empty());
1206  std::lock_guard<std::mutex> lock(m_queue->m_mutex);
1207  return m_put_transaction.raw_allocate_copy(i_begin, i_end);
1208  }
1209 
1232  template <typename INPUT_RANGE>
1233  auto raw_allocate_copy(const INPUT_RANGE & i_source_range)
1234  -> decltype(std::declval<reentrant_put_transaction>().raw_allocate_copy(
1235  std::begin(i_source_range), std::end(i_source_range)))
1236  {
1237  DENSITY_ASSERT(!empty());
1238  std::lock_guard<std::mutex> lock(m_queue->m_mutex);
1239  return m_put_transaction.raw_allocate_copy(
1240  std::begin(i_source_range), std::end(i_source_range));
1241  }
1242 
1251  void commit() noexcept
1252  {
1253  DENSITY_ASSERT(!empty());
1254  std::lock_guard<std::mutex> lock(m_queue->m_mutex);
1255  m_put_transaction.commit();
1256  m_queue = nullptr;
1257  }
1258 
1259 
1270  void cancel() noexcept
1271  {
1272  DENSITY_ASSERT(!empty());
1273  std::lock_guard<std::mutex> lock(m_queue->m_mutex);
1274  m_put_transaction.cancel();
1275  m_queue = nullptr;
1276  }
1277 
1281  bool empty() const noexcept { return m_queue == nullptr; }
1282 
1286  explicit operator bool() const noexcept { return m_queue != nullptr; }
1287 
1291  conc_heter_queue * queue() const noexcept { return m_queue; }
1292 
1304  void * element_ptr() const noexcept { return m_put_transaction.element_ptr(); }
1305 
1319 #ifndef DOXYGEN_DOC_GENERATION
1320  template <
1321  typename EL = ELEMENT_COMPLETE_TYPE,
1322  typename std::enable_if<!std::is_void<EL>::value>::type * = nullptr>
1323  EL &
1324 #else
1325  ELEMENT_COMPLETE_TYPE &
1326 #endif
1327  element() const noexcept
1328  {
1329  return *static_cast<ELEMENT_COMPLETE_TYPE *>(element_ptr());
1330  }
1331 
1338  const RUNTIME_TYPE & complete_type() const noexcept
1339  {
1340  return m_put_transaction.complete_type();
1341  }
1342 
1347  {
1348  if (m_put_transaction)
1349  {
1350  cancel();
1351  }
1352  }
1353 
1356  PrivateType,
1357  conc_heter_queue * i_queue,
1358  typename InnerQueue::template reentrant_put_transaction<ELEMENT_COMPLETE_TYPE> &&
1359  i_put_transaction) noexcept
1360  : m_queue(i_queue), m_put_transaction(std::move(i_put_transaction))
1361  {
1362  }
1363 
1364  private:
1365  conc_heter_queue * m_queue = nullptr;
1366  typename InnerQueue::template reentrant_put_transaction<ELEMENT_COMPLETE_TYPE>
1367  m_put_transaction;
1368  template <typename OTHERTYPE> friend class reentrant_put_transaction;
1369  };
1370 
1371 
1389  {
1390  public:
1394  reentrant_consume_operation() noexcept = default;
1395 
1400 
1405 
1409  reentrant_consume_operation(reentrant_consume_operation && i_source) noexcept = default;
1410 
1415  operator=(reentrant_consume_operation && i_source) noexcept = default;
1416 
1421  {
1422  if (!empty())
1423  {
1424  cancel();
1425  }
1426  }
1427 
1431  friend void swap(
1432  reentrant_consume_operation & i_first,
1433  reentrant_consume_operation & i_second) noexcept
1434  {
1435  std::swap(i_first.m_queue, i_second.m_queue);
1436  std::swap(i_first.m_consume_operation, i_second.m_consume_operation);
1437  }
1438 
1442  bool empty() const noexcept { return m_consume_operation.empty(); }
1443 
1447  explicit operator bool() const noexcept { return m_consume_operation.operator bool(); }
1448 
1452  conc_heter_queue * queue() const noexcept { return m_queue; }
1453 
1462  void commit() noexcept
1463  {
1464  DENSITY_ASSERT(!empty());
1465  std::lock_guard<std::mutex> lock(m_queue->m_mutex);
1466  m_consume_operation.commit();
1467  }
1468 
1486  void commit_nodestroy() noexcept
1487  {
1488  DENSITY_ASSERT(!empty());
1489  std::lock_guard<std::mutex> lock(m_queue->m_mutex);
1490  m_consume_operation.commit_nodestroy();
1491  }
1492 
1503  void cancel() noexcept
1504  {
1505  DENSITY_ASSERT(!empty());
1506  std::lock_guard<std::mutex> lock(m_queue->m_mutex);
1507  m_consume_operation.cancel();
1508  }
1509 
1515  const RUNTIME_TYPE & complete_type() const noexcept
1516  {
1517  return m_consume_operation.complete_type();
1518  }
1519 
1527  void * unaligned_element_ptr() const noexcept
1528  {
1529  return m_consume_operation.unaligned_element_ptr();
1530  }
1531 
1539  void * element_ptr() const noexcept { return m_consume_operation.element_ptr(); }
1540 
1547  template <typename COMPLETE_ELEMENT_TYPE>
1548  COMPLETE_ELEMENT_TYPE & element() const noexcept
1549  {
1550  return m_consume_operation.template element<COMPLETE_ELEMENT_TYPE>();
1551  }
1552 
1555  PrivateType,
1556  conc_heter_queue * i_queue,
1557  typename InnerQueue::reentrant_consume_operation && i_consume_operation) noexcept
1558  : m_queue(i_queue), m_consume_operation(std::move(i_consume_operation))
1559  {
1560  }
1561 
1563  bool start_consume_impl(PrivateType, conc_heter_queue * i_queue)
1564  {
1565  DENSITY_ASSUME(i_queue != nullptr);
1566 
1567  // first we take the locks, because they may throw
1568  std::unique_lock<std::mutex> lock;
1569  if (m_queue != nullptr)
1570  {
1571  lock = std::unique_lock<std::mutex>(m_queue->m_mutex);
1572  }
1573  std::unique_lock<std::mutex> new_lock;
1574  if (m_queue != i_queue && i_queue != nullptr)
1575  {
1576  new_lock = std::unique_lock<std::mutex>(i_queue->m_mutex);
1577  }
1578 
1579  // nothing can throw from now on
1580  if (m_consume_operation)
1581  m_consume_operation.cancel();
1582  lock = std::move(new_lock);
1583  m_queue = i_queue;
1584  return m_queue->m_queue.try_start_reentrant_consume(m_consume_operation);
1585  }
1586 
1587  private:
1588  conc_heter_queue * m_queue = nullptr;
1589  typename InnerQueue::reentrant_consume_operation m_consume_operation;
1590  };
1591 
1597  template <typename ELEMENT_TYPE> void reentrant_push(ELEMENT_TYPE && i_source)
1598  {
1599  return reentrant_emplace<ELEMENT_TYPE>(std::forward<ELEMENT_TYPE>(i_source));
1600  }
1601 
1607  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
1608  void reentrant_emplace(CONSTRUCTION_PARAMS &&... i_construction_params)
1609  {
1610  start_reentrant_emplace<typename std::decay<ELEMENT_TYPE>::type>(
1611  std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...)
1612  .commit();
1613  }
1614 
1620  void reentrant_dyn_push(const runtime_type & i_type)
1621  {
1622  start_reentrant_dyn_push(i_type).commit();
1623  }
1624 
1630  void reentrant_dyn_push_copy(const runtime_type & i_type, const void * i_source)
1631  {
1632  start_reentrant_dyn_push_copy(i_type, i_source).commit();
1633  }
1634 
1640  void reentrant_dyn_push_move(const runtime_type & i_type, void * i_source)
1641  {
1642  start_reentrant_dyn_push_move(i_type, i_source).commit();
1643  }
1644 
1650  template <typename ELEMENT_TYPE>
1651  reentrant_put_transaction<typename std::decay<ELEMENT_TYPE>::type>
1652  start_reentrant_push(ELEMENT_TYPE && i_source)
1653  {
1654  return start_reentrant_emplace<typename std::decay<ELEMENT_TYPE>::type>(
1655  std::forward<ELEMENT_TYPE>(i_source));
1656  }
1657 
1663  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
1664  reentrant_put_transaction<ELEMENT_TYPE>
1665  start_reentrant_emplace(CONSTRUCTION_PARAMS &&... i_construction_params)
1666  {
1667  std::lock_guard<std::mutex> lock(m_mutex);
1668  auto put_transaction = m_queue.template start_reentrant_emplace<ELEMENT_TYPE>(
1669  std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
1670  return reentrant_put_transaction<ELEMENT_TYPE>(
1671  PrivateType(), this, std::move(put_transaction));
1672  }
1673 
1679  reentrant_put_transaction<> start_reentrant_dyn_push(const runtime_type & i_type)
1680  {
1681  std::lock_guard<std::mutex> lock(m_mutex);
1682  auto put_transaction = m_queue.start_reentrant_dyn_push(i_type);
1683  return reentrant_put_transaction<>(PrivateType(), this, std::move(put_transaction));
1684  }
1685 
1686 
1692  reentrant_put_transaction<>
1693  start_reentrant_dyn_push_copy(const runtime_type & i_type, const void * i_source)
1694  {
1695  std::lock_guard<std::mutex> lock(m_mutex);
1696  auto put_transaction = m_queue.start_reentrant_dyn_push_copy(i_type, i_source);
1697  return reentrant_put_transaction<>(PrivateType(), this, std::move(put_transaction));
1698  }
1699 
1705  reentrant_put_transaction<>
1706  start_reentrant_dyn_push_move(const runtime_type & i_type, void * i_source)
1707  {
1708  std::lock_guard<std::mutex> lock(m_mutex);
1709  auto put_transaction = m_queue.start_reentrant_dyn_push_move(i_type, i_source);
1710  return reentrant_put_transaction<>(PrivateType(), this, std::move(put_transaction));
1711  }
1712 
1729 
1741  bool try_reentrant_pop() noexcept
1742  {
1743  if (auto operation = try_start_reentrant_consume())
1744  {
1745  operation.commit();
1746  return true;
1747  }
1748  return false;
1749  }
1750 
1751 
1760  reentrant_consume_operation try_start_reentrant_consume() noexcept
1761  {
1762  std::lock_guard<std::mutex> lock(m_mutex);
1763  return reentrant_consume_operation(
1764  PrivateType(), this, m_queue.try_start_reentrant_consume());
1765  }
1766 
1782  bool try_start_reentrant_consume(reentrant_consume_operation & i_consume) noexcept
1783  {
1784  return i_consume.start_consume_impl(PrivateType(), this);
1785  }
1786 
1787  private:
1788  mutable std::mutex m_mutex;
1789  InnerQueue m_queue;
1790  };
1791 
1792 
1793 } // namespace density
allocator_type & get_allocator_ref() noexcept
Definition: conc_heter_queue.h:160
const RUNTIME_TYPE & complete_type() const noexcept
Definition: conc_heter_queue.h:493
allocator_type get_allocator() noexcept(std::is_nothrow_copy_constructible< allocator_type >::value)
Definition: conc_heter_queue.h:152
~reentrant_put_transaction()
Definition: conc_heter_queue.h:1346
void cancel() noexcept
Definition: conc_heter_queue.h:654
Definition: conc_function_queue.h:11
put_transaction start_dyn_push_copy(const runtime_type &i_type, const void *i_source)
Definition: conc_heter_queue.h:952
reentrant_put_transaction< typename std::decay< ELEMENT_TYPE >::type > start_reentrant_push(ELEMENT_TYPE &&i_source)
Definition: conc_heter_queue.h:1652
bool try_reentrant_pop() noexcept
Definition: conc_heter_queue.h:1741
conc_heter_queue * queue() const noexcept
Definition: conc_heter_queue.h:1452
void commit() noexcept
Definition: conc_heter_queue.h:1462
void reentrant_push(ELEMENT_TYPE &&i_source)
Definition: conc_heter_queue.h:1597
~consume_operation()
Definition: conc_heter_queue.h:580
~put_transaction()
Definition: conc_heter_queue.h:501
void dyn_push_copy(const runtime_type &i_type, const void *i_source)
Definition: conc_heter_queue.h:814
void * element_ptr() const noexcept
Definition: conc_heter_queue.h:455
void * element_ptr() const noexcept
Definition: conc_heter_queue.h:1539
const RUNTIME_TYPE & complete_type() const noexcept
Definition: conc_heter_queue.h:1515
static constexpr size_t min_alignment
Definition: conc_heter_queue.h:60
constexpr conc_heter_queue(ALLOCATOR_TYPE &&i_source_allocator) noexcept
Definition: conc_heter_queue.h:111
void * raw_allocate(size_t i_size, size_t i_alignment)
Definition: conc_heter_queue.h:334
Definition: conc_heter_queue.h:1078
put_transaction< typename std::decay< ELEMENT_TYPE >::type > start_push(ELEMENT_TYPE &&i_source)
Definition: conc_heter_queue.h:867
void commit_nodestroy() noexcept
Definition: conc_heter_queue.h:1486
ELEMENT_COMPLETE_TYPE & element() const noexcept
Definition: conc_heter_queue.h:1327
void reentrant_pop() noexcept
Definition: conc_heter_queue.h:1728
Definition: runtime_type.h:1061
Definition: heter_queue.h:200
void commit() noexcept
Definition: conc_heter_queue.h:409
put_transaction start_dyn_push(const runtime_type &i_type)
Definition: conc_heter_queue.h:924
reentrant_put_transaction< ELEMENT_TYPE > start_reentrant_emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: conc_heter_queue.h:1665
void * unaligned_element_ptr() const noexcept
Definition: conc_heter_queue.h:678
void reentrant_dyn_push_move(const runtime_type &i_type, void *i_source)
Definition: conc_heter_queue.h:1640
static constexpr bool is_seq_cst
Definition: conc_heter_queue.h:56
void commit() noexcept
Definition: conc_heter_queue.h:613
reentrant_consume_operation try_start_reentrant_consume() noexcept
Definition: conc_heter_queue.h:1760
Definition: conc_heter_queue.h:544
void reentrant_dyn_push(const runtime_type &i_type)
Definition: conc_heter_queue.h:1620
constexpr conc_heter_queue() noexcept=default
static constexpr bool concurrent_put_consumes
Definition: conc_heter_queue.h:53
#define DENSITY_ASSERT(...)
Definition: density_config.h:19
bool empty() const noexcept
Definition: conc_heter_queue.h:598
COMPLETE_ELEMENT_TYPE & element() const noexcept
Definition: conc_heter_queue.h:1548
put_transaction(put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: conc_heter_queue.h:267
reentrant_put_transaction start_reentrant_dyn_push_move(const runtime_type &i_type, void *i_source)
Definition: conc_heter_queue.h:1706
reentrant_put_transaction start_reentrant_dyn_push(const runtime_type &i_type)
Definition: conc_heter_queue.h:1679
Definition: heter_queue.h:843
void * element_ptr() const noexcept
Definition: conc_heter_queue.h:1304
reentrant_consume_operation try_start_reentrant_consume() noexcept
Definition: heter_queue.h:2322
bool empty() const noexcept
Definition: conc_heter_queue.h:1442
void cancel() noexcept
Definition: conc_heter_queue.h:1270
std::iterator_traits< INPUT_ITERATOR >::value_type * raw_allocate_copy(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end)
Definition: conc_heter_queue.h:365
consume_operation & operator=(consume_operation &&i_source) noexcept
Definition: conc_heter_queue.h:570
void reentrant_dyn_push_copy(const runtime_type &i_type, const void *i_source)
Definition: conc_heter_queue.h:1630
friend void swap(consume_operation &i_first, consume_operation &i_second) noexcept
Definition: conc_heter_queue.h:589
bool empty() const noexcept
Definition: conc_heter_queue.h:436
conc_heter_queue(conc_heter_queue &&i_source) noexcept
Definition: conc_heter_queue.h:125
void emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: conc_heter_queue.h:772
~reentrant_consume_operation()
Definition: conc_heter_queue.h:1420
reentrant_put_transaction start_reentrant_dyn_push_copy(const runtime_type &i_type, const void *i_source)
Definition: conc_heter_queue.h:1693
Definition: conc_heter_queue.h:35
reentrant_put_transaction & operator=(reentrant_put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: conc_heter_queue.h:1130
const allocator_type & get_allocator_ref() const noexcept
Definition: conc_heter_queue.h:165
void * unaligned_element_ptr() const noexcept
Definition: conc_heter_queue.h:1527
friend void swap(conc_heter_queue< RUNTIME_TYPE, ALLOCATOR_TYPE > &i_first, conc_heter_queue< RUNTIME_TYPE, ALLOCATOR_TYPE > &i_second) noexcept
Definition: conc_heter_queue.h:173
conc_heter_queue & operator=(conc_heter_queue &&i_source) noexcept
Definition: conc_heter_queue.h:142
conc_heter_queue * queue() const noexcept
Definition: conc_heter_queue.h:1291
Definition: conc_heter_queue.h:233
bool empty() const noexcept
Definition: conc_heter_queue.h:1281
void reentrant_emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: conc_heter_queue.h:1608
auto raw_allocate_copy(const INPUT_RANGE &i_source_range) -> decltype(std::declval< put_transaction >().raw_allocate_copy( std::begin(i_source_range), std::end(i_source_range)))
Definition: conc_heter_queue.h:393
std::iterator_traits< INPUT_ITERATOR >::value_type * raw_allocate_copy(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end)
Definition: conc_heter_queue.h:1203
ELEMENT_COMPLETE_TYPE & element() const noexcept
Definition: conc_heter_queue.h:482
const RUNTIME_TYPE & complete_type() const noexcept
Definition: conc_heter_queue.h:1338
static constexpr bool concurrent_puts
Definition: conc_heter_queue.h:46
consume_operation try_start_consume() noexcept
Definition: heter_queue.h:1456
COMPLETE_ELEMENT_TYPE & element() const noexcept
Definition: conc_heter_queue.h:699
void push(ELEMENT_TYPE &&i_source)
Definition: conc_heter_queue.h:749
auto raw_allocate_copy(const INPUT_RANGE &i_source_range) -> decltype(std::declval< reentrant_put_transaction >().raw_allocate_copy( std::begin(i_source_range), std::end(i_source_range)))
Definition: conc_heter_queue.h:1233
static constexpr bool concurrent_consumes
Definition: conc_heter_queue.h:49
reentrant_put_transaction(reentrant_put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: conc_heter_queue.h:1112
friend void swap(reentrant_consume_operation &i_first, reentrant_consume_operation &i_second) noexcept
Definition: conc_heter_queue.h:1431
void commit_nodestroy() noexcept
Definition: conc_heter_queue.h:637
put_transaction & operator=(put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: conc_heter_queue.h:283
void * element_ptr() const noexcept
Definition: conc_heter_queue.h:690
bool try_start_consume(consume_operation &i_consume) noexcept
Definition: conc_heter_queue.h:1051
void dyn_push_move(const runtime_type &i_type, void *i_source)
Definition: conc_heter_queue.h:837
void dyn_push(const runtime_type &i_type)
Definition: conc_heter_queue.h:794
consume_operation try_start_consume() noexcept
Definition: conc_heter_queue.h:1029
void cancel() noexcept
Definition: conc_heter_queue.h:1503
void cancel() noexcept
Definition: conc_heter_queue.h:426
const RUNTIME_TYPE & complete_type() const noexcept
Definition: conc_heter_queue.h:666
bool try_pop() noexcept
Definition: conc_heter_queue.h:1013
void commit() noexcept
Definition: conc_heter_queue.h:1251
void * raw_allocate(size_t i_size, size_t i_alignment)
Definition: conc_heter_queue.h:1170
static constexpr size_t min_alignment
Definition: heter_queue.h:218
#define DENSITY_ASSUME(bool_expr,...)
Definition: density_config.h:46
void clear() noexcept
Definition: conc_heter_queue.h:206
void pop() noexcept
Definition: conc_heter_queue.h:1001
bool empty() const noexcept
Definition: conc_heter_queue.h:193
friend void swap(reentrant_put_transaction &i_first, reentrant_put_transaction &i_second) noexcept
Definition: conc_heter_queue.h:1141
bool try_start_reentrant_consume(reentrant_consume_operation &i_consume) noexcept
Definition: conc_heter_queue.h:1782
friend void swap(put_transaction &i_first, put_transaction &i_second) noexcept
Definition: conc_heter_queue.h:305
put_transaction< ELEMENT_TYPE > start_emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: conc_heter_queue.h:896
put_transaction start_dyn_push_move(const runtime_type &i_type, void *i_source)
Definition: conc_heter_queue.h:979