density
C++11 library for paged memory management, function queues, heterogeneous queues and lifo memory management
sp_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/default_allocator.h>
10 #include <density/raw_atomic.h>
11 #include <density/runtime_type.h>
12 #include <limits>
13 #include <mutex>
14 #include <thread>
15 #include <type_traits>
16 
17 #ifdef _MSC_VER
18 #if defined(_M_IX86) || defined(_M_X64)
19 #include <immintrin.h> // for _mm_pause
20 #endif
21 #pragma warning(push)
22 #pragma warning(disable : 4324) // structure was padded due to alignment specifier
23 #endif
24 
25 #include <density/detail/lf_queue_base.h>
26 #include <density/detail/lf_queue_head_multiple.h>
27 #include <density/detail/lf_queue_head_single.h>
28 #include <density/detail/lf_queue_tail_single.h>
29 #include <density/detail/sp_queue_tail_multiple.h>
30 
31 namespace density
32 {
33  namespace detail
34  {
35  template <
36  typename RUNTIME_TYPE,
37  typename ALLOCATOR_TYPE,
38  concurrency_cardinality PROD_CARDINALITY,
39  typename BUSY_WAIT_FUNC>
40  using SpQueue_Tail = typename std::conditional<
41  PROD_CARDINALITY == concurrency_single,
42  LFQueue_Tail<RUNTIME_TYPE, ALLOCATOR_TYPE, concurrency_single, consistency_sequential>,
43  SpQueue_TailMultiple<RUNTIME_TYPE, ALLOCATOR_TYPE, BUSY_WAIT_FUNC>>::type;
44  }
45 
48  {
49  public:
51  void operator()() noexcept
52  {
53 #if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
54  _mm_pause();
55 #else
56  std::this_thread::yield();
57 #endif
58  }
59  };
60 
202  template <
203  typename RUNTIME_TYPE = runtime_type<>,
204  typename ALLOCATOR_TYPE = default_allocator,
206  concurrency_cardinality CONSUMER_CARDINALITY = concurrency_multiple,
207  typename BUSY_WAIT_FUNC = default_busy_wait>
209  : private detail::LFQueue_Head<
210  RUNTIME_TYPE,
211  ALLOCATOR_TYPE,
212  CONSUMER_CARDINALITY,
213  detail::SpQueue_Tail<RUNTIME_TYPE, ALLOCATOR_TYPE, PROD_CARDINALITY, BUSY_WAIT_FUNC>>
214  {
215  private:
216  using Base = detail::LFQueue_Head<
217  RUNTIME_TYPE,
218  ALLOCATOR_TYPE,
219  CONSUMER_CARDINALITY,
220  detail::SpQueue_Tail<RUNTIME_TYPE, ALLOCATOR_TYPE, PROD_CARDINALITY, BUSY_WAIT_FUNC>>;
221  using Base::try_inplace_allocate;
222  using typename Base::Allocation;
223  using typename Base::Consume;
224  using typename Base::ControlBlock;
225 
227  enum class PrivateType
228  {
229  };
230 
231  public:
233  constexpr static size_t min_alignment = Base::min_alignment;
234 
235  using runtime_type = RUNTIME_TYPE;
236  using value_type = std::pair<const runtime_type &, void * const>;
237  using allocator_type = ALLOCATOR_TYPE;
238  using pointer = value_type *;
239  using const_pointer = const value_type *;
240  using reference = value_type;
241  using const_reference = const value_type &;
242  using size_type = std::size_t;
243  using difference_type = std::ptrdiff_t;
244 
246  static constexpr bool concurrent_puts = PROD_CARDINALITY == concurrency_multiple;
247 
249  static constexpr bool concurrent_consumes = CONSUMER_CARDINALITY == concurrency_multiple;
250 
253  static constexpr bool concurrent_put_consumes = true;
254 
256  static constexpr bool is_seq_cst = true;
257 
258  static_assert(
259  is_power_of_2(ALLOCATOR_TYPE::page_alignment) &&
260  ALLOCATOR_TYPE::page_alignment >= ALLOCATOR_TYPE::page_size &&
261  (ALLOCATOR_TYPE::page_alignment % min_alignment) == 0,
262  "The alignment of the pages must be a power of 2, greater or equal to the size of the "
263  "pages, and a multiple of min_alignment");
264 
265  static_assert(
266  ALLOCATOR_TYPE::page_size > (min_alignment + alignof(ControlBlock)) * 4,
267  "Invalid page size");
268 
278  constexpr sp_heter_queue() noexcept = default;
279 
290  constexpr explicit sp_heter_queue(const ALLOCATOR_TYPE & i_source_allocator) noexcept
291  : Base(i_source_allocator)
292  {
293  }
294 
305  constexpr explicit sp_heter_queue(ALLOCATOR_TYPE && i_source_allocator) noexcept
306  : Base(std::move(i_source_allocator))
307  {
308  static_assert(std::is_nothrow_move_constructible<ALLOCATOR_TYPE>::value, "");
309  }
310 
322  constexpr sp_heter_queue(
323  const ALLOCATOR_TYPE & i_source_allocator, const BUSY_WAIT_FUNC & i_source_wait) noexcept
324  : Base(
325  i_source_allocator,
326  i_source_wait,
327  std::integral_constant<bool, PROD_CARDINALITY == concurrency_multiple>())
328  {
329  }
330 
342  constexpr sp_heter_queue(
343  ALLOCATOR_TYPE && i_source_allocator, const BUSY_WAIT_FUNC & i_source_wait) noexcept
344  : Base(
345  std::move(i_source_allocator),
346  i_source_wait,
347  std::integral_constant<bool, PROD_CARDINALITY == concurrency_multiple>())
348  {
349  static_assert(std::is_nothrow_move_constructible<ALLOCATOR_TYPE>::value, "");
350  }
351 
363  constexpr sp_heter_queue(
364  const ALLOCATOR_TYPE & i_source_allocator, BUSY_WAIT_FUNC && i_source_wait) noexcept
365  : Base(
366  i_source_allocator,
367  std::move(i_source_wait),
368  std::integral_constant<bool, PROD_CARDINALITY == concurrency_multiple>())
369  {
370  static_assert(std::is_nothrow_move_constructible<BUSY_WAIT_FUNC>::value, "");
371  }
372 
384  constexpr sp_heter_queue(
385  ALLOCATOR_TYPE && i_source_allocator, BUSY_WAIT_FUNC && i_source_wait) noexcept
386  : Base(
387  std::move(i_source_allocator),
388  std::move(i_source_wait),
389  std::integral_constant<bool, PROD_CARDINALITY == concurrency_multiple>())
390  {
391  static_assert(std::is_nothrow_move_constructible<ALLOCATOR_TYPE>::value, "");
392  static_assert(std::is_nothrow_move_constructible<BUSY_WAIT_FUNC>::value, "");
393  }
394 
404  sp_heter_queue(sp_heter_queue && i_source) noexcept = default;
405 
418  sp_heter_queue & operator=(sp_heter_queue && i_source) noexcept
419  {
420  swap(*this, i_source);
421  return *this;
422  }
423 
427  allocator_type
428  get_allocator() noexcept(std::is_nothrow_copy_constructible<allocator_type>::value)
429  {
430  return *this;
431  }
432 
436  allocator_type & get_allocator_ref() noexcept { return *this; }
437 
441  const allocator_type & get_allocator_ref() const noexcept { return *this; }
442 
446  friend void swap(sp_heter_queue & i_first, sp_heter_queue & i_second) noexcept
447  {
448  swap(static_cast<Base &>(i_first), static_cast<Base &>(i_second));
449  }
450 
457  {
458  clear();
459 
460  Consume consume;
461  consume.begin_iteration(this);
462  if (!consume.empty())
463  {
464  consume.clean_dead_elements();
465  }
466  }
467 
474  bool empty() const noexcept { return Consume().is_queue_empty(this); }
475 
483  void clear() noexcept
484  {
485  consume_operation consume;
486  while (try_start_consume(consume))
487  {
488  consume.commit();
489  }
490  }
491 
513  template <typename ELEMENT_COMPLETE_TYPE = void> class put_transaction
514  {
515  static_assert(
516  std::is_same<
517  ELEMENT_COMPLETE_TYPE,
518  typename std::decay<ELEMENT_COMPLETE_TYPE>::type>::value,
519  "");
520 
521  public:
523  put_transaction() noexcept = default;
524 
528  put_transaction(const put_transaction &) = delete;
529 
533  put_transaction & operator=(const put_transaction &) = delete;
534 
542  template <
543  typename OTHERTYPE,
544  typename = typename std::enable_if<
545  std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
546  std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
548  : m_put(i_source.m_put), m_queue(i_source.m_queue)
549  {
550  i_source.m_put.m_user_storage = nullptr;
551  }
552 
558  template <
559  typename OTHERTYPE,
560  typename = typename std::enable_if<
561  std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
562  std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
564  {
565  using std::swap;
566  swap(m_put, i_source.m_put);
567  swap(m_queue, i_source.m_queue);
568  return *this;
569  }
570 
574  friend void swap(put_transaction & i_first, put_transaction & i_second) noexcept
575  {
576  using std::swap;
577  swap(i_first.m_put, i_second.m_put);
578  swap(i_first.m_queue, i_second.m_queue);
579  }
580 
603  void * raw_allocate(size_t i_size, size_t i_alignment)
604  {
605  DENSITY_ASSERT(!empty());
606  auto push_data =
607  m_queue->template try_inplace_allocate_impl<detail::LfQueue_Throwing>(
608  detail::LfQueue_Dead, false, i_size, i_alignment);
609  return push_data.m_user_storage;
610  }
611 
636  template <typename INPUT_ITERATOR>
637  typename std::iterator_traits<INPUT_ITERATOR>::value_type *
638  raw_allocate_copy(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end)
639  {
640  using ValueType = typename std::iterator_traits<INPUT_ITERATOR>::value_type;
641  static_assert(
642  std::is_trivially_destructible<ValueType>::value,
643  "raw_allocate_copy provides a raw memory in-place allocation that does not "
644  "invoke "
645  "destructors when deallocating");
646 
647  auto const count_s = std::distance(i_begin, i_end);
648  auto const count = static_cast<size_t>(count_s);
649  DENSITY_ASSUME(static_cast<decltype(count_s)>(count) == count_s);
650 
651  auto const elements = static_cast<ValueType *>(
652  raw_allocate(sizeof(ValueType) * count, alignof(ValueType)));
653  for (auto curr = elements; i_begin != i_end; ++i_begin, ++curr)
654  new (curr) ValueType(*i_begin);
655  return elements;
656  }
657 
680  template <typename INPUT_RANGE>
681  auto raw_allocate_copy(const INPUT_RANGE & i_source_range)
682  -> decltype(std::declval<put_transaction>().raw_allocate_copy(
683  std::begin(i_source_range), std::end(i_source_range)))
684  {
685  return raw_allocate_copy(std::begin(i_source_range), std::end(i_source_range));
686  }
687 
719  progress_guarantee i_progress_guarantee, size_t i_size, size_t i_alignment) noexcept
720  {
721  DENSITY_ASSERT(!empty());
722  auto push_data = m_queue->try_inplace_allocate(
723  i_progress_guarantee, detail::LfQueue_Dead, false, i_size, i_alignment);
724  return push_data.m_user_storage;
725  }
726 
760  template <typename INPUT_ITERATOR>
761  typename std::iterator_traits<INPUT_ITERATOR>::value_type * try_raw_allocate_copy(
762  progress_guarantee i_progress_guarantee,
763  INPUT_ITERATOR i_begin,
764  INPUT_ITERATOR
765  i_end) noexcept(std::
766  is_nothrow_copy_constructible<typename std::iterator_traits<
767  INPUT_ITERATOR>::value_type>::value)
768  {
769  using ValueType = typename std::iterator_traits<INPUT_ITERATOR>::value_type;
770  static_assert(
771  std::is_trivially_destructible<ValueType>::value,
772  "raw_allocate_copy provides a raw memory in-place allocation that does not "
773  "invoke "
774  "destructors when deallocating");
775 
776  auto const count_s = std::distance(i_begin, i_end);
777  auto const count = static_cast<size_t>(count_s);
778  DENSITY_ASSUME(static_cast<decltype(count_s)>(count) == count_s);
779 
780  auto const elements = static_cast<ValueType *>(try_raw_allocate(
781  i_progress_guarantee, sizeof(ValueType) * count, alignof(ValueType)));
782  if (elements != nullptr)
783  {
784  for (auto curr = elements; i_begin != i_end; ++i_begin, ++curr)
785  new (curr) ValueType(*i_begin);
786  }
787  return elements;
788  }
789 
821  template <typename INPUT_RANGE>
823  progress_guarantee i_progress_guarantee,
824  const INPUT_RANGE & i_source_range) noexcept(noexcept(std::declval<put_transaction>()
825  .try_raw_allocate_copy(
826  i_progress_guarantee,
827  std::begin(i_source_range),
828  std::end(i_source_range))))
829  -> decltype(std::declval<put_transaction>().try_raw_allocate_copy(
830  i_progress_guarantee, std::begin(i_source_range), std::end(i_source_range)))
831  {
832  return try_raw_allocate_copy(
833  i_progress_guarantee, std::begin(i_source_range), std::end(i_source_range));
834  }
835 
844  void commit() noexcept
845  {
846  DENSITY_ASSERT(!empty());
847  Base::commit_put_impl(m_put);
848  m_put.m_user_storage = nullptr;
849  }
850 
861  void cancel() noexcept
862  {
863  DENSITY_ASSERT(!empty());
864  Base::cancel_put_impl(m_put);
865  m_put.m_user_storage = nullptr;
866  }
867 
871  bool empty() const noexcept { return m_put.m_user_storage == nullptr; }
872 
876  explicit operator bool() const noexcept { return m_put.m_user_storage != nullptr; }
877 
881  sp_heter_queue * queue() const noexcept
882  {
883  return m_put.m_user_storage != nullptr ? m_queue : nullptr;
884  }
885 
897  void * element_ptr() const noexcept
898  {
899  DENSITY_ASSERT(!empty());
900  return m_put.m_user_storage;
901  }
902 
916 #ifndef DOXYGEN_DOC_GENERATION
917  template <
918  typename EL = ELEMENT_COMPLETE_TYPE,
919  typename std::enable_if<!std::is_void<EL>::value>::type * = nullptr>
920  EL &
921 #else
922  ELEMENT_COMPLETE_TYPE &
923 #endif
924  element() const noexcept
925  {
926  return *static_cast<ELEMENT_COMPLETE_TYPE *>(element_ptr());
927  }
928 
935  const RUNTIME_TYPE & complete_type() const noexcept
936  {
937  DENSITY_ASSERT(!empty());
938  return *Base::type_after_control(m_put.m_control_block);
939  }
940 
945  {
946  if (m_put.m_user_storage != nullptr)
947  {
948  Base::cancel_put_impl(m_put);
949  }
950  }
951 
954  PrivateType, sp_heter_queue * i_queue, const Allocation & i_put) noexcept
955  : m_put(i_put), m_queue(i_queue)
956  {
957  }
958 
959  private:
960  Allocation m_put;
961  sp_heter_queue * m_queue;
962  template <typename OTHERTYPE> friend class put_transaction;
963  };
964 
983  {
984  public:
988  consume_operation() noexcept = default;
989 
993  consume_operation(const consume_operation &) = delete;
994 
998  consume_operation & operator=(const consume_operation &) = delete;
999 
1003  consume_operation(consume_operation && i_source) noexcept = default;
1004 
1008  consume_operation & operator=(consume_operation && i_source) noexcept = default;
1009 
1014  {
1015  if (!m_consume_data.empty())
1016  {
1017  m_consume_data.cancel_consume_impl();
1018  }
1019  }
1020 
1024  friend void swap(consume_operation & i_first, consume_operation & i_second) noexcept
1025  {
1026  i_first.m_consume_data.swap(i_second.m_consume_data);
1027  }
1028 
1032  bool empty() const noexcept { return m_consume_data.empty(); }
1033 
1037  explicit operator bool() const noexcept { return !m_consume_data.empty(); }
1038 
1042  sp_heter_queue * queue() const noexcept
1043  {
1044  return static_cast<sp_heter_queue *>(m_consume_data.m_queue);
1045  }
1046 
1055  void commit() noexcept
1056  {
1057  DENSITY_ASSERT(!empty());
1058 
1059  auto const & type = complete_type();
1060  auto const element = element_ptr();
1061  type.destroy(element);
1062 
1063  type.RUNTIME_TYPE::~RUNTIME_TYPE();
1064 
1065  m_consume_data.commit_consume_impl();
1066  }
1067 
1085  void commit_nodestroy() noexcept
1086  {
1087  DENSITY_ASSERT(!empty());
1088 
1089  bool destroy_type = !std::is_trivially_destructible<RUNTIME_TYPE>::value;
1090  if (destroy_type)
1091  {
1092  auto const & type = complete_type();
1093  type.RUNTIME_TYPE::~RUNTIME_TYPE();
1094  }
1095 
1096  m_consume_data.commit_consume_impl();
1097  }
1098 
1109  void cancel() noexcept
1110  {
1111  DENSITY_ASSERT(!empty());
1112  m_consume_data.cancel_consume_impl();
1113  }
1114 
1120  const RUNTIME_TYPE & complete_type() const noexcept
1121  {
1122  DENSITY_ASSERT(!empty());
1123  return *Base::type_after_control(m_consume_data.m_control);
1124  }
1125 
1133  void * unaligned_element_ptr() const noexcept
1134  {
1135  DENSITY_ASSERT(!empty());
1136  return Base::get_unaligned_element(
1137  m_consume_data.m_control, m_consume_data.external());
1138  }
1139 
1147  void * element_ptr() const noexcept
1148  {
1149  DENSITY_ASSERT(!empty());
1150  return Base::get_element(m_consume_data.m_control, m_consume_data.external());
1151  }
1152 
1159  template <typename COMPLETE_ELEMENT_TYPE>
1160  COMPLETE_ELEMENT_TYPE & element() const noexcept
1161  {
1162  DENSITY_ASSERT(!empty() && complete_type().template is<COMPLETE_ELEMENT_TYPE>());
1163  return *static_cast<COMPLETE_ELEMENT_TYPE *>(
1164  Base::get_element(m_consume_data.m_control, m_consume_data.external()));
1165  }
1166 
1168  consume_operation(PrivateType, sp_heter_queue * i_queue) noexcept
1169  {
1170  m_consume_data.start_consume_impl(i_queue);
1171  }
1172 
1174  bool start_consume_impl(PrivateType, sp_heter_queue * i_queue)
1175  {
1176  if (!m_consume_data.empty())
1177  {
1178  m_consume_data.cancel_consume_impl();
1179  }
1180 
1181  m_consume_data.start_consume_impl(i_queue);
1182 
1183  return !m_consume_data.empty();
1184  }
1185 
1186  private:
1187  Consume m_consume_data;
1188  };
1189 
1207  template <typename ELEMENT_TYPE> void push(ELEMENT_TYPE && i_source)
1208  {
1209  return emplace<typename std::decay<ELEMENT_TYPE>::type>(
1210  std::forward<ELEMENT_TYPE>(i_source));
1211  }
1212 
1229  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
1230  void emplace(CONSTRUCTION_PARAMS &&... i_construction_params)
1231  {
1232  start_emplace<ELEMENT_TYPE>(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...)
1233  .commit();
1234  }
1235 
1252  void dyn_push(const runtime_type & i_type) { start_dyn_push(i_type).commit(); }
1253 
1272  void dyn_push_copy(const runtime_type & i_type, const void * i_source)
1273  {
1274  start_dyn_push_copy(i_type, i_source).commit();
1275  }
1276 
1295  void dyn_push_move(const runtime_type & i_type, void * i_source)
1296  {
1297  start_dyn_push_move(i_type, i_source).commit();
1298  }
1299 
1324  template <typename ELEMENT_TYPE>
1325  put_transaction<typename std::decay<ELEMENT_TYPE>::type>
1326  start_push(ELEMENT_TYPE && i_source)
1327  {
1328  return start_emplace<typename std::decay<ELEMENT_TYPE>::type>(
1329  std::forward<ELEMENT_TYPE>(i_source));
1330  }
1331 
1354  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
1355  put_transaction<ELEMENT_TYPE> start_emplace(CONSTRUCTION_PARAMS &&... i_construction_params)
1356  {
1357  auto push_data = Base::template try_inplace_allocate_impl<
1358  detail::LfQueue_Throwing,
1359  detail::LfQueue_Busy,
1360  true,
1361  detail::size_of<ELEMENT_TYPE>::value,
1362  alignof(ELEMENT_TYPE)>();
1363 
1364  runtime_type * type = nullptr;
1365  try
1366  {
1367  auto const type_storage = Base::type_after_control(push_data.m_control_block);
1368  DENSITY_ASSUME(type_storage != nullptr);
1369  type = new (type_storage) runtime_type(runtime_type::template make<ELEMENT_TYPE>());
1370 
1371  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
1372  new (push_data.m_user_storage)
1373  ELEMENT_TYPE(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
1374  }
1375  catch (...)
1376  {
1377  if (type != nullptr)
1378  type->RUNTIME_TYPE::~RUNTIME_TYPE();
1379 
1380  Base::cancel_put_nodestroy_impl(push_data);
1381  throw;
1382  }
1383 
1384  return put_transaction<ELEMENT_TYPE>(PrivateType(), this, push_data);
1385  }
1386 
1405  put_transaction<> start_dyn_push(const runtime_type & i_type)
1406  {
1407  auto push_data = Base::template try_inplace_allocate_impl<detail::LfQueue_Throwing>(
1408  detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
1409 
1410  runtime_type * type = nullptr;
1411  try
1412  {
1413  auto const type_storage = Base::type_after_control(push_data.m_control_block);
1414  DENSITY_ASSUME(type_storage != nullptr);
1415  type = new (type_storage) runtime_type(i_type);
1416 
1417  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
1418  i_type.default_construct(push_data.m_user_storage);
1419  }
1420  catch (...)
1421  {
1422  if (type != nullptr)
1423  type->RUNTIME_TYPE::~RUNTIME_TYPE();
1424 
1425  Base::cancel_put_nodestroy_impl(push_data);
1426  throw;
1427  }
1428 
1429  return put_transaction<void>(PrivateType(), this, push_data);
1430  }
1431 
1432 
1453  put_transaction<> start_dyn_push_copy(const runtime_type & i_type, const void * i_source)
1454  {
1455  auto push_data = Base::template try_inplace_allocate_impl<detail::LfQueue_Throwing>(
1456  detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
1457 
1458  runtime_type * type = nullptr;
1459  try
1460  {
1461  auto const type_storage = Base::type_after_control(push_data.m_control_block);
1462  DENSITY_ASSUME(type_storage != nullptr);
1463  type = new (type_storage) runtime_type(i_type);
1464 
1465  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
1466  i_type.copy_construct(push_data.m_user_storage, i_source);
1467  }
1468  catch (...)
1469  {
1470  if (type != nullptr)
1471  type->RUNTIME_TYPE::~RUNTIME_TYPE();
1472  Base::cancel_put_nodestroy_impl(push_data);
1473  throw;
1474  }
1475 
1476  return put_transaction<void>(PrivateType(), this, push_data);
1477  }
1478 
1499  put_transaction<> start_dyn_push_move(const runtime_type & i_type, void * i_source)
1500  {
1501  auto push_data = Base::template try_inplace_allocate_impl<detail::LfQueue_Throwing>(
1502  detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
1503 
1504  runtime_type * type = nullptr;
1505  try
1506  {
1507  auto const type_storage = Base::type_after_control(push_data.m_control_block);
1508  DENSITY_ASSUME(type_storage != nullptr);
1509  type = new (type_storage) runtime_type(i_type);
1510 
1511  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
1512  i_type.move_construct(push_data.m_user_storage, i_source);
1513  }
1514  catch (...)
1515  {
1516  if (type != nullptr)
1517  type->RUNTIME_TYPE::~RUNTIME_TYPE();
1518  Base::cancel_put_nodestroy_impl(push_data);
1519  throw;
1520  }
1521 
1522  return put_transaction<void>(PrivateType(), this, push_data);
1523  }
1524 
1551  template <typename ELEMENT_TYPE>
1552  bool try_push(progress_guarantee i_progress_guarantee, ELEMENT_TYPE && i_source) noexcept(
1553  noexcept(std::declval<sp_heter_queue>()
1554  .template try_emplace<typename std::decay<ELEMENT_TYPE>::type>(
1555  i_progress_guarantee, std::forward<ELEMENT_TYPE>(i_source))))
1556  {
1557  return try_emplace<typename std::decay<ELEMENT_TYPE>::type>(
1558  i_progress_guarantee, std::forward<ELEMENT_TYPE>(i_source));
1559  }
1560 
1586  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
1587  bool
1588  try_emplace(progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&... i_construction_params) noexcept(
1589  noexcept(std::declval<sp_heter_queue>().template try_start_emplace<ELEMENT_TYPE>(
1590  i_progress_guarantee, std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...)))
1591  {
1592  auto tranasction = try_start_emplace<ELEMENT_TYPE>(
1593  i_progress_guarantee, std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
1594  if (!tranasction)
1595  return false;
1596  tranasction.commit();
1597  return true;
1598  }
1599 
1624  bool try_dyn_push(progress_guarantee i_progress_guarantee, const runtime_type & i_type)
1625  {
1626  auto tranasction = try_start_dyn_push(i_progress_guarantee, i_type);
1627  if (!tranasction)
1628  return false;
1629  tranasction.commit();
1630  return true;
1631  }
1632 
1660  progress_guarantee i_progress_guarantee,
1661  const runtime_type & i_type,
1662  const void * i_source)
1663  {
1664  auto tranasction = try_start_dyn_push_copy(i_progress_guarantee, i_type, i_source);
1665  if (!tranasction)
1666  return false;
1667  tranasction.commit();
1668  return true;
1669  }
1670 
1698  progress_guarantee i_progress_guarantee, const runtime_type & i_type, void * i_source)
1699  {
1700  auto tranasction = try_start_dyn_push_move(i_progress_guarantee, i_type, i_source);
1701  if (!tranasction)
1702  return false;
1703  tranasction.commit();
1704  return true;
1705  }
1706 
1739  template <typename ELEMENT_TYPE>
1740  put_transaction<typename std::decay<ELEMENT_TYPE>::type> try_start_push(
1741  progress_guarantee i_progress_guarantee,
1742  ELEMENT_TYPE && i_source) noexcept(noexcept(std::declval<sp_heter_queue>()
1743  .template try_start_emplace<
1744  typename std::decay<ELEMENT_TYPE>::type>(
1745  i_progress_guarantee,
1746  std::forward<ELEMENT_TYPE>(i_source))))
1747  {
1748  return try_start_emplace<typename std::decay<ELEMENT_TYPE>::type>(
1749  i_progress_guarantee, std::forward<ELEMENT_TYPE>(i_source));
1750  }
1751 
1782  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
1783  put_transaction<ELEMENT_TYPE>
1784  try_start_emplace(progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&... i_construction_params) noexcept(
1785  noexcept(ELEMENT_TYPE(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...)) &&
1786  noexcept(runtime_type(runtime_type::template make<ELEMENT_TYPE>())))
1787  {
1788  auto push_data = Base::template try_inplace_allocate<
1789  detail::LfQueue_Busy,
1790  true,
1791  detail::size_of<ELEMENT_TYPE>::value,
1792  alignof(ELEMENT_TYPE)>(i_progress_guarantee);
1793  if (push_data.m_user_storage == nullptr)
1794  {
1795  return put_transaction<ELEMENT_TYPE>();
1796  }
1797 
1798  constexpr bool is_noexcept =
1799  std::is_nothrow_constructible<ELEMENT_TYPE, CONSTRUCTION_PARAMS...>::value &&
1800  noexcept(runtime_type(runtime_type::template make<ELEMENT_TYPE>()));
1801 
1802  runtime_type * type = nullptr;
1803 
1804  if (is_noexcept)
1805  {
1806  auto const type_storage = Base::type_after_control(push_data.m_control_block);
1807  DENSITY_ASSUME(type_storage != nullptr);
1808  type = new (type_storage) runtime_type(runtime_type::template make<ELEMENT_TYPE>());
1809 
1810  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
1811  new (push_data.m_user_storage)
1812  ELEMENT_TYPE(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
1813  }
1814  else
1815  {
1816  try
1817  {
1818  auto const type_storage = Base::type_after_control(push_data.m_control_block);
1819  DENSITY_ASSUME(type_storage != nullptr);
1820  type =
1821  new (type_storage) runtime_type(runtime_type::template make<ELEMENT_TYPE>());
1822 
1823  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
1824  new (push_data.m_user_storage)
1825  ELEMENT_TYPE(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
1826  }
1827  catch (...)
1828  {
1829  if (type != nullptr)
1830  type->RUNTIME_TYPE::~RUNTIME_TYPE();
1831 
1832  Base::cancel_put_nodestroy_impl(push_data);
1833  DENSITY_INTERNAL_RETHROW_FROM_NOEXCEPT
1834  }
1835  }
1836 
1837  return put_transaction<ELEMENT_TYPE>(PrivateType(), this, push_data);
1838  }
1839 
1866  put_transaction<>
1867  try_start_dyn_push(progress_guarantee i_progress_guarantee, const runtime_type & i_type)
1868  {
1869  auto push_data = Base::try_inplace_allocate(
1870  i_progress_guarantee, detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
1871  if (push_data.m_user_storage == nullptr)
1872  {
1873  return put_transaction<>();
1874  }
1875 
1876  runtime_type * type = nullptr;
1877  try
1878  {
1879  auto const type_storage = Base::type_after_control(push_data.m_control_block);
1880  DENSITY_ASSUME(type_storage != nullptr);
1881  type = new (type_storage) runtime_type(i_type);
1882 
1883  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
1884  i_type.default_construct(push_data.m_user_storage);
1885  }
1886  catch (...)
1887  {
1888  if (type != nullptr)
1889  type->RUNTIME_TYPE::~RUNTIME_TYPE();
1890 
1891  Base::cancel_put_nodestroy_impl(push_data);
1892  throw;
1893  }
1894 
1895  return put_transaction<void>(PrivateType(), this, push_data);
1896  }
1897 
1898 
1927  put_transaction<> try_start_dyn_push_copy(
1928  progress_guarantee i_progress_guarantee,
1929  const runtime_type & i_type,
1930  const void * i_source)
1931  {
1932  auto push_data = Base::try_inplace_allocate(
1933  i_progress_guarantee, detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
1934  if (push_data.m_user_storage == nullptr)
1935  {
1936  return put_transaction<>();
1937  }
1938 
1939  runtime_type * type = nullptr;
1940  try
1941  {
1942  auto const type_storage = Base::type_after_control(push_data.m_control_block);
1943  DENSITY_ASSUME(type_storage != nullptr);
1944  type = new (type_storage) runtime_type(i_type);
1945 
1946  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
1947  i_type.copy_construct(push_data.m_user_storage, i_source);
1948  }
1949  catch (...)
1950  {
1951  if (type != nullptr)
1952  type->RUNTIME_TYPE::~RUNTIME_TYPE();
1953  Base::cancel_put_nodestroy_impl(push_data);
1954  throw;
1955  }
1956 
1957  return put_transaction<void>(PrivateType(), this, push_data);
1958  }
1959 
1988  put_transaction<> try_start_dyn_push_move(
1989  progress_guarantee i_progress_guarantee, const runtime_type & i_type, void * i_source)
1990  {
1991  auto push_data = Base::try_inplace_allocate(
1992  i_progress_guarantee, detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
1993  if (push_data.m_user_storage == nullptr)
1994  {
1995  return put_transaction<>();
1996  }
1997 
1998  runtime_type * type = nullptr;
1999  try
2000  {
2001  auto const type_storage = Base::type_after_control(push_data.m_control_block);
2002  DENSITY_ASSUME(type_storage != nullptr);
2003  type = new (type_storage) runtime_type(i_type);
2004 
2005  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
2006  i_type.move_construct(push_data.m_user_storage, i_source);
2007  }
2008  catch (...)
2009  {
2010  if (type != nullptr)
2011  type->RUNTIME_TYPE::~RUNTIME_TYPE();
2012  Base::cancel_put_nodestroy_impl(push_data);
2013  throw;
2014  }
2015 
2016  return put_transaction<void>(PrivateType(), this, push_data);
2017  }
2018 
2029  bool try_pop() noexcept
2030  {
2031  if (auto operation = try_start_consume())
2032  {
2033  operation.commit();
2034  return true;
2035  }
2036  return false;
2037  }
2038 
2045  consume_operation try_start_consume() noexcept
2046  {
2047  return consume_operation(PrivateType(), this);
2048  }
2049 
2063  bool try_start_consume(consume_operation & i_consume) noexcept
2064  {
2065  return i_consume.start_consume_impl(PrivateType(), this);
2066  }
2067 
2068 
2090  template <typename ELEMENT_COMPLETE_TYPE = void> class reentrant_put_transaction
2091  {
2092  static_assert(
2093  std::is_same<
2094  ELEMENT_COMPLETE_TYPE,
2095  typename std::decay<ELEMENT_COMPLETE_TYPE>::type>::value,
2096  "");
2097 
2098  public:
2100  reentrant_put_transaction() noexcept = default;
2101 
2106 
2110  reentrant_put_transaction & operator=(const reentrant_put_transaction &) = delete;
2111 
2119  template <
2120  typename OTHERTYPE,
2121  typename = typename std::enable_if<
2122  std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
2123  std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
2125  : m_put(i_source.m_put), m_queue(i_source.m_queue)
2126  {
2127  i_source.m_put.m_user_storage = nullptr;
2128  }
2129 
2135  template <
2136  typename OTHERTYPE,
2137  typename = typename std::enable_if<
2138  std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
2139  std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
2142  {
2143  using std::swap;
2144  swap(m_put, i_source.m_put);
2145  swap(m_queue, i_source.m_queue);
2146  return *this;
2147  }
2148 
2152  friend void swap(
2153  reentrant_put_transaction & i_first, reentrant_put_transaction & i_second) noexcept
2154  {
2155  using std::swap;
2156  swap(i_first.m_put, i_second.m_put);
2157  swap(i_first.m_queue, i_second.m_queue);
2158  }
2159 
2182  void * raw_allocate(size_t i_size, size_t i_alignment)
2183  {
2184  DENSITY_ASSERT(!empty());
2185  auto push_data =
2186  m_queue->template try_inplace_allocate_impl<detail::LfQueue_Throwing>(
2187  detail::LfQueue_Dead, false, i_size, i_alignment);
2188  return push_data.m_user_storage;
2189  }
2190 
2215  template <typename INPUT_ITERATOR>
2216  typename std::iterator_traits<INPUT_ITERATOR>::value_type *
2217  raw_allocate_copy(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end)
2218  {
2219  using ValueType = typename std::iterator_traits<INPUT_ITERATOR>::value_type;
2220  static_assert(
2221  std::is_trivially_destructible<ValueType>::value,
2222  "raw_allocate_copy provides a raw memory in-place allocation that does not "
2223  "invoke "
2224  "destructors when deallocating");
2225 
2226  auto const count_s = std::distance(i_begin, i_end);
2227  auto const count = static_cast<size_t>(count_s);
2228  DENSITY_ASSUME(static_cast<decltype(count_s)>(count) == count_s);
2229 
2230  auto const elements = static_cast<ValueType *>(
2231  raw_allocate(sizeof(ValueType) * count, alignof(ValueType)));
2232  for (auto curr = elements; i_begin != i_end; ++i_begin, ++curr)
2233  new (curr) ValueType(*i_begin);
2234  return elements;
2235  }
2236 
2259  template <typename INPUT_RANGE>
2260  auto raw_allocate_copy(const INPUT_RANGE & i_source_range)
2261  -> decltype(std::declval<reentrant_put_transaction>().raw_allocate_copy(
2262  std::begin(i_source_range), std::end(i_source_range)))
2263  {
2264  return raw_allocate_copy(std::begin(i_source_range), std::end(i_source_range));
2265  }
2266 
2298  progress_guarantee i_progress_guarantee, size_t i_size, size_t i_alignment) noexcept
2299  {
2300  DENSITY_ASSERT(!empty());
2301  auto push_data = m_queue->try_inplace_allocate(
2302  i_progress_guarantee, detail::LfQueue_Dead, false, i_size, i_alignment);
2303  return push_data.m_user_storage;
2304  }
2305 
2339  template <typename INPUT_ITERATOR>
2340  typename std::iterator_traits<INPUT_ITERATOR>::value_type * try_raw_allocate_copy(
2341  progress_guarantee i_progress_guarantee,
2342  INPUT_ITERATOR i_begin,
2343  INPUT_ITERATOR
2344  i_end) noexcept(std::
2345  is_nothrow_copy_constructible<typename std::iterator_traits<
2346  INPUT_ITERATOR>::value_type>::value)
2347  {
2348  using ValueType = typename std::iterator_traits<INPUT_ITERATOR>::value_type;
2349  static_assert(
2350  std::is_trivially_destructible<ValueType>::value,
2351  "raw_allocate_copy provides a raw memory in-place allocation that does not "
2352  "invoke "
2353  "destructors when deallocating");
2354 
2355  auto const count_s = std::distance(i_begin, i_end);
2356  auto const count = static_cast<size_t>(count_s);
2357  DENSITY_ASSUME(static_cast<decltype(count_s)>(count) == count_s);
2358 
2359  auto const elements = static_cast<ValueType *>(try_raw_allocate(
2360  i_progress_guarantee, sizeof(ValueType) * count, alignof(ValueType)));
2361  if (elements != nullptr)
2362  {
2363  for (auto curr = elements; i_begin != i_end; ++i_begin, ++curr)
2364  new (curr) ValueType(*i_begin);
2365  }
2366  return elements;
2367  }
2368 
2400  template <typename INPUT_RANGE>
2402  progress_guarantee i_progress_guarantee,
2403  const INPUT_RANGE &
2404  i_source_range) noexcept(noexcept(std::declval<reentrant_put_transaction>()
2405  .try_raw_allocate_copy(
2406  i_progress_guarantee,
2407  std::begin(i_source_range),
2408  std::end(i_source_range))))
2409  -> decltype(std::declval<reentrant_put_transaction>().try_raw_allocate_copy(
2410  i_progress_guarantee, std::begin(i_source_range), std::end(i_source_range)))
2411  {
2412  return try_raw_allocate_copy(
2413  i_progress_guarantee, std::begin(i_source_range), std::end(i_source_range));
2414  }
2415 
2424  void commit() noexcept
2425  {
2426  DENSITY_ASSERT(!empty());
2427  Base::commit_put_impl(m_put);
2428  m_put.m_user_storage = nullptr;
2429  }
2430 
2441  void cancel() noexcept
2442  {
2443  DENSITY_ASSERT(!empty());
2444  Base::cancel_put_impl(m_put);
2445  m_put.m_user_storage = nullptr;
2446  }
2447 
2451  bool empty() const noexcept { return m_put.m_user_storage == nullptr; }
2452 
2456  explicit operator bool() const noexcept { return m_put.m_user_storage != nullptr; }
2457 
2461  sp_heter_queue * queue() const noexcept
2462  {
2463  return m_put.m_user_storage != nullptr ? m_queue : nullptr;
2464  }
2465 
2477  void * element_ptr() const noexcept
2478  {
2479  DENSITY_ASSERT(!empty());
2480  return m_put.m_user_storage;
2481  }
2482 
2496 #ifndef DOXYGEN_DOC_GENERATION
2497  template <
2498  typename EL = ELEMENT_COMPLETE_TYPE,
2499  typename std::enable_if<!std::is_void<EL>::value>::type * = nullptr>
2500  EL &
2501 #else
2502  ELEMENT_COMPLETE_TYPE &
2503 #endif
2504  element() const noexcept
2505  {
2506  return *static_cast<ELEMENT_COMPLETE_TYPE *>(element_ptr());
2507  }
2508 
2515  const RUNTIME_TYPE & complete_type() const noexcept
2516  {
2517  DENSITY_ASSERT(!empty());
2518  return *Base::type_after_control(m_put.m_control_block);
2519  }
2520 
2525  {
2526  if (m_put.m_user_storage != nullptr)
2527  {
2528  Base::cancel_put_impl(m_put);
2529  }
2530  }
2531 
2534  PrivateType, sp_heter_queue * i_queue, const Allocation & i_put) noexcept
2535  : m_put(i_put), m_queue(i_queue)
2536  {
2537  }
2538 
2539  private:
2540  Allocation m_put;
2541  sp_heter_queue * m_queue = nullptr;
2542  template <typename OTHERTYPE> friend class reentrant_put_transaction;
2543  };
2544 
2545 
2563  {
2564  public:
2568  reentrant_consume_operation() noexcept = default;
2569 
2574 
2578  reentrant_consume_operation & operator=(const reentrant_consume_operation &) = delete;
2579 
2583  reentrant_consume_operation(reentrant_consume_operation && i_source) noexcept = default;
2584 
2589  operator=(reentrant_consume_operation && i_source) noexcept = default;
2590 
2595  {
2596  if (!m_consume_data.empty())
2597  {
2598  m_consume_data.cancel_consume_impl();
2599  }
2600  }
2601 
2605  friend void swap(
2606  reentrant_consume_operation & i_first,
2607  reentrant_consume_operation & i_second) noexcept
2608  {
2609  i_first.m_consume_data.swap(i_second.m_consume_data);
2610  }
2611 
2615  bool empty() const noexcept { return m_consume_data.empty(); }
2616 
2620  explicit operator bool() const noexcept { return !m_consume_data.empty(); }
2621 
2625  sp_heter_queue * queue() const noexcept
2626  {
2627  return static_cast<sp_heter_queue *>(m_consume_data.m_queue);
2628  }
2629 
2638  void commit() noexcept
2639  {
2640  DENSITY_ASSERT(!empty());
2641 
2642  auto const & type = complete_type();
2643  auto const element = element_ptr();
2644  type.destroy(element);
2645 
2646  type.RUNTIME_TYPE::~RUNTIME_TYPE();
2647 
2648  m_consume_data.commit_consume_impl();
2649  }
2650 
2668  void commit_nodestroy() noexcept
2669  {
2670  DENSITY_ASSERT(!empty());
2671 
2672  bool destroy_type = !std::is_trivially_destructible<RUNTIME_TYPE>::value;
2673  if (destroy_type)
2674  {
2675  auto const & type = complete_type();
2676  type.RUNTIME_TYPE::~RUNTIME_TYPE();
2677  }
2678 
2679  m_consume_data.commit_consume_impl();
2680  }
2681 
2692  void cancel() noexcept
2693  {
2694  DENSITY_ASSERT(!empty());
2695  m_consume_data.cancel_consume_impl();
2696  }
2697 
2703  const RUNTIME_TYPE & complete_type() const noexcept
2704  {
2705  DENSITY_ASSERT(!empty());
2706  return *Base::type_after_control(m_consume_data.m_control);
2707  }
2708 
2716  void * unaligned_element_ptr() const noexcept
2717  {
2718  DENSITY_ASSERT(!empty());
2719  return Base::get_unaligned_element(
2720  m_consume_data.m_control, m_consume_data.external());
2721  }
2722 
2730  void * element_ptr() const noexcept
2731  {
2732  DENSITY_ASSERT(!empty());
2733  return Base::get_element(m_consume_data.m_control, m_consume_data.external());
2734  }
2735 
2742  template <typename COMPLETE_ELEMENT_TYPE>
2743  COMPLETE_ELEMENT_TYPE & element() const noexcept
2744  {
2745  DENSITY_ASSERT(!empty() && complete_type().template is<COMPLETE_ELEMENT_TYPE>());
2746  return *static_cast<COMPLETE_ELEMENT_TYPE *>(
2747  Base::get_element(m_consume_data.m_control, m_consume_data.external()));
2748  }
2749 
2751  reentrant_consume_operation(PrivateType, sp_heter_queue * i_queue) noexcept
2752  {
2753  m_consume_data.start_consume_impl(i_queue);
2754  }
2755 
2757  bool start_consume_impl(PrivateType, sp_heter_queue * i_queue)
2758  {
2759  if (!m_consume_data.empty())
2760  {
2761  m_consume_data.cancel_consume_impl();
2762  }
2763 
2764  m_consume_data.start_consume_impl(i_queue);
2765 
2766  return !m_consume_data.empty();
2767  }
2768 
2769  private:
2770  Consume m_consume_data;
2771  };
2772 
2778  template <typename ELEMENT_TYPE> void reentrant_push(ELEMENT_TYPE && i_source)
2779  {
2780  return reentrant_emplace<typename std::decay<ELEMENT_TYPE>::type>(
2781  std::forward<ELEMENT_TYPE>(i_source));
2782  }
2783 
2789  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
2790  void reentrant_emplace(CONSTRUCTION_PARAMS &&... i_construction_params)
2791  {
2792  start_reentrant_emplace<ELEMENT_TYPE>(
2793  std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...)
2794  .commit();
2795  }
2796 
2802  void reentrant_dyn_push(const runtime_type & i_type)
2803  {
2804  start_reentrant_dyn_push(i_type).commit();
2805  }
2806 
2812  void reentrant_dyn_push_copy(const runtime_type & i_type, const void * i_source)
2813  {
2814  start_reentrant_dyn_push_copy(i_type, i_source).commit();
2815  }
2816 
2822  void reentrant_dyn_push_move(const runtime_type & i_type, void * i_source)
2823  {
2824  start_reentrant_dyn_push_move(i_type, i_source).commit();
2825  }
2826 
2832  template <typename ELEMENT_TYPE>
2833  reentrant_put_transaction<typename std::decay<ELEMENT_TYPE>::type>
2834  start_reentrant_push(ELEMENT_TYPE && i_source)
2835  {
2836  return start_reentrant_emplace<typename std::decay<ELEMENT_TYPE>::type>(
2837  std::forward<ELEMENT_TYPE>(i_source));
2838  }
2839 
2845  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
2846  reentrant_put_transaction<ELEMENT_TYPE>
2847  start_reentrant_emplace(CONSTRUCTION_PARAMS &&... i_construction_params)
2848  {
2849  auto push_data = Base::template try_inplace_allocate_impl<
2850  detail::LfQueue_Throwing,
2851  detail::LfQueue_Busy,
2852  true,
2853  detail::size_of<ELEMENT_TYPE>::value,
2854  alignof(ELEMENT_TYPE)>();
2855 
2856  runtime_type * type = nullptr;
2857  try
2858  {
2859  auto const type_storage = Base::type_after_control(push_data.m_control_block);
2860  DENSITY_ASSUME(type_storage != nullptr);
2861  type = new (type_storage) runtime_type(runtime_type::template make<ELEMENT_TYPE>());
2862 
2863  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
2864  new (push_data.m_user_storage)
2865  ELEMENT_TYPE(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
2866  }
2867  catch (...)
2868  {
2869  if (type != nullptr)
2870  type->RUNTIME_TYPE::~RUNTIME_TYPE();
2871  Base::cancel_put_nodestroy_impl(push_data);
2872  throw;
2873  }
2874 
2875  return reentrant_put_transaction<ELEMENT_TYPE>(PrivateType(), this, push_data);
2876  }
2877 
2883  reentrant_put_transaction<> start_reentrant_dyn_push(const runtime_type & i_type)
2884  {
2885  auto push_data = Base::template try_inplace_allocate_impl<detail::LfQueue_Throwing>(
2886  detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
2887 
2888  runtime_type * type = nullptr;
2889  try
2890  {
2891  auto const type_storage = Base::type_after_control(push_data.m_control_block);
2892  DENSITY_ASSUME(type_storage != nullptr);
2893  type = new (type_storage) runtime_type(i_type);
2894 
2895  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
2896  i_type.default_construct(push_data.m_user_storage);
2897  }
2898  catch (...)
2899  {
2900  if (type != nullptr)
2901  type->RUNTIME_TYPE::~RUNTIME_TYPE();
2902  Base::cancel_put_nodestroy_impl(push_data);
2903  throw;
2904  }
2905 
2906  return reentrant_put_transaction<void>(PrivateType(), this, push_data);
2907  }
2908 
2909 
2915  reentrant_put_transaction<>
2916  start_reentrant_dyn_push_copy(const runtime_type & i_type, const void * i_source)
2917  {
2918  auto push_data = Base::template try_inplace_allocate_impl<detail::LfQueue_Throwing>(
2919  detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
2920 
2921  runtime_type * type = nullptr;
2922  try
2923  {
2924  auto const type_storage = Base::type_after_control(push_data.m_control_block);
2925  DENSITY_ASSUME(type_storage != nullptr);
2926  type = new (type_storage) runtime_type(i_type);
2927 
2928  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
2929  i_type.copy_construct(push_data.m_user_storage, i_source);
2930  }
2931  catch (...)
2932  {
2933  if (type != nullptr)
2934  type->RUNTIME_TYPE::~RUNTIME_TYPE();
2935  Base::cancel_put_nodestroy_impl(push_data);
2936  throw;
2937  }
2938 
2939  return reentrant_put_transaction<void>(PrivateType(), this, push_data);
2940  }
2941 
2947  reentrant_put_transaction<>
2948  start_reentrant_dyn_push_move(const runtime_type & i_type, void * i_source)
2949  {
2950  auto push_data = Base::template try_inplace_allocate_impl<detail::LfQueue_Throwing>(
2951  detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
2952 
2953  runtime_type * type = nullptr;
2954  try
2955  {
2956  auto const type_storage = Base::type_after_control(push_data.m_control_block);
2957  DENSITY_ASSUME(type_storage != nullptr);
2958  type = new (type_storage) runtime_type(i_type);
2959 
2960  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
2961  i_type.move_construct(push_data.m_user_storage, i_source);
2962  }
2963  catch (...)
2964  {
2965  if (type != nullptr)
2966  type->RUNTIME_TYPE::~RUNTIME_TYPE();
2967  Base::cancel_put_nodestroy_impl(push_data);
2968  throw;
2969  }
2970 
2971  return reentrant_put_transaction<void>(PrivateType(), this, push_data);
2972  }
2973 
2979  template <typename ELEMENT_TYPE>
2981  progress_guarantee i_progress_guarantee,
2982  ELEMENT_TYPE && i_source) noexcept(noexcept(std::declval<sp_heter_queue>()
2983  .template try_reentrant_emplace<
2984  typename std::decay<ELEMENT_TYPE>::type>(
2985  i_progress_guarantee,
2986  std::forward<ELEMENT_TYPE>(i_source))))
2987  {
2988  return try_reentrant_emplace<typename std::decay<ELEMENT_TYPE>::type>(
2989  i_progress_guarantee, std::forward<ELEMENT_TYPE>(i_source));
2990  }
2991 
2997  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
2998  bool
2999  try_reentrant_emplace(progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&... i_construction_params) noexcept(
3000  noexcept(
3001  std::declval<sp_heter_queue>().template try_start_reentrant_emplace<ELEMENT_TYPE>(
3002  i_progress_guarantee, std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...)))
3003  {
3004  auto tranasction = try_start_reentrant_emplace<ELEMENT_TYPE>(
3005  i_progress_guarantee, std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
3006  if (!tranasction)
3007  return false;
3008  tranasction.commit();
3009  return true;
3010  }
3011 
3018  progress_guarantee i_progress_guarantee, const runtime_type & i_type)
3019  {
3020  auto tranasction = try_start_reentrant_dyn_push(i_progress_guarantee, i_type);
3021  if (!tranasction)
3022  return false;
3023  tranasction.commit();
3024  return true;
3025  }
3026 
3033  progress_guarantee i_progress_guarantee,
3034  const runtime_type & i_type,
3035  const void * i_source)
3036  {
3037  auto tranasction =
3038  try_start_reentrant_dyn_push_copy(i_progress_guarantee, i_type, i_source);
3039  if (!tranasction)
3040  return false;
3041  tranasction.commit();
3042  return true;
3043  }
3044 
3051  progress_guarantee i_progress_guarantee, const runtime_type & i_type, void * i_source)
3052  {
3053  auto tranasction =
3054  try_start_reentrant_dyn_push_move(i_progress_guarantee, i_type, i_source);
3055  if (!tranasction)
3056  return false;
3057  tranasction.commit();
3058  return true;
3059  }
3060 
3066  template <typename ELEMENT_TYPE>
3067  reentrant_put_transaction<typename std::decay<ELEMENT_TYPE>::type> try_start_reentrant_push(
3068  progress_guarantee i_progress_guarantee,
3069  ELEMENT_TYPE && i_source) noexcept(noexcept(std::declval<sp_heter_queue>()
3070  .template try_start_reentrant_emplace<
3071  typename std::decay<ELEMENT_TYPE>::type>(
3072  i_progress_guarantee,
3073  std::forward<ELEMENT_TYPE>(i_source))))
3074  {
3075  return try_start_reentrant_emplace<typename std::decay<ELEMENT_TYPE>::type>(
3076  i_progress_guarantee, std::forward<ELEMENT_TYPE>(i_source));
3077  }
3078 
3084  template <typename ELEMENT_TYPE, typename... CONSTRUCTION_PARAMS>
3085  reentrant_put_transaction<ELEMENT_TYPE>
3086  try_start_reentrant_emplace(progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&... i_construction_params) noexcept(
3087  noexcept(ELEMENT_TYPE(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...)) &&
3088  noexcept(runtime_type(runtime_type::template make<ELEMENT_TYPE>())))
3089  {
3090  auto push_data = Base::template try_inplace_allocate<
3091  detail::LfQueue_Busy,
3092  true,
3093  detail::size_of<ELEMENT_TYPE>::value,
3094  alignof(ELEMENT_TYPE)>(i_progress_guarantee);
3095  if (push_data.m_user_storage == nullptr)
3096  {
3097  return reentrant_put_transaction<ELEMENT_TYPE>();
3098  }
3099 
3100  constexpr bool is_noexcept =
3101  std::is_nothrow_constructible<ELEMENT_TYPE, CONSTRUCTION_PARAMS...>::value &&
3102  noexcept(runtime_type(runtime_type::template make<ELEMENT_TYPE>()));
3103 
3104  runtime_type * type = nullptr;
3105 
3106  if (is_noexcept)
3107  {
3108  auto const type_storage = Base::type_after_control(push_data.m_control_block);
3109  DENSITY_ASSUME(type_storage != nullptr);
3110  type = new (type_storage) runtime_type(runtime_type::template make<ELEMENT_TYPE>());
3111 
3112  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
3113  new (push_data.m_user_storage)
3114  ELEMENT_TYPE(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
3115  }
3116  else
3117  {
3118  try
3119  {
3120  auto const type_storage = Base::type_after_control(push_data.m_control_block);
3121  DENSITY_ASSUME(type_storage != nullptr);
3122  type =
3123  new (type_storage) runtime_type(runtime_type::template make<ELEMENT_TYPE>());
3124 
3125  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
3126  new (push_data.m_user_storage)
3127  ELEMENT_TYPE(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
3128  }
3129  catch (...)
3130  {
3131  if (type != nullptr)
3132  type->RUNTIME_TYPE::~RUNTIME_TYPE();
3133 
3134  Base::cancel_put_nodestroy_impl(push_data);
3135  DENSITY_INTERNAL_RETHROW_FROM_NOEXCEPT
3136  }
3137  }
3138 
3139  return reentrant_put_transaction<ELEMENT_TYPE>(PrivateType(), this, push_data);
3140  }
3141 
3147  reentrant_put_transaction<> try_start_reentrant_dyn_push(
3148  progress_guarantee i_progress_guarantee, const runtime_type & i_type)
3149  {
3150  auto push_data = Base::try_inplace_allocate(
3151  i_progress_guarantee, detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
3152  if (push_data.m_user_storage == nullptr)
3153  {
3154  return reentrant_put_transaction<>();
3155  }
3156 
3157  runtime_type * type = nullptr;
3158  try
3159  {
3160  auto const type_storage = Base::type_after_control(push_data.m_control_block);
3161  DENSITY_ASSUME(type_storage != nullptr);
3162  type = new (type_storage) runtime_type(i_type);
3163 
3164  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
3165  i_type.default_construct(push_data.m_user_storage);
3166  }
3167  catch (...)
3168  {
3169  if (type != nullptr)
3170  type->RUNTIME_TYPE::~RUNTIME_TYPE();
3171 
3172  Base::cancel_put_nodestroy_impl(push_data);
3173  throw;
3174  }
3175 
3176  return reentrant_put_transaction<void>(PrivateType(), this, push_data);
3177  }
3178 
3184  reentrant_put_transaction<> try_start_reentrant_dyn_push_copy(
3185  progress_guarantee i_progress_guarantee,
3186  const runtime_type & i_type,
3187  const void * i_source)
3188  {
3189  auto push_data = Base::try_inplace_allocate(
3190  i_progress_guarantee, detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
3191  if (push_data.m_user_storage == nullptr)
3192  {
3193  return reentrant_put_transaction<>();
3194  }
3195 
3196  runtime_type * type = nullptr;
3197  try
3198  {
3199  auto const type_storage = Base::type_after_control(push_data.m_control_block);
3200  DENSITY_ASSUME(type_storage != nullptr);
3201  type = new (type_storage) runtime_type(i_type);
3202 
3203  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
3204  i_type.copy_construct(push_data.m_user_storage, i_source);
3205  }
3206  catch (...)
3207  {
3208  if (type != nullptr)
3209  type->RUNTIME_TYPE::~RUNTIME_TYPE();
3210  Base::cancel_put_nodestroy_impl(push_data);
3211  throw;
3212  }
3213 
3214  return reentrant_put_transaction<void>(PrivateType(), this, push_data);
3215  }
3216 
3222  reentrant_put_transaction<> try_start_reentrant_dyn_push_move(
3223  progress_guarantee i_progress_guarantee, const runtime_type & i_type, void * i_source)
3224  {
3225  auto push_data = Base::try_inplace_allocate(
3226  i_progress_guarantee, detail::LfQueue_Busy, true, i_type.size(), i_type.alignment());
3227  if (push_data.m_user_storage == nullptr)
3228  {
3229  return reentrant_put_transaction<>();
3230  }
3231 
3232  runtime_type * type = nullptr;
3233  try
3234  {
3235  auto const type_storage = Base::type_after_control(push_data.m_control_block);
3236  DENSITY_ASSUME(type_storage != nullptr);
3237  type = new (type_storage) runtime_type(i_type);
3238 
3239  DENSITY_ASSUME(push_data.m_user_storage != nullptr);
3240  i_type.move_construct(push_data.m_user_storage, i_source);
3241  }
3242  catch (...)
3243  {
3244  if (type != nullptr)
3245  type->RUNTIME_TYPE::~RUNTIME_TYPE();
3246  Base::cancel_put_nodestroy_impl(push_data);
3247  throw;
3248  }
3249 
3250  return reentrant_put_transaction<void>(PrivateType(), this, push_data);
3251  }
3252 
3264  bool try_reentrant_pop() noexcept
3265  {
3266  if (auto operation = try_start_reentrant_consume())
3267  {
3268  operation.commit();
3269  return true;
3270  }
3271  return false;
3272  }
3273 
3274 
3283  reentrant_consume_operation try_start_reentrant_consume() noexcept
3284  {
3285  return reentrant_consume_operation(PrivateType(), this);
3286  }
3287 
3303  bool try_start_reentrant_consume(reentrant_consume_operation & i_consume) noexcept
3304  {
3305  return i_consume.start_consume_impl(PrivateType(), this);
3306  }
3307  };
3308 
3309 } // namespace density
3310 
3311 #ifdef _MSC_VER
3312 #pragma warning(pop)
3313 #endif
~reentrant_consume_operation()
Definition: sp_heter_queue.h:2594
void cancel() noexcept
Definition: sp_heter_queue.h:2441
reentrant_put_transaction start_reentrant_dyn_push_move(const runtime_type &i_type, void *i_source)
Definition: sp_heter_queue.h:2948
void reentrant_dyn_push_move(const runtime_type &i_type, void *i_source)
Definition: sp_heter_queue.h:2822
basic_default_allocator< default_page_capacity > default_allocator
Definition: default_allocator.h:152
sp_heter_queue & operator=(sp_heter_queue &&i_source) noexcept
Definition: sp_heter_queue.h:418
std::iterator_traits< INPUT_ITERATOR >::value_type * try_raw_allocate_copy(progress_guarantee i_progress_guarantee, INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end) noexcept(std:: is_nothrow_copy_constructible< typename std::iterator_traits< INPUT_ITERATOR >::value_type >::value)
Definition: sp_heter_queue.h:2340
~put_transaction()
Definition: sp_heter_queue.h:944
Definition: sp_heter_queue.h:208
void cancel() noexcept
Definition: sp_heter_queue.h:2692
concurrency_cardinality
Definition: density_common.h:56
Definition: conc_function_queue.h:11
Definition: runtime_type.h:665
sp_heter_queue * queue() const noexcept
Definition: sp_heter_queue.h:2625
void * try_raw_allocate(progress_guarantee i_progress_guarantee, size_t i_size, size_t i_alignment) noexcept
Definition: sp_heter_queue.h:2297
friend void swap(reentrant_consume_operation &i_first, reentrant_consume_operation &i_second) noexcept
Definition: sp_heter_queue.h:2605
put_transaction & operator=(put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: sp_heter_queue.h:563
void dyn_push(const runtime_type &i_type)
Definition: sp_heter_queue.h:1252
reentrant_put_transaction start_reentrant_dyn_push_copy(const runtime_type &i_type, const void *i_source)
Definition: sp_heter_queue.h:2916
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: sp_heter_queue.h:2260
void commit() noexcept
Definition: sp_heter_queue.h:2424
ELEMENT_COMPLETE_TYPE & element() const noexcept
Definition: sp_heter_queue.h:2504
Definition: density_common.h:60
void operator()() noexcept
Definition: sp_heter_queue.h:51
void reentrant_push(ELEMENT_TYPE &&i_source)
Definition: sp_heter_queue.h:2778
reentrant_put_transaction try_start_reentrant_dyn_push_copy(progress_guarantee i_progress_guarantee, const runtime_type &i_type, const void *i_source)
Definition: sp_heter_queue.h:3184
void commit_nodestroy() noexcept
Definition: sp_heter_queue.h:2668
reentrant_put_transaction< typename std::decay< ELEMENT_TYPE >::type > start_reentrant_push(ELEMENT_TYPE &&i_source)
Definition: sp_heter_queue.h:2834
Definition: runtime_type.h:1061
void * element_ptr() const noexcept
Definition: sp_heter_queue.h:2477
sp_heter_queue * queue() const noexcept
Definition: sp_heter_queue.h:2461
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: sp_heter_queue.h:681
auto try_raw_allocate_copy(progress_guarantee i_progress_guarantee, const INPUT_RANGE &i_source_range) noexcept(noexcept(std::declval< reentrant_put_transaction >() .try_raw_allocate_copy( i_progress_guarantee, std::begin(i_source_range), std::end(i_source_range)))) -> decltype(std::declval< reentrant_put_transaction >().try_raw_allocate_copy( i_progress_guarantee, std::begin(i_source_range), std::end(i_source_range)))
Definition: sp_heter_queue.h:2401
const RUNTIME_TYPE & complete_type() const noexcept
Definition: sp_heter_queue.h:935
void * element_ptr() const noexcept
Definition: sp_heter_queue.h:1147
reentrant_put_transaction try_start_reentrant_dyn_push(progress_guarantee i_progress_guarantee, const runtime_type &i_type)
Definition: sp_heter_queue.h:3147
put_transaction start_dyn_push_copy(const runtime_type &i_type, const void *i_source)
Definition: sp_heter_queue.h:1453
Definition: density_common.h:58
reentrant_put_transaction start_reentrant_dyn_push(const runtime_type &i_type)
Definition: sp_heter_queue.h:2883
COMPLETE_ELEMENT_TYPE & element() const noexcept
Definition: sp_heter_queue.h:2743
allocator_type & get_allocator_ref() noexcept
Definition: sp_heter_queue.h:436
void dyn_push_copy(const runtime_type &i_type, const void *i_source)
Definition: sp_heter_queue.h:1272
friend void swap(put_transaction &i_first, put_transaction &i_second) noexcept
Definition: sp_heter_queue.h:574
void emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: sp_heter_queue.h:1230
bool empty() const noexcept
Definition: sp_heter_queue.h:2615
bool try_dyn_push(progress_guarantee i_progress_guarantee, const runtime_type &i_type)
Definition: sp_heter_queue.h:1624
bool try_emplace(progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&...i_construction_params) noexcept( noexcept(std::declval< sp_heter_queue >().template try_start_emplace< ELEMENT_TYPE >( i_progress_guarantee, std::forward< CONSTRUCTION_PARAMS >(i_construction_params)...)))
Definition: sp_heter_queue.h:1588
void clear() noexcept
Definition: sp_heter_queue.h:483
bool empty() const noexcept
Definition: sp_heter_queue.h:871
void commit() noexcept
Definition: sp_heter_queue.h:2638
#define DENSITY_ASSERT(...)
Definition: density_config.h:19
constexpr sp_heter_queue(const ALLOCATOR_TYPE &i_source_allocator, BUSY_WAIT_FUNC &&i_source_wait) noexcept
Definition: sp_heter_queue.h:363
void * raw_allocate(size_t i_size, size_t i_alignment)
Definition: sp_heter_queue.h:603
reentrant_put_transaction(reentrant_put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: sp_heter_queue.h:2124
bool try_start_consume(consume_operation &i_consume) noexcept
Definition: sp_heter_queue.h:2063
put_transaction(put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: sp_heter_queue.h:547
constexpr sp_heter_queue(ALLOCATOR_TYPE &&i_source_allocator, BUSY_WAIT_FUNC &&i_source_wait) noexcept
Definition: sp_heter_queue.h:384
void commit() noexcept
Definition: sp_heter_queue.h:844
friend void swap(reentrant_put_transaction &i_first, reentrant_put_transaction &i_second) noexcept
Definition: sp_heter_queue.h:2152
bool empty() const noexcept
Definition: sp_heter_queue.h:2451
constexpr sp_heter_queue(ALLOCATOR_TYPE &&i_source_allocator) noexcept
Definition: sp_heter_queue.h:305
allocator_type get_allocator() noexcept(std::is_nothrow_copy_constructible< allocator_type >::value)
Definition: sp_heter_queue.h:428
put_transaction< typename std::decay< ELEMENT_TYPE >::type > try_start_push(progress_guarantee i_progress_guarantee, ELEMENT_TYPE &&i_source) noexcept(noexcept(std::declval< sp_heter_queue >() .template try_start_emplace< typename std::decay< ELEMENT_TYPE >::type >( i_progress_guarantee, std::forward< ELEMENT_TYPE >(i_source))))
Definition: sp_heter_queue.h:1740
bool try_reentrant_emplace(progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&...i_construction_params) noexcept( noexcept( std::declval< sp_heter_queue >().template try_start_reentrant_emplace< ELEMENT_TYPE >( i_progress_guarantee, std::forward< CONSTRUCTION_PARAMS >(i_construction_params)...)))
Definition: sp_heter_queue.h:2999
void commit() noexcept
Definition: sp_heter_queue.h:1055
constexpr sp_heter_queue(const ALLOCATOR_TYPE &i_source_allocator, const BUSY_WAIT_FUNC &i_source_wait) noexcept
Definition: sp_heter_queue.h:322
void * unaligned_element_ptr() const noexcept
Definition: sp_heter_queue.h:1133
Definition: sp_heter_queue.h:47
void commit_nodestroy() noexcept
Definition: sp_heter_queue.h:1085
bool try_pop() noexcept
Definition: sp_heter_queue.h:2029
ELEMENT_COMPLETE_TYPE & element() const noexcept
Definition: sp_heter_queue.h:924
bool try_reentrant_dyn_push(progress_guarantee i_progress_guarantee, const runtime_type &i_type)
Definition: sp_heter_queue.h:3017
~sp_heter_queue()
Definition: sp_heter_queue.h:456
COMPLETE_ELEMENT_TYPE & element() const noexcept
Definition: sp_heter_queue.h:1160
bool try_start_reentrant_consume(reentrant_consume_operation &i_consume) noexcept
Definition: sp_heter_queue.h:3303
bool empty() const noexcept
Definition: sp_heter_queue.h:1032
progress_guarantee
Definition: density_common.h:84
reentrant_put_transaction< typename std::decay< ELEMENT_TYPE >::type > try_start_reentrant_push(progress_guarantee i_progress_guarantee, ELEMENT_TYPE &&i_source) noexcept(noexcept(std::declval< sp_heter_queue >() .template try_start_reentrant_emplace< typename std::decay< ELEMENT_TYPE >::type >( i_progress_guarantee, std::forward< ELEMENT_TYPE >(i_source))))
Definition: sp_heter_queue.h:3067
bool try_reentrant_pop() noexcept
Definition: sp_heter_queue.h:3264
constexpr bool is_power_of_2(size_t i_number) noexcept
Definition: density_common.h:109
bool empty() const noexcept
Definition: sp_heter_queue.h:474
bool try_dyn_push_move(progress_guarantee i_progress_guarantee, const runtime_type &i_type, void *i_source)
Definition: sp_heter_queue.h:1697
void * try_raw_allocate(progress_guarantee i_progress_guarantee, size_t i_size, size_t i_alignment) noexcept
Definition: sp_heter_queue.h:718
void cancel() noexcept
Definition: sp_heter_queue.h:861
void cancel() noexcept
Definition: sp_heter_queue.h:1109
sp_heter_queue * queue() const noexcept
Definition: sp_heter_queue.h:881
const RUNTIME_TYPE & complete_type() const noexcept
Definition: sp_heter_queue.h:2515
bool try_reentrant_dyn_push_copy(progress_guarantee i_progress_guarantee, const runtime_type &i_type, const void *i_source)
Definition: sp_heter_queue.h:3032
const RUNTIME_TYPE & complete_type() const noexcept
Definition: sp_heter_queue.h:2703
void * raw_allocate(size_t i_size, size_t i_alignment)
Definition: sp_heter_queue.h:2182
reentrant_put_transaction< ELEMENT_TYPE > try_start_reentrant_emplace(progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&...i_construction_params) noexcept( noexcept(ELEMENT_TYPE(std::forward< CONSTRUCTION_PARAMS >(i_construction_params)...))&& noexcept(runtime_type(runtime_type::template make< ELEMENT_TYPE >())))
Definition: sp_heter_queue.h:3086
std::iterator_traits< INPUT_ITERATOR >::value_type * raw_allocate_copy(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end)
Definition: sp_heter_queue.h:638
const allocator_type & get_allocator_ref() const noexcept
Definition: sp_heter_queue.h:441
void dyn_push_move(const runtime_type &i_type, void *i_source)
Definition: sp_heter_queue.h:1295
std::iterator_traits< INPUT_ITERATOR >::value_type * try_raw_allocate_copy(progress_guarantee i_progress_guarantee, INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end) noexcept(std:: is_nothrow_copy_constructible< typename std::iterator_traits< INPUT_ITERATOR >::value_type >::value)
Definition: sp_heter_queue.h:761
std::iterator_traits< INPUT_ITERATOR >::value_type * raw_allocate_copy(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end)
Definition: sp_heter_queue.h:2217
bool try_reentrant_dyn_push_move(progress_guarantee i_progress_guarantee, const runtime_type &i_type, void *i_source)
Definition: sp_heter_queue.h:3050
Definition: sp_heter_queue.h:513
void reentrant_dyn_push_copy(const runtime_type &i_type, const void *i_source)
Definition: sp_heter_queue.h:2812
put_transaction try_start_dyn_push(progress_guarantee i_progress_guarantee, const runtime_type &i_type)
Definition: sp_heter_queue.h:1867
void push(ELEMENT_TYPE &&i_source)
Definition: sp_heter_queue.h:1207
put_transaction try_start_dyn_push_copy(progress_guarantee i_progress_guarantee, const runtime_type &i_type, const void *i_source)
Definition: sp_heter_queue.h:1927
void reentrant_dyn_push(const runtime_type &i_type)
Definition: sp_heter_queue.h:2802
sp_heter_queue * queue() const noexcept
Definition: sp_heter_queue.h:1042
~consume_operation()
Definition: sp_heter_queue.h:1013
const RUNTIME_TYPE & complete_type() const noexcept
Definition: sp_heter_queue.h:1120
Definition: sp_heter_queue.h:982
reentrant_put_transaction & operator=(reentrant_put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: sp_heter_queue.h:2141
auto try_raw_allocate_copy(progress_guarantee i_progress_guarantee, const INPUT_RANGE &i_source_range) noexcept(noexcept(std::declval< put_transaction >() .try_raw_allocate_copy( i_progress_guarantee, std::begin(i_source_range), std::end(i_source_range)))) -> decltype(std::declval< put_transaction >().try_raw_allocate_copy( i_progress_guarantee, std::begin(i_source_range), std::end(i_source_range)))
Definition: sp_heter_queue.h:822
reentrant_consume_operation try_start_reentrant_consume() noexcept
Definition: sp_heter_queue.h:3283
consume_operation try_start_consume() noexcept
Definition: sp_heter_queue.h:2045
reentrant_put_transaction try_start_reentrant_dyn_push_move(progress_guarantee i_progress_guarantee, const runtime_type &i_type, void *i_source)
Definition: sp_heter_queue.h:3222
put_transaction< ELEMENT_TYPE > start_emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: sp_heter_queue.h:1355
put_transaction start_dyn_push(const runtime_type &i_type)
Definition: sp_heter_queue.h:1405
friend void swap(sp_heter_queue &i_first, sp_heter_queue &i_second) noexcept
Definition: sp_heter_queue.h:446
bool try_push(progress_guarantee i_progress_guarantee, ELEMENT_TYPE &&i_source) noexcept( noexcept(std::declval< sp_heter_queue >() .template try_emplace< typename std::decay< ELEMENT_TYPE >::type >( i_progress_guarantee, std::forward< ELEMENT_TYPE >(i_source))))
Definition: sp_heter_queue.h:1552
put_transaction start_dyn_push_move(const runtime_type &i_type, void *i_source)
Definition: sp_heter_queue.h:1499
void reentrant_emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: sp_heter_queue.h:2790
put_transaction< ELEMENT_TYPE > try_start_emplace(progress_guarantee i_progress_guarantee, CONSTRUCTION_PARAMS &&...i_construction_params) noexcept( noexcept(ELEMENT_TYPE(std::forward< CONSTRUCTION_PARAMS >(i_construction_params)...))&& noexcept(runtime_type(runtime_type::template make< ELEMENT_TYPE >())))
Definition: sp_heter_queue.h:1784
#define DENSITY_ASSUME(bool_expr,...)
Definition: density_config.h:46
bool try_dyn_push_copy(progress_guarantee i_progress_guarantee, const runtime_type &i_type, const void *i_source)
Definition: sp_heter_queue.h:1659
bool try_reentrant_push(progress_guarantee i_progress_guarantee, ELEMENT_TYPE &&i_source) noexcept(noexcept(std::declval< sp_heter_queue >() .template try_reentrant_emplace< typename std::decay< ELEMENT_TYPE >::type >( i_progress_guarantee, std::forward< ELEMENT_TYPE >(i_source))))
Definition: sp_heter_queue.h:2980
reentrant_put_transaction< ELEMENT_TYPE > start_reentrant_emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: sp_heter_queue.h:2847
void * element_ptr() const noexcept
Definition: sp_heter_queue.h:897
put_transaction< typename std::decay< ELEMENT_TYPE >::type > start_push(ELEMENT_TYPE &&i_source)
Definition: sp_heter_queue.h:1326
void * unaligned_element_ptr() const noexcept
Definition: sp_heter_queue.h:2716
friend void swap(consume_operation &i_first, consume_operation &i_second) noexcept
Definition: sp_heter_queue.h:1024
~reentrant_put_transaction()
Definition: sp_heter_queue.h:2524
put_transaction try_start_dyn_push_move(progress_guarantee i_progress_guarantee, const runtime_type &i_type, void *i_source)
Definition: sp_heter_queue.h:1988
constexpr sp_heter_queue(ALLOCATOR_TYPE &&i_source_allocator, const BUSY_WAIT_FUNC &i_source_wait) noexcept
Definition: sp_heter_queue.h:342
void * element_ptr() const noexcept
Definition: sp_heter_queue.h:2730