RTI Connext Modern C++ API  Version 6.1.1
dds::sub::DataReader< T >::Selector Class Reference

The Selector class is used by the DataReader to compose read and take operations. More...

#include <TDataReader.hpp>

Public Member Functions

 Selector (DataReader &dr)
 Create a Selector for this DataReader. More...
 
Selectorinstance (const dds::core::InstanceHandle &h)
 Select a specific instance to read/take. More...
 
Selectornext_instance (const dds::core::InstanceHandle &previous_handle)
 Select the instance after a specific instance. More...
 
Selectorstate (const dds::sub::status::DataState &s)
 Select a specific DataState. More...
 
Selectorcontent (const dds::sub::Query &query)
 Select samples based on a Query. More...
 
Selectorcondition (const dds::sub::cond::ReadCondition &the_condition)
 Select samples based on a ReadCondition. More...
 
Selectormax_samples (int32_t n)
 Choose to only read/take up to a maximum number of samples. More...
 
dds::sub::LoanedSamples< T > read ()
 Read samples based on the state associated with this Selector. More...
 
dds::sub::LoanedSamples< T > take ()
 Take samples based on the state associated with this Selector. More...
 
template<typename SamplesFWIterator >
uint32_t read (SamplesFWIterator sfit, int32_t the_max_samples)
 Read up to max_samples samples, inserting the samples into a provided container. More...
 
template<typename SamplesFWIterator >
uint32_t take (SamplesFWIterator sfit, int32_t the_max_samples)
 Take up to max_samples samples, inserting the samples into a provided container. More...
 
template<typename SamplesBIIterator >
uint32_t read (SamplesBIIterator sbit)
 Read samples, inserting them into a provided container. More...
 
template<typename SamplesBIIterator >
uint32_t take (SamplesBIIterator sbit)
 Take samples, inserting them into a provided container. More...
 

Detailed Description

template<typename T>
class dds::sub::DataReader< T >::Selector

The Selector class is used by the DataReader to compose read and take operations.

A Selector has an associated DataReader and configures the behavior of the read or take operation performed by that DataReader.

A Selector call is typically composed of the following steps:

  1. Start with a call to reader.select() to return a Selector;
  2. Follow with one or more Selector setters configure what data to read;
  3. Finally call read() or take() to perform the operation.

The following example reads a maximum of 5 previously unread samples:

LoanedSamples<Foo> samples = reader.select()
.max_samples(5)
.read()

The selector also allows iterating over the samples one instance at a time, using the next_instance() setter.

See also
Accessing Received Data

Constructor & Destructor Documentation

◆ Selector()

template<typename T>
dds::sub::DataReader< T >::Selector::Selector ( DataReader dr)
inline

Create a Selector for this DataReader.

Selectors are created with the default filter state of the DataReader

Parameters
drThe DataReader that this Selector is attached to
See also
dds::sub::DataReader::default_filter_state()

Member Function Documentation

◆ instance()

template<typename T>
Selector& dds::sub::DataReader< T >::Selector::instance ( const dds::core::InstanceHandle h)
inline

Select a specific instance to read/take.

This operation causes the subsequent read or take operation to access only samples belonging the single specified instance whose handle is h.

Upon successful completion, the data collection will contain samples all belonging to the same instance. The corresponding SampleInfo verifies SampleInfo.instance_handle() == h.

The subsequent read/take operation will be semantically equivalent to a read or take without specifying the instance, except in building the collection, the DataReader will check that the sample belongs to the specified instance and otherwise it will not place the sample in the returned collection.

The subsequent read/take may operation may fail with dds::core::InvalidArgumentError if the InstanceHandle does not correspond to an existing data-object known to the DataReader.

Parameters
hThe handle of the instance to select

◆ next_instance()

template<typename T>
Selector& dds::sub::DataReader< T >::Selector::next_instance ( const dds::core::InstanceHandle previous_handle)
inline

Select the instance after a specific instance.

