density
C++11 library for paged memory management, function queues, heterogeneous queues and lifo memory management
Public Member Functions | Friends | List of all members
heter_queue< RUNTIME_TYPE, ALLOCATOR_TYPE >::reentrant_consume_operation Class Reference

#include <heter_queue.h>

Public Member Functions

 reentrant_consume_operation () noexcept
 
 reentrant_consume_operation (const reentrant_consume_operation &)=delete
 
reentrant_consume_operationoperator= (const reentrant_consume_operation &)=delete
 
 reentrant_consume_operation (reentrant_consume_operation &&i_source) noexcept
 
reentrant_consume_operationoperator= (reentrant_consume_operation &&i_source) noexcept
 
 ~reentrant_consume_operation ()
 
bool empty () const noexcept
 
 operator bool () const noexcept
 
heter_queuequeue () const noexcept
 
void commit () noexcept
 
void commit_nodestroy () noexcept
 
void cancel () noexcept
 
const RUNTIME_TYPE & complete_type () const noexcept
 
void * unaligned_element_ptr () const noexcept
 
void * element_ptr () const noexcept
 
template<typename COMPLETE_ELEMENT_TYPE >
COMPLETE_ELEMENT_TYPE & element () const noexcept
 
 reentrant_consume_operation (PrivateType, heter_queue *i_queue, ControlBlock *i_control) noexcept
 
bool start_consume_impl (PrivateType, heter_queue *i_queue) noexcept
 

Friends

void swap (reentrant_consume_operation &i_first, reentrant_consume_operation &i_second) noexcept
 

Detailed Description

template<typename RUNTIME_TYPE = runtime_type<>, typename ALLOCATOR_TYPE = default_allocator>
class density::heter_queue< RUNTIME_TYPE, ALLOCATOR_TYPE >::reentrant_consume_operation

Move-only class that can be bound to a reentrant consume operation, otherwise it's empty.

Reentrant consume functions on heter_queue return a non-empty reentrant_consume_operation that can be used to inspect or alter the element while it is not observable in the queue, and commit or cancel the consume.

A reentrant_consume_operation is empty when:

Calling commit, commit_nodestroy, cancel, element_ptr, unaligned_element_ptr, element or complete_type on an empty reentrant_consume_operation triggers undefined behavior.

Constructor & Destructor Documentation

reentrant_consume_operation ( )
inlinenoexcept

Constructs an empty reentrant_consume_operation

heter_queue<>::reentrant_consume_operation consume;
assert(consume.empty());

Copy construction is not allowed

static_assert(
!std::is_copy_constructible<heter_queue<>::reentrant_consume_operation>::value, "");

Move constructor. The source is left empty.

heter_queue<> queue;
queue.push(42);
auto consume = queue.try_start_reentrant_consume();
auto consume_1 = std::move(consume);
assert(consume.empty() && !consume_1.empty());
consume_1.commit();

Destructor: cancel the operation (if any).

heter_queue<> queue;
queue.push(42);
// this consumed is started and destroyed before being committed, so it has no observable effects
queue.try_start_reentrant_consume();

Member Function Documentation

Copy assignment is not allowed

static_assert(
!std::is_copy_assignable<heter_queue<>::reentrant_consume_operation>::value, "");
reentrant_consume_operation& operator= ( reentrant_consume_operation &&  i_source)
inlinenoexcept

Move assignment. The source is left empty.

heter_queue<> queue;
queue.push(42);
queue.push(43);
auto consume = queue.try_start_reentrant_consume();
heter_queue<>::reentrant_consume_operation consume_1;
consume = queue.try_start_reentrant_consume();
consume_1 = std::move(consume);
assert(consume.empty() && !consume_1.empty());
consume_1.commit();
bool empty ( ) const
inlinenoexcept

Returns true whether this object does not hold the state of an operation.

heter_queue<> queue;
queue.push(42);
heter_queue<>::reentrant_consume_operation consume;
assert(consume.empty());
consume = queue.try_start_reentrant_consume();
assert(!consume.empty());
operator bool ( ) const
inlineexplicitnoexcept

Returns true whether this object does not hold the state of an operation. Same to !reentrant_consume_operation::empty.

heter_queue<> queue;
queue.push(42);
heter_queue<>::reentrant_consume_operation consume;
assert(consume.empty() == !consume);
consume = queue.try_start_reentrant_consume();
assert(consume.empty() == !consume);
heter_queue* queue ( ) const
inlinenoexcept

Returns a pointer to the target queue if a transaction is bound, otherwise returns nullptr

heter_queue<> queue;
queue.push(42);
heter_queue<>::reentrant_consume_operation consume;
assert(consume.empty() && !consume && consume.queue() == nullptr);
consume = queue.try_start_reentrant_consume();
assert(!consume.empty() && !!consume && consume.queue() == &queue);
void commit ( )
inlinenoexcept

Destroys the element, making the consume irreversible. This comnsume_operation becomes empty.

Precondition
The behavior is undefined if either:
  • this object is empty

Complexity: Constant.
Effects on iterators: no iterator is invalidated
Throws: Nothing.

void commit_nodestroy ( )
inlinenoexcept

