8 #include <density/default_allocator.h> 10 #include <density/dynamic_reference.h> 11 #include <density/runtime_type.h> 26 enum Queue_Flags : uintptr_t
37 Queue_AllFlags = Queue_Busy | Queue_Dead | Queue_External
199 template <
typename RUNTIME_TYPE = runtime_type<>,
typename ALLOCATOR_TYPE = default_allocator>
202 using ControlBlock = detail::QueueControl;
205 ControlBlock * m_head;
208 ControlBlock * m_tail;
211 enum class PrivateType
218 constexpr
static size_t min_alignment = detail::size_max(
219 detail::Queue_AllFlags + 1,
alignof(ControlBlock),
alignof(RUNTIME_TYPE));
221 using runtime_type = RUNTIME_TYPE;
223 using allocator_type = ALLOCATOR_TYPE;
228 using size_type = std::size_t;
229 using difference_type = std::ptrdiff_t;
231 class const_iterator;
237 constexpr
static auto s_invalid_control_block = ALLOCATOR_TYPE::page_size - 1;
241 constexpr
static size_t s_sizeof_ControlBlock =
246 constexpr
static size_t s_sizeof_RuntimeType =
250 constexpr
static auto s_max_size_inpage = ALLOCATOR_TYPE::page_size -
251 s_sizeof_ControlBlock - s_sizeof_RuntimeType -
252 s_sizeof_ControlBlock;
257 ControlBlock * m_control_block;
258 void * m_user_storage;
263 static constexpr
bool concurrent_puts =
false;
266 static constexpr
bool concurrent_consumes =
false;
270 static constexpr
bool concurrent_put_consumes =
false;
273 static constexpr
bool is_seq_cst =
true;
277 ALLOCATOR_TYPE::page_alignment >= ALLOCATOR_TYPE::page_size &&
278 (ALLOCATOR_TYPE::page_alignment % min_alignment) == 0,
279 "The alignment of the pages must be a power of 2, greater or equal to the size of the " 280 "pages, and a multiple of min_alignment");
283 ALLOCATOR_TYPE::page_size > (min_alignment +
alignof(ControlBlock)) * 4,
284 "Invalid page size");
296 : m_head(reinterpret_cast<ControlBlock *>(s_invalid_control_block)),
297 m_tail(reinterpret_cast<ControlBlock *>(s_invalid_control_block))
299 static_assert(std::is_nothrow_default_constructible<ALLOCATOR_TYPE>::value,
"");
312 constexpr
explicit heter_queue(
const ALLOCATOR_TYPE & i_source_allocator) noexcept
313 : ALLOCATOR_TYPE(i_source_allocator),
314 m_head(reinterpret_cast<ControlBlock *>(s_invalid_control_block)),
315 m_tail(reinterpret_cast<ControlBlock *>(s_invalid_control_block))
329 constexpr
explicit heter_queue(ALLOCATOR_TYPE && i_source_allocator) noexcept
330 : ALLOCATOR_TYPE(
std::move(i_source_allocator)),
331 m_head(reinterpret_cast<ControlBlock *>(s_invalid_control_block)),
332 m_tail(reinterpret_cast<ControlBlock *>(s_invalid_control_block))
334 static_assert(std::is_nothrow_move_constructible<ALLOCATOR_TYPE>::value,
"");
347 : ALLOCATOR_TYPE(
std::move(static_cast<ALLOCATOR_TYPE &&>(i_source))),
348 m_head(i_source.m_head), m_tail(i_source.m_tail)
350 static_assert(std::is_nothrow_move_constructible<ALLOCATOR_TYPE>::value,
"");
352 i_source.m_tail = i_source.m_head =
353 reinterpret_cast<ControlBlock *
>(s_invalid_control_block);
367 : allocator_type(static_cast<const allocator_type &>(i_source)),
368 m_head(reinterpret_cast<ControlBlock *>(s_invalid_control_block)),
369 m_tail(reinterpret_cast<ControlBlock *>(s_invalid_control_block))
371 for (
auto source_it = i_source.cbegin(); source_it != i_source.cend(); source_it++)
373 dyn_push_copy(source_it.complete_type(), source_it.element_ptr());
392 m_tail = m_head =
reinterpret_cast<ControlBlock *
>(s_invalid_control_block);
393 swap(*
this, i_source);
440 swap(static_cast<ALLOCATOR_TYPE &>(i_first), static_cast<ALLOCATOR_TYPE &>(i_second));
441 swap(i_first.m_head, i_second.m_head);
442 swap(i_first.m_tail, i_second.m_tail);
461 for (
auto curr = m_head; curr != m_tail;)
463 auto const control_bits = curr->m_next & (detail::Queue_Busy | detail::Queue_Dead);
464 if (control_bits == 0)
468 curr =
reinterpret_cast<ControlBlock *
>(curr->m_next & ~detail::Queue_AllFlags);
482 consume_operation consume;
483 while (try_start_consume(consume))
490 clean_dead_elements();
518 ELEMENT_COMPLETE_TYPE,
519 typename std::decay<ELEMENT_COMPLETE_TYPE>::type>::value,
545 typename =
typename std::enable_if<
546 std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
547 std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
549 : m_queue(i_source.m_queue), m_put_data(i_source.m_put_data)
551 i_source.m_queue =
nullptr;
561 typename =
typename std::enable_if<
562 std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
563 std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
574 std::swap(m_queue, i_source.m_queue);
575 std::swap(m_put_data, i_source.m_put_data);
586 swap(i_first.m_queue, i_second.m_queue);
587 swap(i_first.m_put_data, i_second.m_put_data);
616 m_queue->inplace_allocate<detail::Queue_Dead,
false>(i_size, i_alignment);
617 return push_data.m_user_storage;
644 template <
typename INPUT_ITERATOR>
645 typename std::iterator_traits<INPUT_ITERATOR>::value_type *
648 using ValueType =
typename std::iterator_traits<INPUT_ITERATOR>::value_type;
650 std::is_trivially_destructible<ValueType>::value,
651 "raw_allocate_copy provides a raw memory in-place allocation that does not " 653 "destructors when deallocating");
655 auto const count_s = std::distance(i_begin, i_end);
656 auto const count =
static_cast<size_t>(count_s);
659 auto const elements =
static_cast<ValueType *
>(
660 raw_allocate(
sizeof(ValueType) * count,
alignof(ValueType)));
661 for (
auto curr = elements; i_begin != i_end; ++i_begin, ++curr)
662 new (curr) ValueType(*i_begin);
688 template <
typename INPUT_RANGE>
690 -> decltype(std::declval<put_transaction>().raw_allocate_copy(
691 std::begin(i_source_range), std::end(i_source_range)))
693 return raw_allocate_copy(std::begin(i_source_range), std::end(i_source_range));
723 cancel_put_impl(m_put_data.m_control_block);
730 bool empty() const noexcept {
return m_queue ==
nullptr; }
735 explicit operator bool() const noexcept {
return m_queue !=
nullptr; }
760 return m_put_data.m_user_storage;
776 #ifndef DOXYGEN_DOC_GENERATION 778 typename EL = ELEMENT_COMPLETE_TYPE,
779 typename std::enable_if<!std::is_void<EL>::value>::type * =
nullptr>
782 ELEMENT_COMPLETE_TYPE &
786 return *
static_cast<ELEMENT_COMPLETE_TYPE *
>(element_ptr());
798 return *type_after_control(m_put_data.m_control_block);
806 if (m_queue !=
nullptr)
808 cancel_put_impl(m_put_data.m_control_block);
814 : m_queue(i_queue), m_put_data(i_push_data)
821 Allocation m_put_data;
865 : m_queue(i_source.m_queue), m_control(i_source.m_control)
867 i_source.m_control =
nullptr;
875 if (
this != &i_source)
881 m_queue = i_source.m_queue;
882 m_control = i_source.m_control;
883 i_source.m_control =
nullptr;
893 if (m_control !=
nullptr)
895 m_queue->cancel_consume_impl(m_control);
905 swap(i_first.m_queue, i_second.m_queue);
906 swap(i_first.m_control, i_second.m_control);
912 bool empty() const noexcept {
return m_control ==
nullptr; }
917 explicit operator bool() const noexcept {
return m_control !=
nullptr; }
924 return m_control !=
nullptr ? m_queue :
nullptr;
939 auto const & type = complete_type();
940 auto const element = element_ptr();
941 type.destroy(element);
943 type.RUNTIME_TYPE::~RUNTIME_TYPE();
945 m_queue->commit_consume_impl(m_control);
970 bool destroy_type = !std::is_trivially_destructible<RUNTIME_TYPE>::value;
973 auto const & type = complete_type();
974 type.RUNTIME_TYPE::~RUNTIME_TYPE();
977 m_queue->commit_consume_impl(m_control);
995 m_queue->cancel_consume_impl(m_control);
1007 return *type_after_control(m_control);
1020 return get_unaligned_element(m_control);
1033 return get_element(m_control);
1042 template <
typename COMPLETE_ELEMENT_TYPE>
1045 DENSITY_ASSERT(!empty() && complete_type().
template is<COMPLETE_ELEMENT_TYPE>());
1046 return *
static_cast<COMPLETE_ELEMENT_TYPE *
>(get_element(m_control));
1051 : m_queue(i_queue), m_control(i_control)
1056 bool start_consume_impl(PrivateType,
heter_queue * i_queue)
1058 if (m_control !=
nullptr)
1060 m_queue->cancel_consume_impl(m_control);
1063 m_control = i_queue->start_consume_impl();
1064 return m_control !=
nullptr;
1069 ControlBlock * m_control;
1089 template <
typename ELEMENT_TYPE>
void push(ELEMENT_TYPE && i_source)
1091 return emplace<typename std::decay<ELEMENT_TYPE>::type>(
1092 std::forward<ELEMENT_TYPE>(i_source));
1111 template <
typename ELEMENT_TYPE,
typename... CONSTRUCTION_PARAMS>
1112 void emplace(CONSTRUCTION_PARAMS &&... i_construction_params)
1114 start_emplace<ELEMENT_TYPE>(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...)
1134 void dyn_push(
const RUNTIME_TYPE & i_type) { start_dyn_push(i_type).commit(); }
1156 start_dyn_push_copy(i_type, i_source).commit();
1179 start_dyn_push_move(i_type, i_source).commit();
1206 template <
typename ELEMENT_TYPE>
1207 put_transaction<typename std::decay<ELEMENT_TYPE>::type>
1210 return start_emplace<typename std::decay<ELEMENT_TYPE>::type>(
1211 std::forward<ELEMENT_TYPE>(i_source));
1236 template <
typename ELEMENT_TYPE,
typename... CONSTRUCTION_PARAMS>
1237 put_transaction<ELEMENT_TYPE>
start_emplace(CONSTRUCTION_PARAMS &&... i_construction_params)
1239 auto push_data = inplace_allocate<
1242 detail::size_of<ELEMENT_TYPE>::value,
1243 alignof(ELEMENT_TYPE)>();
1245 RUNTIME_TYPE * type =
nullptr;
1248 auto const type_storage = type_after_control(push_data.m_control_block);
1250 type =
new (type_storage) RUNTIME_TYPE(RUNTIME_TYPE::template make<ELEMENT_TYPE>());
1253 new (push_data.m_user_storage)
1254 ELEMENT_TYPE(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
1258 if (type !=
nullptr)
1259 type->RUNTIME_TYPE::~RUNTIME_TYPE();
1261 (push_data.m_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
1263 push_data.m_control_block->m_next += detail::Queue_Dead;
1267 return put_transaction<ELEMENT_TYPE>(PrivateType(),
this, push_data);
1290 auto push_data = inplace_allocate<0, true>(i_type.size(), i_type.alignment());
1292 RUNTIME_TYPE * type =
nullptr;
1295 auto const type_storage = type_after_control(push_data.m_control_block);
1297 type =
new (type_storage) RUNTIME_TYPE(i_type);
1300 i_type.default_construct(push_data.m_user_storage);
1304 if (type !=
nullptr)
1305 type->RUNTIME_TYPE::~RUNTIME_TYPE();
1307 (push_data.m_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
1309 push_data.m_control_block->m_next += detail::Queue_Dead;
1313 return put_transaction<void>(PrivateType(),
this, push_data);
1339 auto push_data = inplace_allocate<0, true>(i_type.size(), i_type.alignment());
1341 RUNTIME_TYPE * type =
nullptr;
1344 auto const type_storage = type_after_control(push_data.m_control_block);
1346 type =
new (type_storage) RUNTIME_TYPE(i_type);
1349 i_type.copy_construct(push_data.m_user_storage, i_source);
1353 if (type !=
nullptr)
1354 type->RUNTIME_TYPE::~RUNTIME_TYPE();
1356 (push_data.m_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
1358 push_data.m_control_block->m_next += detail::Queue_Dead;
1362 return put_transaction<void>(PrivateType(),
this, push_data);
1387 auto push_data = inplace_allocate<0, true>(i_type.size(), i_type.alignment());
1389 RUNTIME_TYPE * type =
nullptr;
1392 auto const type_storage = type_after_control(push_data.m_control_block);
1394 type =
new (type_storage) RUNTIME_TYPE(i_type);
1397 i_type.move_construct(push_data.m_user_storage, i_source);
1401 if (type !=
nullptr)
1402 type->RUNTIME_TYPE::~RUNTIME_TYPE();
1404 (push_data.m_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
1406 push_data.m_control_block->m_next += detail::Queue_Dead;
1410 return put_transaction<void>(PrivateType(),
this, push_data);
1428 void pop() noexcept { try_start_consume().commit(); }
1442 if (
auto operation = try_start_consume())
1458 return consume_operation(PrivateType(),
this, start_consume_impl());
1476 return i_consume.start_consume_impl(PrivateType(),
this);
1505 ELEMENT_COMPLETE_TYPE,
1506 typename std::decay<ELEMENT_COMPLETE_TYPE>::type>::value,
1532 typename =
typename std::enable_if<
1533 std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
1534 std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
1536 : m_queue(i_source.m_queue), m_put_data(i_source.m_put_data)
1538 i_source.m_queue =
nullptr;
1548 typename =
typename std::enable_if<
1549 std::is_same<OTHERTYPE, ELEMENT_COMPLETE_TYPE>::value ||
1550 std::is_void<ELEMENT_COMPLETE_TYPE>::value>::type>
1556 static_cast<void *>(
1562 std::swap(m_queue, i_source.m_queue);
1563 std::swap(m_put_data, i_source.m_put_data);
1574 std::swap(i_first.m_queue, i_second.m_queue);
1575 std::swap(i_first.m_put_data, i_second.m_put_data);
1605 m_queue->inplace_allocate<detail::Queue_Dead,
false>(i_size, i_alignment);
1606 return push_data.m_user_storage;
1633 template <
typename INPUT_ITERATOR>
1634 typename std::iterator_traits<INPUT_ITERATOR>::value_type *
1637 using ValueType =
typename std::iterator_traits<INPUT_ITERATOR>::value_type;
1639 std::is_trivially_destructible<ValueType>::value,
1640 "raw_allocate_copy provides a raw memory in-place allocation that does not " 1642 "destructors when deallocating");
1644 auto const count_s = std::distance(i_begin, i_end);
1645 auto const count =
static_cast<size_t>(count_s);
1646 DENSITY_ASSUME(
static_cast<decltype(count_s)
>(count) == count_s);
1648 auto const elements =
static_cast<ValueType *
>(
1649 raw_allocate(
sizeof(ValueType) * count,
alignof(ValueType)));
1650 for (
auto curr = elements; i_begin != i_end; ++i_begin, ++curr)
1651 new (curr) ValueType(*i_begin);
1677 template <
typename INPUT_RANGE>
1679 -> decltype(std::declval<reentrant_put_transaction>().raw_allocate_copy(
1680 std::begin(i_source_range), std::end(i_source_range)))
1682 return raw_allocate_copy(std::begin(i_source_range), std::end(i_source_range));
1696 commit_reentrant_put_impl(m_put_data.m_control_block);
1714 cancel_reentrant_put_impl(m_put_data.m_control_block);
1721 bool empty() const noexcept {
return m_queue ==
nullptr; }
1726 explicit operator bool() const noexcept {
return m_queue !=
nullptr; }
1747 return m_put_data.m_user_storage;
1763 #ifndef DOXYGEN_DOC_GENERATION 1765 typename EL = ELEMENT_COMPLETE_TYPE,
1766 typename std::enable_if<!std::is_void<EL>::value>::type * =
nullptr>
1769 ELEMENT_COMPLETE_TYPE &
1773 return *
static_cast<ELEMENT_COMPLETE_TYPE *
>(element_ptr());
1785 return *type_after_control(m_put_data.m_control_block);
1793 if (m_queue !=
nullptr)
1795 cancel_reentrant_put_impl(m_put_data.m_control_block);
1801 PrivateType,
heter_queue * i_queue, Allocation i_push_data) noexcept
1802 : m_queue(i_queue), m_put_data(i_push_data)
1809 Allocation m_put_data;
1853 : m_queue(i_source.m_queue), m_control(i_source.m_control)
1855 i_source.m_control =
nullptr;
1864 if (
this != &i_source)
1870 m_queue = i_source.m_queue;
1871 m_control = i_source.m_control;
1872 i_source.m_control =
nullptr;
1882 if (m_control !=
nullptr)
1884 m_queue->cancel_consume_impl(m_control);
1895 std::swap(i_first.m_queue, i_second.m_queue);
1896 std::swap(i_first.m_control, i_second.m_control);
1902 bool empty() const noexcept {
return m_control ==
nullptr; }
1907 explicit operator bool() const noexcept {
return m_control !=
nullptr; }
1914 return m_control !=
nullptr ? m_queue :
nullptr;
1929 auto const & type = complete_type();
1930 auto const element = element_ptr();
1931 type.destroy(element);
1933 type.RUNTIME_TYPE::~RUNTIME_TYPE();
1935 m_queue->commit_consume_impl(m_control);
1936 m_control =
nullptr;
1960 bool destroy_type = !std::is_trivially_destructible<RUNTIME_TYPE>::value;
1963 auto const & type = complete_type();
1964 type.RUNTIME_TYPE::~RUNTIME_TYPE();
1967 m_queue->commit_consume_impl(m_control);
1968 m_control =
nullptr;
1985 m_queue->cancel_consume_impl(m_control);
1986 m_control =
nullptr;
1997 return *type_after_control(m_control);
2010 return get_unaligned_element(m_control);
2023 return get_element(m_control);
2032 template <
typename COMPLETE_ELEMENT_TYPE>
2035 DENSITY_ASSERT(!empty() && complete_type().
template is<COMPLETE_ELEMENT_TYPE>());
2036 return *
static_cast<COMPLETE_ELEMENT_TYPE *
>(get_element(m_control));
2041 PrivateType,
heter_queue * i_queue, ControlBlock * i_control) noexcept
2042 : m_queue(i_queue), m_control(i_control)
2047 bool start_consume_impl(PrivateType,
heter_queue * i_queue) noexcept
2049 if (m_control !=
nullptr)
2051 m_queue->cancel_consume_impl(m_control);
2054 m_control = i_queue->start_consume_impl();
2055 return m_control !=
nullptr;
2060 ControlBlock * m_control;
2070 return reentrant_emplace<typename std::decay<ELEMENT_TYPE>::type>(
2071 std::forward<ELEMENT_TYPE>(i_source));
2079 template <
typename ELEMENT_TYPE,
typename... CONSTRUCTION_PARAMS>
2082 start_reentrant_emplace<ELEMENT_TYPE>(
2083 std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...)
2094 start_reentrant_dyn_push(i_type).commit();
2104 start_reentrant_dyn_push_copy(i_type, i_source).commit();
2114 start_reentrant_dyn_push_move(i_type, i_source).commit();
2122 template <
typename ELEMENT_TYPE>
2123 reentrant_put_transaction<typename std::decay<ELEMENT_TYPE>::type>
2126 return start_reentrant_emplace<typename std::decay<ELEMENT_TYPE>::type>(
2127 std::forward<ELEMENT_TYPE>(i_source));
2135 template <
typename ELEMENT_TYPE,
typename... CONSTRUCTION_PARAMS>
2136 reentrant_put_transaction<ELEMENT_TYPE>
2139 auto push_data = inplace_allocate<
2142 detail::size_of<ELEMENT_TYPE>::value,
2143 alignof(ELEMENT_TYPE)>();
2145 RUNTIME_TYPE * type =
nullptr;
2148 auto const type_storage = type_after_control(push_data.m_control_block);
2150 type =
new (type_storage) RUNTIME_TYPE(RUNTIME_TYPE::template make<ELEMENT_TYPE>());
2153 new (push_data.m_user_storage)
2154 ELEMENT_TYPE(std::forward<CONSTRUCTION_PARAMS>(i_construction_params)...);
2158 if (type !=
nullptr)
2159 type->RUNTIME_TYPE::~RUNTIME_TYPE();
2161 (push_data.m_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
2162 detail::Queue_Busy);
2163 push_data.m_control_block->m_next += detail::Queue_Dead - detail::Queue_Busy;
2167 return reentrant_put_transaction<ELEMENT_TYPE>(PrivateType(),
this, push_data);
2178 inplace_allocate<detail::Queue_Busy, true>(i_type.size(), i_type.alignment());
2180 RUNTIME_TYPE * type =
nullptr;
2183 auto const type_storage = type_after_control(push_data.m_control_block);
2185 type =
new (type_storage) RUNTIME_TYPE(i_type);
2188 i_type.default_construct(push_data.m_user_storage);
2192 if (type !=
nullptr)
2193 type->RUNTIME_TYPE::~RUNTIME_TYPE();
2195 (push_data.m_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
2196 detail::Queue_Busy);
2197 push_data.m_control_block->m_next += detail::Queue_Dead - detail::Queue_Busy;
2201 return reentrant_put_transaction<void>(PrivateType(),
this, push_data);
2210 reentrant_put_transaction<>
2214 inplace_allocate<detail::Queue_Busy, true>(i_type.size(), i_type.alignment());
2216 RUNTIME_TYPE * type =
nullptr;
2219 auto const type_storage = type_after_control(push_data.m_control_block);
2221 type =
new (type_storage) RUNTIME_TYPE(i_type);
2224 i_type.copy_construct(push_data.m_user_storage, i_source);
2228 if (type !=
nullptr)
2229 type->RUNTIME_TYPE::~RUNTIME_TYPE();
2231 (push_data.m_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
2232 detail::Queue_Busy);
2233 push_data.m_control_block->m_next += detail::Queue_Dead - detail::Queue_Busy;
2237 return reentrant_put_transaction<void>(PrivateType(),
this, push_data);
2245 reentrant_put_transaction<>
2249 inplace_allocate<detail::Queue_Busy, true>(i_type.size(), i_type.alignment());
2251 RUNTIME_TYPE * type =
nullptr;
2254 auto const type_storage = type_after_control(push_data.m_control_block);
2256 type =
new (type_storage) RUNTIME_TYPE(i_type);
2259 i_type.move_construct(push_data.m_user_storage, i_source);
2263 if (type !=
nullptr)
2264 type->RUNTIME_TYPE::~RUNTIME_TYPE();
2266 (push_data.m_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
2267 detail::Queue_Busy);
2268 push_data.m_control_block->m_next += detail::Queue_Dead - detail::Queue_Busy;
2272 return reentrant_put_transaction<void>(PrivateType(),
this, push_data);
2305 if (
auto operation = try_start_reentrant_consume())
2324 return reentrant_consume_operation(PrivateType(),
this, start_consume_impl());
2344 return i_consume.start_consume_impl(PrivateType(),
this);
2350 class const_iterator
2353 using iterator_category = std::input_iterator_tag;
2354 using runtime_type = RUNTIME_TYPE;
2360 using size_type = std::size_t;
2361 using difference_type = std::ptrdiff_t;
2363 const_iterator() noexcept =
default;
2364 const_iterator(
const const_iterator & i_source) noexcept
2365 : m_control(i_source.m_control), m_queue(i_source.m_queue)
2367 new (&m_value.m_pair)
value_type(m_value.m_pair);
2370 const_iterator & operator=(
const const_iterator & i_source) noexcept
2372 m_control = i_source.m_control;
2373 m_queue = i_source.m_queue;
2374 new (&m_value.m_pair)
value_type(m_value.m_pair);
2378 const_iterator(
const heter_queue * i_queue, ControlBlock * i_control) noexcept
2379 : m_control(i_control), m_queue(i_queue)
2381 if (m_control !=
nullptr)
2383 const RUNTIME_TYPE & type = *type_after_control(m_control);
2384 new (&m_value.m_pair)
value_type(type, get_element(m_control));
2388 const value_type & operator*()
const noexcept
2391 return m_value.m_pair;
2394 const value_type * operator->()
const noexcept
2397 return &m_value.m_pair;
2400 const RUNTIME_TYPE & complete_type()
const noexcept
2403 return m_value.m_pair.type();
2406 const void * element_ptr()
const noexcept
2409 return m_value.m_pair.address();
2412 const_iterator & operator++() noexcept
2415 m_control = m_queue->next_valid(m_control);
2416 if (m_control !=
nullptr)
2418 RUNTIME_TYPE & type = *type_after_control(m_control);
2419 new (&m_value.m_pair)
value_type(type, get_element(m_control));
2424 const_iterator operator++(
int) noexcept
2427 auto const prev_state = *
this;
2432 bool operator==(
const const_iterator & i_other)
const noexcept
2434 return m_control == i_other.m_control;
2437 bool operator!=(
const const_iterator & i_other)
const noexcept
2439 return m_control != i_other.m_control;
2443 ControlBlock * m_control =
nullptr;
2457 using iterator_category = std::input_iterator_tag;
2458 using runtime_type = RUNTIME_TYPE;
2464 using size_type = std::size_t;
2465 using difference_type = std::ptrdiff_t;
2467 iterator() noexcept =
default;
2468 iterator(
const iterator & i_source) noexcept
2469 : m_control(i_source.m_control), m_queue(i_source.m_queue)
2471 new (&m_value.m_pair)
value_type(m_value.m_pair);
2474 iterator & operator=(
const iterator & i_source) noexcept
2476 m_control = i_source.m_control;
2477 m_queue = i_source.m_queue;
2478 new (&m_value.m_pair)
value_type(m_value.m_pair);
2482 iterator(
const heter_queue * i_queue, ControlBlock * i_control) noexcept
2483 : m_control(i_control), m_queue(i_queue)
2485 if (m_control !=
nullptr)
2487 const RUNTIME_TYPE & type = *type_after_control(m_control);
2488 new (&m_value.m_pair)
value_type(type, get_element(m_control));
2492 const value_type & operator*()
const noexcept
2495 return m_value.m_pair;
2498 const value_type * operator->()
const noexcept
2501 return &m_value.m_pair;
2504 const RUNTIME_TYPE & complete_type()
const noexcept
2507 return m_value.m_pair.type();
2510 void * element_ptr()
const noexcept
2513 return m_value.m_pair.address();
2516 iterator & operator++() noexcept
2519 m_control = m_queue->next_valid(m_control);
2520 if (m_control !=
nullptr)
2522 RUNTIME_TYPE & type = *type_after_control(m_control);
2523 new (&m_value.m_pair)
value_type(type, get_element(m_control));
2528 iterator operator++(
int) noexcept
2531 auto const prev_state = *
this;
2536 bool operator==(
const iterator & i_other)
const noexcept
2538 return m_control == i_other.m_control;
2541 bool operator!=(
const iterator & i_other)
const noexcept
2543 return m_control != i_other.m_control;
2547 ControlBlock * m_control =
nullptr;
2556 iterator begin() noexcept {
return iterator(
this, first_valid(m_head)); }
2557 iterator end() noexcept {
return iterator(); }
2559 const_iterator begin()
const noexcept {
return const_iterator(
this, first_valid(m_head)); }
2560 const_iterator end()
const noexcept {
return const_iterator(); }
2562 const_iterator cbegin()
const noexcept {
return const_iterator(
this, first_valid(m_head)); }
2563 const_iterator cend()
const noexcept {
return const_iterator(); }
2582 const auto end_1 = cend();
2583 const auto end_2 = i_source.cend();
2584 auto it_2 = i_source.cbegin();
2585 for (
auto it_1 = cbegin(); it_1 != end_1; ++it_1, ++it_2)
2588 it_2 == end_2 || it_1.complete_type() != it_2.complete_type() ||
2589 !it_1.complete_type().are_equal(it_1.element_ptr(), it_2.element_ptr()))
2594 return it_2 == end_2;
2615 ControlBlock * first_valid(ControlBlock * i_from)
const 2617 for (
auto curr = i_from; curr != m_tail;)
2619 if ((curr->m_next & (detail::Queue_Busy | detail::Queue_Dead)) == 0)
2623 curr =
reinterpret_cast<ControlBlock *
>(curr->m_next & ~detail::Queue_AllFlags);
2628 ControlBlock * next_valid(ControlBlock * i_from)
const 2632 reinterpret_cast<ControlBlock *>(i_from->m_next & ~static_cast<uintptr_t>(3));
2635 if ((curr->m_next & (detail::Queue_Busy | detail::Queue_Dead)) == 0)
2639 curr =
reinterpret_cast<ControlBlock *
>(curr->m_next & ~detail::Queue_AllFlags);
2644 static RUNTIME_TYPE * type_after_control(ControlBlock * i_control) noexcept
2646 return reinterpret_cast<RUNTIME_TYPE *
>(
address_add(i_control, s_sizeof_ControlBlock));
2649 static void * get_unaligned_element(ControlBlock * i_control) noexcept
2651 auto result =
address_add(i_control, s_sizeof_ControlBlock + s_sizeof_RuntimeType);
2652 if (i_control->m_next & detail::Queue_External)
2654 result =
static_cast<ExternalBlock *
>(result)->m_element;
2659 static void * get_element(detail::QueueControl * i_control) noexcept
2661 auto result =
address_add(i_control, s_sizeof_ControlBlock + s_sizeof_RuntimeType);
2662 if (i_control->m_next & detail::Queue_External)
2664 result =
static_cast<ExternalBlock *
>(result)->m_element;
2674 static bool same_page(
const void * i_first,
const void * i_second) noexcept
2676 auto const page_mask = ALLOCATOR_TYPE::page_alignment - 1;
2677 return ((reinterpret_cast<uintptr_t>(i_first) ^ reinterpret_cast<uintptr_t>(i_second)) &
2681 struct ExternalBlock
2684 size_t m_size, m_alignment;
2687 static void * get_end_of_page(
void * i_address) noexcept
2691 allocator_type::page_size - s_sizeof_ControlBlock);
2697 template <u
intptr_t CONTROL_BITS,
bool INCLUDE_TYPE>
2698 Allocation inplace_allocate(
size_t i_size,
size_t i_alignment)
2702 if (i_alignment < min_alignment)
2704 i_alignment = min_alignment;
2712 m_tail == reinterpret_cast<ControlBlock *>(s_invalid_control_block));
2715 auto const control_block = m_tail;
2718 INCLUDE_TYPE ? (s_sizeof_ControlBlock + s_sizeof_RuntimeType)
2719 : s_sizeof_ControlBlock);
2723 void *
const user_storage = new_tail;
2727 void * end_of_page = get_end_of_page(control_block);
2731 new (control_block) ControlBlock();
2733 control_block->m_next =
reinterpret_cast<uintptr_t
>(new_tail) + CONTROL_BITS;
2734 m_tail =
static_cast<ControlBlock *
>(new_tail);
2735 return Allocation{control_block, user_storage};
2738 i_size + (i_alignment - min_alignment) <=
2742 allocate_new_page();
2747 return external_allocate<CONTROL_BITS>(i_size, i_alignment);
2753 template <u
intptr_t CONTROL_BITS,
bool INCLUDE_TYPE,
size_t SIZE,
size_t ALIGNMENT>
2754 Allocation inplace_allocate()
2756 static_assert(
is_power_of_2(ALIGNMENT) && (SIZE % ALIGNMENT) == 0,
"");
2760 m_tail == reinterpret_cast<ControlBlock *>(s_invalid_control_block));
2762 constexpr
size_t alignment = detail::size_max(ALIGNMENT, min_alignment);
2764 constexpr
bool can_fit_in_a_page =
2765 size + (alignment - min_alignment) <= s_max_size_inpage;
2766 constexpr
bool over_aligned = alignment > min_alignment;
2771 auto const control_block = m_tail;
2774 INCLUDE_TYPE ? (s_sizeof_ControlBlock + s_sizeof_RuntimeType)
2775 : s_sizeof_ControlBlock);
2784 m_tail == reinterpret_cast<ControlBlock *>(s_invalid_control_block));
2785 void * new_element = new_tail;
2789 void * end_of_page = get_end_of_page(control_block);
2793 new (control_block) ControlBlock();
2795 control_block->m_next =
reinterpret_cast<uintptr_t
>(new_tail) + CONTROL_BITS;
2796 m_tail =
static_cast<ControlBlock *
>(new_tail);
2797 return Allocation{control_block, new_element};
2799 else if (can_fit_in_a_page)
2802 allocate_new_page();
2807 return external_allocate<CONTROL_BITS>(size, alignment);
2812 template <u
intptr_t CONTROL_BITS>
2813 Allocation external_allocate(
size_t i_size,
size_t i_alignment)
2815 auto const external_block = ALLOCATOR_TYPE::allocate(i_size, i_alignment);
2820 auto const inplace_put = inplace_allocate<CONTROL_BITS, true>(
2821 sizeof(ExternalBlock),
alignof(ExternalBlock));
2823 new (inplace_put.m_user_storage) ExternalBlock{external_block, i_size, i_alignment};
2825 DENSITY_ASSERT((inplace_put.m_control_block->m_next & detail::Queue_External) == 0);
2826 inplace_put.m_control_block->m_next |= detail::Queue_External;
2827 return Allocation{inplace_put.m_control_block, external_block};
2834 ALLOCATOR_TYPE::deallocate(external_block, i_size, i_alignment);
2842 if (
DENSITY_LIKELY(m_tail != reinterpret_cast<ControlBlock *>(s_invalid_control_block)))
2844 auto const control_block = m_tail;
2847 new (control_block) ControlBlock();
2849 auto new_page = allocator_type::allocate_page();
2850 control_block->m_next =
reinterpret_cast<uintptr_t
>(new_page) + detail::Queue_Dead;
2851 m_tail =
static_cast<ControlBlock *
>(new_page);
2856 m_tail = m_head =
static_cast<ControlBlock *
>(allocator_type::allocate_page());
2862 const auto type_ptr = type_after_control(i_control_block);
2863 type_ptr->destroy(get_element(i_control_block));
2865 type_ptr->RUNTIME_TYPE::~RUNTIME_TYPE();
2868 (i_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) == 0);
2869 i_control_block->m_next += detail::Queue_Dead;
2872 static void commit_reentrant_put_impl(ControlBlock * i_control_block)
2875 (i_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
2876 detail::Queue_Busy);
2877 i_control_block->m_next -= detail::Queue_Busy;
2880 DENSITY_NO_INLINE static void cancel_reentrant_put_impl(ControlBlock * i_control_block)
2882 const auto type_ptr = type_after_control(i_control_block);
2883 type_ptr->destroy(get_element(i_control_block));
2885 type_ptr->RUNTIME_TYPE::~RUNTIME_TYPE();
2888 (i_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
2889 detail::Queue_Busy);
2890 i_control_block->m_next += (detail::Queue_Dead - detail::Queue_Busy);
2893 ControlBlock * start_consume_impl() noexcept
2896 auto const tail = m_tail;
2897 while (curr != tail)
2899 if ((curr->m_next & (detail::Queue_Busy | detail::Queue_Dead)) == 0)
2901 curr->m_next += detail::Queue_Busy;
2905 curr =
reinterpret_cast<ControlBlock *
>(curr->m_next & ~detail::Queue_AllFlags);
2911 void commit_consume_impl(ControlBlock * i_control_block) noexcept
2914 (i_control_block->m_next & (detail::Queue_Busy | detail::Queue_Dead)) ==
2915 detail::Queue_Busy);
2916 i_control_block->m_next += (detail::Queue_Dead - detail::Queue_Busy);
2918 clean_dead_elements();
2921 void clean_dead_elements() noexcept
2924 while (curr != m_tail)
2928 (curr->m_next & (detail::Queue_Busy | detail::Queue_Dead)) != detail::Queue_Dead)
2934 reinterpret_cast<ControlBlock *
>(curr->m_next & ~detail::Queue_AllFlags);
2935 if (curr->m_next & detail::Queue_External)
2937 auto result =
address_add(curr, s_sizeof_ControlBlock + s_sizeof_RuntimeType);
2938 const auto & block = *
static_cast<ExternalBlock *
>(result);
2939 ALLOCATOR_TYPE::deallocate(block.m_element, block.m_size, block.m_alignment);
2942 if (!same_page(next, curr))
2944 allocator_type::deallocate_page(curr);
2952 (curr->m_next & (detail::Queue_Busy | detail::Queue_Dead)) != detail::Queue_Dead);
2956 void cancel_consume_impl(ControlBlock * i_control_block) noexcept
2959 (i_control_block->m_next & (detail::Queue_AllFlags - detail::Queue_External)) ==
2960 detail::Queue_Busy);
2961 i_control_block->m_next -= detail::Queue_Busy;
2964 void destroy() noexcept
2968 if (m_head != reinterpret_cast<ControlBlock *>(s_invalid_control_block))
2970 allocator_type::deallocate_page(m_head);
~consume_operation()
Definition: heter_queue.h:891
void * address_add(void *i_address, size_t i_offset) noexcept
Definition: density_common.h:142
void commit_nodestroy() noexcept
Definition: heter_queue.h:1956
reentrant_consume_operation(reentrant_consume_operation &&i_source) noexcept
Definition: heter_queue.h:1852
put_transaction start_dyn_push(const RUNTIME_TYPE &i_type)
Definition: heter_queue.h:1288
bool empty() const noexcept
Definition: heter_queue.h:458
bool address_is_aligned(const void *i_address, size_t i_alignment) noexcept
Definition: density_common.h:118
const RUNTIME_TYPE & complete_type() const noexcept
Definition: heter_queue.h:1994
reentrant_put_transaction start_reentrant_dyn_push(const RUNTIME_TYPE &i_type)
Definition: heter_queue.h:2175
heter_queue(const heter_queue &i_source)
Definition: heter_queue.h:366
reentrant_put_transaction start_reentrant_dyn_push_copy(const RUNTIME_TYPE &i_type, const void *i_source)
Definition: heter_queue.h:2211
allocator_type get_allocator() noexcept(std::is_nothrow_copy_constructible< allocator_type >::value)
Definition: heter_queue.h:417
void * unaligned_element_ptr() const noexcept
Definition: heter_queue.h:1017
void commit() noexcept
Definition: heter_queue.h:704
put_transaction< ELEMENT_TYPE > start_emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: heter_queue.h:1237
heter_queue(heter_queue &&i_source) noexcept
Definition: heter_queue.h:346
Definition: conc_function_queue.h:11
void commit_nodestroy() noexcept
Definition: heter_queue.h:966
void emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: heter_queue.h:1112
friend void swap(consume_operation &i_first, consume_operation &i_second) noexcept
Definition: heter_queue.h:902
heter_queue * queue() const noexcept
Definition: heter_queue.h:1731
void cancel() noexcept
Definition: heter_queue.h:720
constexpr heter_queue(const ALLOCATOR_TYPE &i_source_allocator) noexcept
Definition: heter_queue.h:312
void commit() noexcept
Definition: heter_queue.h:1693
ELEMENT_COMPLETE_TYPE & element() const noexcept
Definition: heter_queue.h:784
void cancel() noexcept
Definition: heter_queue.h:1981
bool operator==(const heter_queue &i_source) const
Definition: heter_queue.h:2580
friend void swap(heter_queue< RUNTIME_TYPE, ALLOCATOR_TYPE > &i_first, heter_queue< RUNTIME_TYPE, ALLOCATOR_TYPE > &i_second) noexcept
Definition: heter_queue.h:435
Definition: runtime_type.h:1061
Definition: heter_queue.h:200
void dyn_push_move(const RUNTIME_TYPE &i_type, void *i_source)
Definition: heter_queue.h:1177
const RUNTIME_TYPE & complete_type() const noexcept
Definition: heter_queue.h:1004
void * raw_allocate(size_t i_size, size_t i_alignment)
Definition: heter_queue.h:1600
reentrant_consume_operation() noexcept
Definition: heter_queue.h:1837
put_transaction() noexcept
Definition: heter_queue.h:524
void reentrant_dyn_push(const RUNTIME_TYPE &i_type)
Definition: heter_queue.h:2092
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: heter_queue.h:1678
void push(ELEMENT_TYPE &&i_source)
Definition: heter_queue.h:1089
Definition: heter_queue.h:1501
heter_queue * queue() const noexcept
Definition: heter_queue.h:922
bool try_start_reentrant_consume(reentrant_consume_operation &i_consume) noexcept
Definition: heter_queue.h:2342
COMPLETE_ELEMENT_TYPE & element() const noexcept
Definition: heter_queue.h:2033
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: heter_queue.h:689
void commit() noexcept
Definition: heter_queue.h:935
put_transaction & operator=(put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: heter_queue.h:564
#define DENSITY_ASSERT(...)
Definition: density_config.h:19
const RUNTIME_TYPE & complete_type() const noexcept
Definition: heter_queue.h:795
reentrant_put_transaction(reentrant_put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: heter_queue.h:1535
#define DENSITY_NO_INLINE
Definition: density_config.h:86
Definition: heter_queue.h:843
bool empty() const noexcept
Definition: heter_queue.h:1721
reentrant_consume_operation try_start_reentrant_consume() noexcept
Definition: heter_queue.h:2322
Definition: heter_queue.h:514
put_transaction< typename std::decay< ELEMENT_TYPE >::type > start_push(ELEMENT_TYPE &&i_source)
Definition: heter_queue.h:1208
void reentrant_dyn_push_move(const RUNTIME_TYPE &i_type, void *i_source)
Definition: heter_queue.h:2112
void * element_ptr() const noexcept
Definition: heter_queue.h:757
std::iterator_traits< INPUT_ITERATOR >::value_type * raw_allocate_copy(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end)
Definition: heter_queue.h:646
allocator_type & get_allocator_ref() noexcept
Definition: heter_queue.h:425
ELEMENT_COMPLETE_TYPE & element() const noexcept
Definition: heter_queue.h:1771
~reentrant_put_transaction()
Definition: heter_queue.h:1791
consume_operation() noexcept
Definition: heter_queue.h:849
void pop() noexcept
Definition: heter_queue.h:1428
heter_queue * queue() const noexcept
Definition: heter_queue.h:740
void cancel() noexcept
Definition: heter_queue.h:1711
heter_queue & operator=(const heter_queue &i_source)
Definition: heter_queue.h:406
void clear() noexcept
Definition: heter_queue.h:480
Definition: heter_queue.h:1831
bool operator!=(const heter_queue &i_source) const
Definition: heter_queue.h:2612
constexpr bool is_power_of_2(size_t i_number) noexcept
Definition: density_common.h:109
constexpr heter_queue(ALLOCATOR_TYPE &&i_source_allocator) noexcept
Definition: heter_queue.h:329
friend void swap(reentrant_consume_operation &i_first, reentrant_consume_operation &i_second) noexcept
Definition: heter_queue.h:1891
heter_queue & operator=(heter_queue &&i_source) noexcept
Definition: heter_queue.h:389
bool empty() const noexcept
Definition: heter_queue.h:912
void * raw_allocate(size_t i_size, size_t i_alignment)
Definition: heter_queue.h:612
void * address_upper_align(void *i_address, size_t i_alignment) noexcept
Definition: density_common.h:264
void reentrant_pop() noexcept
Definition: heter_queue.h:2290
bool try_reentrant_pop() noexcept
Definition: heter_queue.h:2303
void reentrant_dyn_push_copy(const RUNTIME_TYPE &i_type, const void *i_source)
Definition: heter_queue.h:2102
~heter_queue()
Definition: heter_queue.h:450
const RUNTIME_TYPE & complete_type() const noexcept
Definition: heter_queue.h:1782
#define DENSITY_ASSERT_INTERNAL(...)
Definition: density_config.h:28
reentrant_consume_operation & operator=(reentrant_consume_operation &&i_source) noexcept
Definition: heter_queue.h:1862
void * address_lower_align(void *i_address, size_t i_alignment) noexcept
Definition: density_common.h:198
reentrant_put_transaction start_reentrant_dyn_push_move(const RUNTIME_TYPE &i_type, void *i_source)
Definition: heter_queue.h:2246
consume_operation try_start_consume() noexcept
Definition: heter_queue.h:1456
COMPLETE_ELEMENT_TYPE & element() const noexcept
Definition: heter_queue.h:1043
put_transaction start_dyn_push_copy(const RUNTIME_TYPE &i_type, const void *i_source)
Definition: heter_queue.h:1337
friend void swap(put_transaction &i_first, put_transaction &i_second) noexcept
Definition: heter_queue.h:583
consume_operation(consume_operation &&i_source) noexcept
Definition: heter_queue.h:864
put_transaction(put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: heter_queue.h:548
bool try_pop() noexcept
Definition: heter_queue.h:1440
~put_transaction()
Definition: heter_queue.h:804
friend void swap(reentrant_put_transaction &i_first, reentrant_put_transaction &i_second) noexcept
Definition: heter_queue.h:1571
constexpr UINT uint_upper_align(UINT i_uint, size_t i_alignment) noexcept
Definition: density_common.h:297
const allocator_type & get_allocator_ref() const noexcept
Definition: heter_queue.h:430
consume_operation & operator=(consume_operation &&i_source) noexcept
Definition: heter_queue.h:873
void commit() noexcept
Definition: heter_queue.h:1925
void reentrant_push(ELEMENT_TYPE &&i_source)
Definition: heter_queue.h:2068
reentrant_put_transaction() noexcept
Definition: heter_queue.h:1511
void * element_ptr() const noexcept
Definition: heter_queue.h:1744
void dyn_push_copy(const RUNTIME_TYPE &i_type, const void *i_source)
Definition: heter_queue.h:1154
void dyn_push(const RUNTIME_TYPE &i_type)
Definition: heter_queue.h:1134
#define DENSITY_LIKELY(bool_expr)
Definition: density_config.h:76
Definition: dynamic_reference.h:107
~reentrant_consume_operation()
Definition: heter_queue.h:1880
void * element_ptr() const noexcept
Definition: heter_queue.h:1030
constexpr heter_queue() noexcept
Definition: heter_queue.h:295
bool empty() const noexcept
Definition: heter_queue.h:730
bool try_start_consume(consume_operation &i_consume) noexcept
Definition: heter_queue.h:1474
void reentrant_emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: heter_queue.h:2080
reentrant_put_transaction< ELEMENT_TYPE > start_reentrant_emplace(CONSTRUCTION_PARAMS &&...i_construction_params)
Definition: heter_queue.h:2137
heter_queue * queue() const noexcept
Definition: heter_queue.h:1912
reentrant_put_transaction< typename std::decay< ELEMENT_TYPE >::type > start_reentrant_push(ELEMENT_TYPE &&i_source)
Definition: heter_queue.h:2124
void * unaligned_element_ptr() const noexcept
Definition: heter_queue.h:2007
#define DENSITY_ASSUME(bool_expr,...)
Definition: density_config.h:46
void * element_ptr() const noexcept
Definition: heter_queue.h:2020
reentrant_put_transaction & operator=(reentrant_put_transaction< OTHERTYPE > &&i_source) noexcept
Definition: heter_queue.h:1552
void cancel() noexcept
Definition: heter_queue.h:991
std::iterator_traits< INPUT_ITERATOR >::value_type * raw_allocate_copy(INPUT_ITERATOR i_begin, INPUT_ITERATOR i_end)
Definition: heter_queue.h:1635
bool empty() const noexcept
Definition: heter_queue.h:1902
put_transaction start_dyn_push_move(const RUNTIME_TYPE &i_type, void *i_source)
Definition: heter_queue.h:1385