This operation causes the subsequent read or take operation to access only samples belonging a single instance whose handle is considered 'next' after the provided InstanceHandle h.

The accessed samples will all belong to the 'next' instance with InstanceHandle 'greater' than the specified previous handle that has available samples.

This operation implies the existence of a total order 'greater-than' relationship between the instance handles. The specifics of this relationship are not all important and are implementation specific. The important thing is that, according to the middleware, all instances are ordered relative to each other. This ordering is between the instance handles; It should not depend on the state of the instance (e.g. whether it has data or not) and must be defined even for instance handles that do not correspond to instances currently managed by the dds::sub::DataReader. For the purposes of the ordering, it should be 'as if' each instance handle was represented as unique integer.

The behavior of dds::sub::DataReader::Selector::next_instance is 'as if' the dds::sub::DataReader invoked dds::sub::instance(const dds::core::InstanceHandle& h), passing the smallest instance_handle among all the ones that: (a) are greater than previous_handle, and (b) have available samples (i.e. samples that meet the constraints imposed by the specified states).

The special value dds::core::InstanceHandle::nil() is guaranteed to be 'less than' any valid instance_handle. So the use of the parameter value previous_handle == dds::core::InstanceHandle::nil() will return the samples for the instance which has the smallest instance_handle among all the instances that contain available samples.

Note
The operation dds::sub::DataReader::Selector::next_instance is intended to be used in an application-driven iteration, where the application starts by passing previous_handle == dds::core::InstanceHandle::nil(), examines the samples returned, and then uses the instance_handle returned in the dds::sub::SampleInfo as the value of the previous_handle argument to the next call to dds::sub::DataReader::Selector::next_instance. The iteration continues until the read/take operation doesn't return any more samples. This application-driven iteration is required to ensure that all samples on the reader queue are read.

Note that it is possible to call the dds::sub::DataReader::Selector::next_instance operation with a previous_handle that does not correspond to an instance currently managed by the dds::sub::DataReader. This is because as stated earlier the 'greater-than' relationship is defined even for handles not managed by the dds::sub::DataReader. One practical situation where this may occur is when an application is iterating though all the instances, takes all the samples of a dds::sub::status::InstanceState::not_alive_no_writers() instance, returns the loan (at which point the instance information may be removed, and thus the handle becomes invalid), and tries to read the next instance.

Parameters
previous_handleThe 'next smallest' instance with a value greater than this value that has available samples will be returned.
See also
Selecting what samples to read for an example

◆ state()

template<typename T>
Selector& dds::sub::DataReader< T >::Selector::state ( const dds::sub::status::DataState s)
inline

Select a specific DataState.

By setting the DataState, you can specify the state of the samples that should be read or taken. The DataState of a sample encapsulates the SampleState, ViewState, and InstanceState of a sample. For example:

using namespace dds::sub::status;
LoanedSamples<Foo> samples = reader.select()
.state(DataState(SampleState::not_read(), ViewState::new_view(), InstanceState::alive())
.read();

If you're only interested in the SampleState, the ViewState, or the InstanceState, you can pass it directly. For example, to read alive instances with any SampleState or ViewState:

LoanedSamples<Foo> samples = reader.select()
.state(InstanceState::alive())
.read();

If this method comes before a call to condition(), then it will be overridden and will not have any effect on the read or take operation.

Parameters
sThe selected DataState

◆ content()

template<typename T>
Selector& dds::sub::DataReader< T >::Selector::content ( const dds::sub::Query query)
inline

Select samples based on a Query.

The effect of using this manipulator is that the subsequent read/take will filter the samples based on the Query's expression. If the DataReader has no samples that meet the constraints, the read/take will not return any data.

If this method is called before a call to condition then it will be overridden and will not have any effect on the read or take operation. Similarly, if this operation follows a call to condition(), then the previously set ReadCondition will be cleared.

Parameters
queryThe Query to read/take with

◆ condition()

template<typename T>
Selector& dds::sub::DataReader< T >::Selector::condition ( const dds::sub::cond::ReadCondition the_condition)
inline

Select samples based on a ReadCondition.

When passing a QueryCondition, the effect of calling this method is that the subsequent read/take will filter the samples based on the QueryConditions's expression and state. If the DataReader has no samples that meet the constraints, the read/take will not return any data.

Passing an actual ReadCondition will only filter based on the state.

If this method is called before a call to content then it will be overridden and will not have any effect on the read or take operation. Similarly, if this operation follows a call to content() and/or state, then the previously set Query and DataState will be cleared.

This method is effectively a combination of calling content and state, but a QueryCondition is more efficient when reading with the same query multiple times.

For example:

samples = reader.select()
.read()
.content(dds::sub::Query(system.reader, "foo = 7"))

is equivalent to:

samples = reader.select()
.read()
.condition(QueryCondition(Query(system.reader, "foo = 7"), DataState::new_data()))
Parameters
the_conditionThe ReadCondition (or QueryCondition) to read/take with

◆ max_samples()

template<typename T>
Selector& dds::sub::DataReader< T >::Selector::max_samples ( int32_t  n)
inline

Choose to only read/take up to a maximum number of samples.

Parameters
nThe maximum number of samples to read/take

◆ read() [1/3]

template<typename T>
dds::sub::LoanedSamples<T> dds::sub::DataReader< T >::Selector::read ( )
inline

Read samples based on the state associated with this Selector.

Returns
dds::sub::LoanedSamples<T>

◆ take() [1/3]

template<typename T>
dds::sub::LoanedSamples<T> dds::sub::DataReader< T >::Selector::take ( )
inline

Take samples based on the state associated with this Selector.

Returns
dds::sub::LoanedSamples<T>

◆ read() [2/3]

template<typename T>
template<typename SamplesFWIterator >
uint32_t dds::sub::DataReader< T >::Selector::read ( SamplesFWIterator  sfit,
int32_t  the_max_samples 
)
inline

Read up to max_samples samples, inserting the samples into a provided container.

Template Parameters
SamplesFWIteratorA forward iterator whose value type is dds::sub::Sample<T>
Parameters
sfitA forward iterator pointing to the position in a container in which to put the read samples
the_max_samplesThe maximum number of samples to read
Returns
uint32_t The number of read samples

◆ take() [2/3]

template<typename T>
template<typename SamplesFWIterator >
uint32_t dds::sub::DataReader< T >::Selector::take ( SamplesFWIterator  sfit,
int32_t  the_max_samples 
)
inline

Take up to max_samples samples, inserting the samples into a provided container.

Template Parameters
SamplesFWIteratorA forward iterator whose value type is dds::sub::Sample<T>
Parameters
sfitA forward iterator pointing to the position in a container in which to put the taken samples
the_max_samplesThe maximum number of samples to take
Returns
uint32_t The number of taken samples

◆ read() [3/3]

template<typename T>
template<typename SamplesBIIterator >
uint32_t dds::sub::DataReader< T >::Selector::read ( SamplesBIIterator  sbit)
inline

Read samples, inserting them into a provided container.

Template Parameters
SamplesBIIteratorA back-inserting iterator whose value type is dds::sub::Sample<T>
Parameters
sbitA back-inserting iterator placed at the position in the destination container where the read samples should be placed
Returns
uint32_t The number of samples that were read

◆ take() [3/3]

template<typename T>
template<typename SamplesBIIterator >
uint32_t dds::sub::DataReader< T >::Selector::take ( SamplesBIIterator  sbit)
inline

Take samples, inserting them into a provided container.

Template Parameters
SamplesBIIteratorA back-inserting iterator whose value type is dds::sub::Sample<T>
Parameters
sbitA back-inserting iterator placed at the position in the destination container where the taken samples should be placed
Returns
uint32_t The number of samples that were taken