Destroys the element, making the consume irreversible. This comnsume_operation becomes empty. The caller should destroy the element before calling this function. This object becomes empty.

Precondition
The behavior is undefined if either:
  • this object is empty

Complexity: Constant.
Effects on iterators: no iterator is invalidated
Throws: Nothing.

Note: this function may be used to combine a feature of the runtime type on the element with the destruction of the element. For example a function queue may improve the performances using a feature like invoke_destroy to do both the function call and the destruction of the capture in a single call, making a single pseudo v-call instead of two.

heter_queue<> queue;
queue.emplace<std::string>("abc");
heter_queue<>::reentrant_consume_operation consume =
queue.try_start_reentrant_consume();
consume.complete_type().destroy(consume.element_ptr());
// the string has already been destroyed. Calling commit would trigger an undefined behavior
consume.commit_nodestroy();
void cancel ( )
inlinenoexcept

Cancel the operation. This reentrant_consume_operation becomes empty.

Precondition
The behavior is undefined if either:
  • this object is empty

Complexity: Constant.
Effects on iterators: no iterator is invalidated
Throws: Nothing.

heter_queue<> queue;
queue.push(42);
heter_queue<>::reentrant_consume_operation consume =
queue.try_start_reentrant_consume();
consume.cancel();
// there is still a 42 in the queue
assert(std::distance(queue.cbegin(), queue.cend()) == 1);
const RUNTIME_TYPE& complete_type ( ) const
inlinenoexcept

Returns the type of the element being consumed.

Precondition
The behavior is undefined if this reentrant_consume_operation is empty.
heter_queue<> queue;
queue.push(42);
heter_queue<>::reentrant_consume_operation consume =
queue.try_start_reentrant_consume();
assert(consume.complete_type().is<int>());
assert(
consume.complete_type() ==
runtime_type<>::make<int>()); // same to the previous assert
consume.commit();
assert(std::distance(queue.cbegin(), queue.cend()) == 0);
void* unaligned_element_ptr ( ) const
inlinenoexcept

Returns a pointer that, if properly aligned to the alignment of the element type, points to the element. The returned address is guaranteed to be aligned to min_alignment

Precondition
The behavior is undefined if this reentrant_consume_operation is empty, that is it has been used as source for a move operation.
Postcondition
The returned address is aligned at least on heter_queue::min_alignment.
heter_queue<> queue;
queue.push(42);
heter_queue<>::reentrant_consume_operation consume =
queue.try_start_reentrant_consume();
bool const is_overaligned = alignof(int) > heter_queue<>::min_alignment;
void * const unaligned_ptr = consume.unaligned_element_ptr();
int * element_ptr;
if (is_overaligned)
{
element_ptr = static_cast<int *>(address_upper_align(unaligned_ptr, alignof(int)));
}
else
{
assert(unaligned_ptr == consume.element_ptr());
element_ptr = static_cast<int *>(unaligned_ptr);
}
assert(address_is_aligned(element_ptr, alignof(int)));
std::cout << "An int: " << *element_ptr << std::endl;
consume.commit();
void* element_ptr ( ) const
inlinenoexcept

Returns a pointer to the element being consumed.

This call is equivalent to: address_upper_align(unaligned_element_ptr(), complete_type().alignment());

Precondition
The behavior is undefined if this reentrant_consume_operation is empty, that is it has been committed or used as source for a move operation.
heter_queue<> queue;
queue.push(42);
heter_queue<>::reentrant_consume_operation consume =
queue.try_start_reentrant_consume();
++*static_cast<int *>(consume.element_ptr());
assert(consume.element<int>() == 43);
consume.commit();
COMPLETE_ELEMENT_TYPE& element ( ) const
inlinenoexcept

Returns a reference to the element being consumed.

Precondition
The behavior is undefined if this reentrant_consume_operation is empty, that is it has been committed or used as source for a move operation.
The behavior is undefined if COMPLETE_ELEMENT_TYPE is not exactly the complete type of the element.
heter_queue<> queue;
queue.push(42);
heter_queue<>::reentrant_consume_operation consume =
queue.try_start_reentrant_consume();
assert(consume.complete_type().is<int>());
std::cout << "An int: " << consume.element<int>() << std::endl;
/* std::cout << "A float: " << consume.element<float>() << std::endl; this would
trigger an undefined behavior, because the element is not a float */
consume.commit();

Friends And Related Function Documentation

void swap ( reentrant_consume_operation i_first,
reentrant_consume_operation i_second 
)
friend

Swaps two instances of reentrant_consume_operation.

heter_queue<> queue;
queue.push(42);
heter_queue<>::reentrant_consume_operation consume_1 =
queue.try_start_reentrant_consume();
heter_queue<>::reentrant_consume_operation consume_2;
{
using namespace std;
swap(consume_1, consume_2);
}
assert(consume_2.complete_type().is<int>());
assert(
consume_2.complete_type() ==
runtime_type<>::make<int>()); // same to the previous assert
assert(consume_2.element<int>() == 42);
consume_2.commit();
assert(std::distance(queue.cbegin(), queue.cend()) == 0);

The documentation for this class was generated from the following file: