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

#include <conc_heter_queue.h>

Public Member Functions

 consume_operation () noexcept=default
 
 consume_operation (const consume_operation &)=delete
 
consume_operationoperator= (const consume_operation &)=delete
 
 consume_operation (consume_operation &&i_source) noexcept=default
 
consume_operationoperator= (consume_operation &&i_source) noexcept
 
 ~consume_operation ()
 
bool empty () const noexcept
 
 operator bool () 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
 
 consume_operation (PrivateType, std::unique_lock< std::mutex > &&i_lock, typename InnerQueue::consume_operation &&i_consume_operation) noexcept
 
bool start_consume_impl (PrivateType, conc_heter_queue *i_queue)
 

Friends

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

Detailed Description

template<typename RUNTIME_TYPE = runtime_type<>, typename ALLOCATOR_TYPE = default_allocator>
class density::conc_heter_queue< RUNTIME_TYPE, ALLOCATOR_TYPE >::consume_operation

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

Consume functions on conc_heter_queue return a non-empty 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 consume_operation is empty when:

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

Constructor & Destructor Documentation

consume_operation ( )
defaultnoexcept

Constructs an empty consume_operation

conc_heter_queue<>::consume_operation consume;
assert(consume.empty());
consume_operation ( const consume_operation )
delete

Copy construction is not allowed

static_assert(
!std::is_copy_constructible<conc_heter_queue<>::consume_operation>::value, "");
consume_operation ( consume_operation &&  i_source)
defaultnoexcept

Move constructor. The source is left empty.

conc_heter_queue<> queue;
queue.push(42);
auto consume = queue.try_start_consume();
auto consume_1 = std::move(consume);
assert(consume.empty() && !consume_1.empty());
consume_1.commit();
~consume_operation ( )
inline

Destructor: cancel the operation (if any).

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

Member Function Documentation

consume_operation& operator= ( const consume_operation )
delete

Copy assignment is not allowed

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

Move assignment. The source is left empty.

conc_heter_queue<> queue;
queue.push(42);
queue.push(43);
auto consume = queue.try_start_consume();
conc_heter_queue<>::consume_operation consume_1;
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.

conc_heter_queue<> queue;
queue.push(42);
conc_heter_queue<>::consume_operation consume;
assert(consume.empty());
consume = queue.try_start_consume();
assert(!consume.empty());
operator bool ( ) const
inlineexplicitnoexcept

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

conc_heter_queue<> queue;
queue.push(42);
conc_heter_queue<>::consume_operation consume;
assert(consume.empty() == !consume);
consume = queue.try_start_consume();
assert(consume.empty() == !consume);
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.

conc_heter_queue<> queue;
queue.emplace<std::string>("abc");
conc_heter_queue<>::consume_operation consume = queue.try_start_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 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.

conc_heter_queue<> queue;
queue.push(42);
conc_heter_queue<>::consume_operation consume = queue.try_start_consume();
consume.cancel();
// there is still a 42 in the queue
assert(queue.try_start_consume().element<int>() == 42);
const RUNTIME_TYPE& complete_type ( ) const
inlinenoexcept

Returns the type of the element being consumed.

Precondition
The behavior is undefined if this consume_operation is empty.
conc_heter_queue<> queue;
queue.push(42);
conc_heter_queue<>::consume_operation consume = queue.try_start_consume();
assert(consume.complete_type().is<int>());
assert(
consume.complete_type() ==
runtime_type<>::make<int>()); // same to the previous assert
assert(consume.element<int>() == 42);
consume.commit();
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 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 conc_heter_queue::min_alignment.
conc_heter_queue<> queue;
queue.push(42);
conc_heter_queue<>::consume_operation consume = queue.try_start_consume();
bool const is_overaligned = alignof(int) > conc_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 consume_operation is empty, that is it has been committed or used as source for a move operation.
conc_heter_queue<> queue;
queue.push(42);
conc_heter_queue<>::consume_operation consume = queue.try_start_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 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.
conc_heter_queue<> queue;
queue.push(42);
conc_heter_queue<>::consume_operation consume = queue.try_start_consume();
assert(consume.complete_type().is<int>());
std::cout << "An int: " << consume.element<int>() << std::endl;
/* std::cout << "An 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 ( consume_operation i_first,
consume_operation i_second 
)
friend

Swaps two instances of consume_operation.

conc_heter_queue<> queue;
queue.push(42);
conc_heter_queue<>::consume_operation consume_1 = queue.try_start_consume();
conc_heter_queue<>::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(queue.empty());

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