Go2Py_SIM/cpp_bridge/thirdparty/include/ddscxx/dds/sub/TDataReader.hpp

1690 lines
78 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef OMG_DDS_SUB_TDATA_READER_HPP_
#define OMG_DDS_SUB_TDATA_READER_HPP_
/* Copyright 2010, Object Management Group, Inc.
* Copyright 2010, PrismTech, Corp.
* Copyright 2010, Real-Time Innovations, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <dds/core/detail/conformance.hpp>
#include <dds/sub/AnyDataReader.hpp>
#include <dds/topic/ContentFilteredTopic.hpp>
#include <dds/topic/TopicInstance.hpp>
#include <dds/sub/LoanedSamples.hpp>
#include <dds/sub/Subscriber.hpp>
namespace dds
{
namespace sub
{
template <typename T, template <typename Q> class DELEGATE>
class DataReader;
template <typename T>
class DataReaderListener;
}
}
/**
* @brief
* DataReader allows the applicatin to access published sample data.
*
* A DataReader allows the application:
* - to declare the data it wishes to receive (i.e., make a subscription)
* - to access the data received by the attached Subscriber
*
* A DataReader refers to exactly one TopicDescription (either a Topic, a
* ContentFilteredTopic or a MultiTopic) that identifies the samples to be
* read. The Topic must exist prior to the DataReader creation.
*
* A DataReader is attached to exactly one Subscriber which acts as a factory
* for it.
*
* The DataReader may give access to several instances of the data type, which
* are distinguished from each other by their key.
*
* The pre-processor generates from IDL type descriptions the application
* DataReader<type> classes. For each application data type that is used as Topic
* data type, a typed class DataReader<type> is derived from the AnyDataReader
* class.
*
* For instance, for an application, the definitions are located in the Foo.idl file.
* The pre-processor will generate a ccpp_Foo.h include file.
*
* <b>General note:</b> The name ccpp_Foo.h is derived from the IDL file Foo.idl,
* that defines Foo::Bar, for all relevant DataReader<Foo::Bar> operations.
*
* @note Apart from idl files, Google protocol buffers are also supported. For the
* API itself, it doesn't matter if the type header files were generated from
* idl or protocol buffers. The resulting API usage and includes remain the same.
*
* @anchor anchor_dds_sub_datareader_example
* <b>Example</b>
* @code{.cpp}
* // Default creation of a DataReader
* dds::domain::DomainParticipant participant(org::eclipse::cyclonedds::domain::default_id());
* dds::topic::Topic<Foo::Bar> topic(participant, "TopicName");
* dds::sub::Subscriber subscriber(participant);
* dds::sub::DataReader<Foo::Bar> reader(subscriber, topic);
*
* {
* // Default read of a sample on the DataReader
* dds::sub::LoanedSamples<Foo::Bar> samples;
* samples = reader.read();
*
* // Default way of accessing the loaned samples
* dds::sub::LoanedSamples<Foo::Bar>::const_iterator it;
* for (it = samples.begin(); it != samples.end(); ++it) {
* const dds::sub::Sample<Foo::Bar>& sample = *it;
* const Foo::Bar& data = sample.data();
* const dds::sub::SampleInfo& info = sample.info();
* // Use sample data and meta information.
* }
* }
* // Like the name says, the read samples are loans from the DataReader. The loan
* // was automatically returned when the LoanedSamples went out of scope.
* @endcode
*
* @see for more information: @ref DCPS_Modules_Subscription "Subscription concept"
* @see for more information: @ref DCPS_Modules_Subscription_DataReader "DataReader concept"
*/
template <typename T, template <typename Q> class DELEGATE>
class dds::sub::DataReader : public dds::sub::TAnyDataReader< DELEGATE<T> >
{
public:
/**
* Local convenience typedef for dds::sub::DataReaderListener.
*/
typedef ::dds::sub::DataReaderListener<T> Listener;
public:
/**
* The Selector class is used by the DataReader to compose read operations.
*
* A Selector can perform complex data selections, such as per-instance selection,
* content and status filtering, etc, when reading or taking samples. These settings
* on a Selector can be concatenated.
*
* The DataReader has the select() operation, which can be used to aqcuire the Selector
* functionality on the reader implicitly.
* @code{.cpp}
* // Take a maximum of 3 new samples of a certain instance.
* samples = reader.select()
* .max_samples(3)
* .state(dds::sub::status::DataState::new_data())
* .instance(someValidInstanceHandle)
* .take();
* @endcode
* However, this will create and destroy a Selector for every read, which is not
* very performance friendly.
*
* The performance can be increase by creating a Selector up front and doing the
* reading on that Selector directly and re-using it.
* @code{.cpp}
* // Create a Selector as selective reader up front.
* dds::sub::DataReader<Foo::Bar>::Selector selectiveReader(reader);
* // Configure it to take a maximum of 3 new samples of a certain instance
* selectiveReader.max_samples(3);
* selectiveReader.state(dds::sub::status::DataState::new_data());
* selectiveReader.instance(someValidInstanceHandle);
*
* // Use the configured Selector to -take- a maximum of 3 new samples of a
* // certain instance (which it was configured to do).
* // This can be used in loops for example, reducing the need for creating
* // implicit Selectors for every take.
* samples = selectiveReader.take();
* @endcode
*
* <i>Defaults</i>
* Element | Default Value
* --------------- | --------------------
* state | dds::sub::status::DataState::any
* content | Empty dds::sub::Query
* max_samples | dds::core::LENGTH_UNLIMITED
* instance | dds::core::InstanceHandle nil
*
* @see for more information: @link dds::sub::DataReader::select() DataReader select() @endlink
*/
class Selector
{
public:
/**
* Construct a Selector for a DataReader.
*
* @param dr DataReader
*/
Selector(DataReader& dr);
/**
* Set InstanceHandle to filter with during the read or take.
*
* <i>Example</i><br>
* Read only samples of the given instance.
* @code{.cpp}
* dds::core::InstanceHandle hdl = someValidInstanceHandle;
*
* // Implicit use of Selector
* samples = reader.select().instance(hdl).read();
*
* // Explicit use of Selector
* dds::sub::DataReader<Foo::Bar>::Selector selectiveReader(reader);
* selectiveReader.instance(hdl);
* samples = selectiveReader.read();
* @endcode
* See also @link dds::sub::DataReader::select() DataReader select() @endlink operation.
*
* @param handle the InstanceHandle to read/take for
* @return a Selector to be able to concatenate Selector settings.
*/
Selector& instance(const dds::core::InstanceHandle& handle);
/**
* Set next InstanceHandle to filter with during the read or take.
*
* <i>Example</i><br>
* Read all samples, instance by instance.
* @code{.cpp}
* // Implicit use of Selector
* {
* // Get sample(s) of first instance
* dds::core::InstanceHandle hdl; //nil
* samples = reader.select().next_instance(hdl).read();
* while (samples.length() > 0) {
* // Handle the sample(s) of this instance (just the first one in this case)
* const dds::sub::Sample<Foo::Bar>& sample = *(samples.begin());
* // Get sample(s) of the next instance
* hdl = sample.info().instance_handle();
* samples = reader.select().next_instance(hdl).read();
* }
* }
*
* // Explicit use of Selector
* {
* // Get sample(s) of first instance
* dds::sub::DataReader<Foo::Bar>::Selector selectiveReader(reader);
* dds::core::InstanceHandle hdl; //nil
* selectiveReader.next_instance(hdl);
* samples = selectiveReader.read();
* while (samples.length() > 0) {
* // Handle the sample(s) of this instance (just the first one in this case)
* const dds::sub::Sample<Foo::Bar>& sample = *(samples.begin());
* // Get sample(s) of the next instance
* hdl = sample.info().instance_handle();
* selectiveReader.next_instance(hdl);
* samples = selectiveReader.read();
* }
* }
* @endcode
* See also @link dds::sub::DataReader::select() DataReader select() @endlink operation.
*
* @param handle the 'previous' InstanceHandle associated with new the read/take
* @return a Selector to be able to concatenate Selector settings.
*/
Selector& next_instance(const dds::core::InstanceHandle& handle);
/**
* Set DataState to filter with during the read or take.
*
* <i>Example</i><br>
* Read only new data.
* @code{.cpp}
* // DataState to filter only new data
* dds::sub::status::DataState newData = dds::sub::status::DataState::new_data();
*
* // Implicit use of Selector
* samples = reader.select().state(newData).read();
*
* // Explicit use of Selector
* dds::sub::DataReader<Foo::Bar>::Selector selectiveReader(reader);
* selectiveReader.state(newData);
* samples = selectiveReader.read();
* @endcode
* See also @link dds::sub::DataReader::select() DataReader select() @endlink operation.
*
* @param state the requested DataState of the samples
* @return a Selector to be able to concatenate Selector settings.
*/
Selector& state(const dds::sub::status::DataState& state);
/**
* Set the Query to filter with during the read or take.
*
* <i>Example</i><br>
* Read only samples that will be filtered according to the given dds::sub::Query.
* @code{.cpp}
* // Assume data type has an element called long_1
* dds::sub::Query query(reader, "long_1 > 1 and long_1 < 7");
*
* // Implicit use of Selector
* samples = reader.select().content(query).read();
*
* // Explicit use of Selector
* dds::sub::DataReader<Foo::Bar>::Selector selectiveReader(reader);
* selectiveReader.content(query);
* samples = selectiveReader.read();
* @endcode
* See also @link dds::sub::DataReader::select() DataReader select() @endlink operation.
*
* @param query the Query to apply to the selector
* @return a Selector to be able to concatenate Selector settings.
*/
Selector& content(const dds::sub::Query& query);
/**
* Set max_samples to limit the number of sample to get during the read or take.
*
* <i>Example</i><br>
* Read a maximum of three samples.
* @code{.cpp}
* // Implicit use of Selector
* samples = reader.select().max_samples(3).read();
*
* // Explicit use of Selector
* dds::sub::DataReader<Foo::Bar>::Selector selectiveReader(reader);
* selectiveReader.max_samples(3);
* samples = selectiveReader.read();
* @endcode
* See also @link dds::sub::DataReader::select() DataReader select() @endlink operation.
*
* @param maxsamples maximum number of samples to read/take
* @return a Selector to be able to concatenate Selector settings.
*/
Selector& max_samples(uint32_t maxsamples);
/**
* This operation works the same as the @link DataReader::read() default
* DataReader read() @endlink, except that it is performed on this Selector
* with possible filters set.
*
* @return The samples in the LoanedSamples container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
dds::sub::LoanedSamples<T> read();
/**
* This operation works the same as the @link DataReader::take() default
* DataReader take() @endlink, except that it is performed on this Selector
* with possible filters set.
*
* @return The samples in the LoanedSamples container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
dds::sub::LoanedSamples<T> take();
// --- Forward Iterators: --- //
/**
* This operation works the same as the @link DataReader::read(SamplesFWIterator sfit, uint32_t max_samples)
* forward iterator DataReader read() @endlink, except that it is performed on this
* Selector with possible filters set.
*
* @param sfit Forward-inserting container iterator
* @param max_samples Maximum samples to read and copy into the given container
* @return The number of samples in the LoanedSamples container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
template <typename SamplesFWIterator>
uint32_t
read(SamplesFWIterator sfit, uint32_t max_samples);
/**
* This operation works the same as the @link DataReader::take(SamplesFWIterator sfit, uint32_t max_samples)
* forward iterator DataReader take() @endlink, except that it is performed on this
* Selector with possible filters set.
*
* @param sfit Forward-inserting container iterator
* @param max_samples Maximum samples to read and copy into the given container
* @return The number of samples in the given container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
template <typename SamplesFWIterator>
uint32_t
take(SamplesFWIterator sfit, uint32_t max_samples);
// --- Back-Inserting Iterators: --- //
/**
* This operation works the same as the @link DataReader::read(SamplesBIIterator sbit)
* backward iterator DataReader read() @endlink, except that it is performed on this
* Selector with possible filters set.
*
* @param sbit Back-inserting container iterator
* @return The number of samples in the given container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
template <typename SamplesBIIterator>
uint32_t
read(SamplesBIIterator sbit);
/**
* This operation works the same as the @link DataReader::take(SamplesBIIterator sbit)
* backward iterator DataReader take() @endlink, except that it is performed on this
* Selector with possible filters set.
*
* @param sbit Back-inserting container iterator
* @return The number of samples in the given container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
template <typename SamplesBIIterator>
uint32_t
take(SamplesBIIterator sbit);
private:
typename DELEGATE<T>::Selector impl_;
};
/**
* The ManipulatorSelector class is used by the DataReader to compose streaming
* read operations.
*
* A ManipulatorSelector can perform complex data selections, such as per-instance
* selection, content and status filtering, etc, when reading or taking samples
* through the streaming operator.
*
* <i>Convenience functors</i><br>
* The following convenience functors use a ManipulatorSelector implicitly and can be
* used in the streaming operator:
* - dds::sub::read
* - dds::sub::take
* - dds::sub::max_samples
* - dds::sub::content
* - dds::sub::state
* - dds::sub::instance
* - dds::sub::next_instance
*
* @code{.cpp}
* // Take a maximum of 3 new samples of a certain instance.
* reader >> dds::sub::take
* >> dds::sub::max_samples(3)
* >> dds::sub::state(dds::sub::status::DataState::new_data())
* >> dds::sub::instance(someValidInstanceHandle)
* >> samples;
* @endcode
* However, this will create and destroy ManipulatorSelectors and Functors for
* every read, which is not very performance friendly.
*
* The performance can be increase by creating a ManipulatorSelector up front and
* doing the reading on that ManipulatorSelector directly and re-using it.
* @code{.cpp}
* // Create a ManipulatorSelector as selective reader up front.
* dds::sub::DataReader<Foo::Bar>::ManipulatorSelector selectiveReader(reader);
* // Configure it to take a maximum of 3 new samples of a certain instance
* selectiveReader.max_samples(3);
* selectiveReader.state(dds::sub::status::DataState::new_data());
* selectiveReader.instance(someValidInstanceHandle);
* selectiveReader.read_mode(false); // take
*
* // Use the configured ManipulatorSelector to -take- a maximum of 3 samples of a
* // certain instance (which it was configured to do).
* // This can be used in loops for example, reducing the need for creating
* // implicit ManipulatorSelectors for every take.
* selectiveReader >> samples;
* @endcode
*
* <i>Defaults</i>
* Element | Default Value
* --------------- | --------------------
* read_mode | true (read)
* state | dds::sub::status::DataState::any
* content | Empty dds::sub::Query
* max_samples | dds::core::LENGTH_UNLIMITED
* instance | dds::core::InstanceHandle nil
*
* @see for more information: @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls) DataReader stream operator>> @endlink
*/
class ManipulatorSelector
{
public:
/**
* Construct a ManipulatorSelector for a DataReader.
*
* See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls)
* DataReader stream operator>> @endlink
*
* @param DataReader
*/
ManipulatorSelector(DataReader& dr);
/**
* Get the read_mode.
*
* The read_mode specifies if a sample should be read or taken:
* - true = read (default)
* - false = take
*
* @return true if read_mode is set to read
*/
bool read_mode();
/**
* Set the read_mode.
*
* The read_mode specifies if a sample should be read or taken:
* - true = read (default)
* - false = take
*
* <i>Convenience Functor:</i> dds::sub::read<br>
* <i>Convenience Functor:</i> dds::sub::take
*
* <i>Example</i><br>
* Determine to read or take samples.
* @code{.cpp}
* // No usage of ManipulatorSelector, means a read iso take as default.
* reader >> samples;
*
* // Implicit use of ManipulatorSelector
* reader >> dds::sub::read >> samples;
* reader >> dds::sub::take >> samples;
*
* // Explicit use of ManipulatorSelector
* dds::sub::DataReader<Foo::Bar>::ManipulatorSelector readingReader(reader);
* readingReader.read_mode(true); // Read, which is already the default.
* readingReader >> samples;
*
* dds::sub::DataReader<Foo::Bar>::ManipulatorSelector takingReader(reader);
* takingReader.read_mode(false); // Take.
* takingReader >> samples;
* @endcode
* See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls)
* DataReader stream operator>> @endlink
*
* @param readmode the read mode of the DataReader
*/
void read_mode(bool readmode);
/**
* Set max_samples to limit the number of sample to get during the read or take.
*
* <i>Convenience Functor:</i> dds::sub::max_samples
*
* <i>Example</i><br>
* Read a maximum of three samples.
* @code{.cpp}
* // Implicit use of ManipulatorSelector
* reader >> dds::sub::max_samples(3) >> samples;
*
* // Explicit use of ManipulatorSelector
* dds::sub::DataReader<Foo::Bar>::ManipulatorSelector selectiveReader(reader);
* selectiveReader.max_samples(3);
* selectiveReader >> samples;
* @endcode
* See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls)
* DataReader stream operator>> @endlink
*
* @param n maximum number of samples
*/
ManipulatorSelector& max_samples(uint32_t n);
/**
* Set InstanceHandle to filter with during the read or take.
*
* <i>Convenience Functor:</i> dds::sub::instance
*
* <i>Example</i><br>
* Read only samples of the given instance.
* @code{.cpp}
* dds::core::InstanceHandle hdl = someValidInstanceHandle;
*
* // Implicit use of ManipulatorSelector
* reader >> dds::sub::instance(hdl) >> samples;
*
* // Explicit use of ManipulatorSelector
* dds::sub::DataReader<Foo::Bar>::ManipulatorSelector selectiveReader(reader);
* selectiveReader.instance(hdl);
* selectiveReader >> samples;
* @endcode
* See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls)
* DataReader stream operator>> @endlink
*
* @param handle the InstanceHandle for the read/take
*/
ManipulatorSelector& instance(const dds::core::InstanceHandle& handle);
/**
* Set next InstanceHandle to filter with during the read or take.
*
* <i>Convenience Functor:</i> dds::sub::next_instance
*
* <i>Example</i><br>
* Read all samples, instance by instance.
* @code{.cpp}
* // Implicit use of ManipulatorSelector
* {
* // Get sample(s) of first instance
* dds::core::InstanceHandle hdl; //nil
* reader >> dds::sub::next_instance(hdl) >> samples;
* while (samples.length() > 0) {
* // Handle the sample(s) of this instance (just the first one in this case)
* const dds::sub::Sample<Foo::Bar>& sample = *(samples.begin());
* // Get sample(s) of the next instance
* hdl = sample.info().instance_handle();
* reader >> dds::sub::next_instance(hdl) >> samples;
* }
* }
*
* // Explicit use of ManipulatorSelector
* {
* // Get sample(s) of first instance
* dds::sub::DataReader<Foo::Bar>::ManipulatorSelector selectiveReader(reader);
* dds::core::InstanceHandle hdl; //nil
* selectiveReader.next_instance(hdl);
* selectiveReader >> samples;
* while (samples.length() > 0) {
* // Handle the sample(s) of this instance (just the first one in this case)
* const dds::sub::Sample<Foo::Bar>& sample = *(samples.begin());
* // Get sample(s) of the next instance
* hdl = sample.info().instance_handle();
* selectiveReader.next_instance(hdl);
* selectiveReader >> samples;
* }
* }
* @endcode
* See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls)
* DataReader stream operator>> @endlink
*
* @param handle the 'previous' InstanceHandle associated with new the read/take
*/
ManipulatorSelector& next_instance(const dds::core::InstanceHandle& handle);
/**
* Set DataState to filter with during the read or take.
*
* <i>Convenience Functor:</i> dds::sub::state
*
* <i>Example</i><br>
* Read only new data.
* @code{.cpp}
* // DataState to filter only new data
* dds::sub::status::DataState newData = dds::sub::status::DataState::new_data();
*
* // Implicit use of ManipulatorSelector
* reader >> dds::sub::state(newData) >> samples;
*
* // Explicit use of ManipulatorSelector
* dds::sub::DataReader<Foo::Bar>::ManipulatorSelector selectiveReader(reader);
* selectiveReader.state(newData);
* selectiveReader.read() >> samples;
* @endcode
* See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls)
* DataReader stream operator>> @endlink
*
* @param state the required DataState of the samples
*/
ManipulatorSelector& state(const dds::sub::status::DataState& state);
/**
* Set Query to filter with during the read or take.
*
* <i>Convenience Functor:</i> dds::sub::content
*
* <i>Example</i><br>
* Read only samples that will be filtered according to the given dds::sub::Query.
* @code{.cpp}
* // Assume data type has an element called long_1
* dds::sub::Query query(reader, "long_1 > 1 and long_1 < 7");
*
* // Implicit use of ManipulatorSelector
* reader >> dds::sub::content(query) >> samples;
*
* // Explicit use of ManipulatorSelector
* dds::sub::DataReader<Foo::Bar>::ManipulatorSelector selectiveReader(reader);
* selectiveReader.content(query);
* selectiveReader >> read;
* @endcode
* See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls)
* DataReader stream operator>> @endlink
*
* @param query The Query to apply to a read/take
*/
ManipulatorSelector& content(const dds::sub::Query& query);
/**
* This operation works the same as the @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls)
* DataReader stream operator>> @endlink, except that it is performed on this ManipulatorSelector
* with possible filters set.
*
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
ManipulatorSelector&
operator >>(dds::sub::LoanedSamples<T>& samples);
/**
* This operation works the same as the @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls)
* DataReader stream operator>> @endlink, except that it is performed on this ManipulatorSelector
* with possible filters set.
*
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
ManipulatorSelector&
operator >> (ManipulatorSelector & (manipulator)(ManipulatorSelector&));
/**
* This operation works the same as the @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls)
* DataReader stream operator>> @endlink, except that it is performed on this ManipulatorSelector
* with possible filters set.
*
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
template <typename Functor>
ManipulatorSelector
operator >> (Functor f);
private:
typename DELEGATE<T>::ManipulatorSelector impl_;
};
public:
OMG_DDS_REF_TYPE_PROTECTED_DC_T(DataReader, dds::sub::TAnyDataReader, T, DELEGATE)
OMG_DDS_IMPLICIT_REF_BASE(DataReader)
OMG_DDS_COMPLETE_RULE_OF_FIVE_VIRTUAL_DEFAULT(DataReader)
public:
/**
* Create a new DataReader for the desired Topic, ContentFilteredTopic or MultiTopic,
* using the given Subscriber.
*
* <i>QoS</i><br>
* The DataReader will be created with the QoS values specified on the last
* successful call to @link dds::sub::Subscriber::default_datareader_qos(const dds::sub::qos::DataReaderQos& qos)
* sub.default_datareader_qos(qos) @endlink or, if the call was never made,
* the @ref anchor_dds_sub_datareader_qos_defaults "default" values.
*
* @param sub the Subscriber that will contain this DataReader
* @param topic the Topic associated with this DataReader
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
*/
DataReader(const dds::sub::Subscriber& sub,
const ::dds::topic::Topic<T>& topic);
/**
* Create a new DataReader for the desired Topic, ContentFilteredTopic or MultiTopic,
* using the given Subscriber and DataReaderQos and attaches the optionally specified
* DataReaderListener to it.
*
* <i>QoS</i><br>
* A possible application pattern to construct the DataReaderQos for the
* DataReader is to:
* @code{.cpp}
* // 1) Retrieve the QosPolicy settings on the associated Topic
* dds::topic::qos::TopicQos topicQos = topic.qos();
* // 2) Retrieve the default DataReaderQos from the related Subscriber
* dds::sub::qos::DataReaderQos readerQos = subscriber.default_datareader_qos();
* // 3) Combine those two lists of QosPolicy settings by overwriting DataReaderQos
* // policies that are also present TopicQos
* readerQos = topicQos;
* // 4) Selectively modify QosPolicy settings as desired.
* readerQos << dds::core::policy::Durability::Transient();
* // 5) Use the resulting QoS to construct the DataReader.
* dds::sub::DataReader<Foo::Bar> reader(subscriber, topic, readerQos);
* @endcode
*
* <i>Listener</i><br>
* The following statuses are applicable to the DataReaderListener:
* - dds::core::status::StatusMask::requested_deadline_missed()
* - dds::core::status::StatusMask::requested_incompatible_qos()
* - dds::core::status::StatusMask::sample_lost()
* - dds::core::status::StatusMask::sample_rejected()
* - dds::core::status::StatusMask::data_available()
* - dds::core::status::StatusMask::liveliness_changed()
* - dds::core::status::StatusMask::subscription_matched()
*
* See @ref DCPS_Modules_Infrastructure_Listener "listener concept",
* @ref anchor_dds_sub_datareader_commstatus "communication status" and
* @ref anchor_dds_sub_datareader_commpropagation "communication propagation"
* for more information.
*
* @param sub the Subscriber that will contain this DataReader
* @param topic the Topic, ContentFilteredTopic or MultiTopic associated with this DataReader
* @param qos the DataReader qos.
* @param listener the DataReader listener.
* @param mask the listener event mask.
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::InconsistentPolicyError
* The parameter qos contains conflicting QosPolicy settings.
*/
DataReader(const dds::sub::Subscriber& sub,
const ::dds::topic::Topic<T>& topic,
const dds::sub::qos::DataReaderQos& qos,
dds::sub::DataReaderListener<T>* listener = NULL,
const dds::core::status::StatusMask& mask = ::dds::core::status::StatusMask::none());
#ifdef OMG_DDS_CONTENT_SUBSCRIPTION_SUPPORT
/** @copydoc dds::sub::DataReader::DataReader(const dds::sub::Subscriber& sub, const ::dds::topic::Topic<T>& topic) */
DataReader(const dds::sub::Subscriber& sub,
const ::dds::topic::ContentFilteredTopic<T>& topic);
/** @copydoc dds::sub::DataReader::DataReader(const dds::sub::Subscriber& sub, const ::dds::topic::Topic<T>& topic, const dds::sub::qos::DataReaderQos& qos, dds::sub::DataReaderListener<T>* listener, const dds::core::status::StatusMask& mask) */
DataReader(const dds::sub::Subscriber& sub,
const ::dds::topic::ContentFilteredTopic<T>& topic,
const dds::sub::qos::DataReaderQos& qos,
dds::sub::DataReaderListener<T>* listener = NULL,
const dds::core::status::StatusMask& mask = ::dds::core::status::StatusMask::none());
#endif /* OMG_DDS_CONTENT_SUBSCRIPTION_SUPPORT */
#ifdef OMG_DDS_MULTI_TOPIC_SUPPORT
/** @copydoc dds::sub::DataReader::DataReader(const dds::sub::Subscriber& sub, const ::dds::topic::Topic<T>& topic) */
DataReader(const dds::sub::Subscriber& sub,
const ::dds::topic::MultiTopic<T>& topic);
/** @copydoc dds::sub::DataReader::DataReader(const dds::sub::Subscriber& sub, const ::dds::topic::Topic<T>& topic, const dds::sub::qos::DataReaderQos& qos, dds::sub::DataReaderListener<T>* listener, const dds::core::status::StatusMask& mask) */
DataReader(const dds::sub::Subscriber& sub,
const ::dds::topic::MultiTopic<T>& topic,
const dds::sub::qos::DataReaderQos& qos,
dds::sub::DataReaderListener<T>* listener = NULL,
const dds::core::status::StatusMask& mask = ::dds::core::status::StatusMask::none());
#endif /* OMG_DDS_MULTI_TOPIC_SUPPORT */
public:
// == ReadState Management
/**
* Returns the @ref anchor_dds_sub_datareader_defaultstatefilter "default state filter"
* for read/take operations.
*
* The default value of default_filter_state is dds::sub::status::DataState::any().
*
* @return the default state to filter for
*/
dds::sub::status::DataState default_filter_state();
/**
* Set the default state filter for read/take operations.
*
* @anchor anchor_dds_sub_datareader_defaultstatefilter
* <i>Default State Filter</i><br>
* The default_filter_state indicates what the dds::sub::status::DataState of samples
* should be for the read to filter them out of the total data samples pool.
*
* This filter can be overruled by using dds::sub::DataReader::Selector::state or
* dds::sub::DataReader::ManipulatorSelector::state during the actual read action.
*
* @param state the state mask that will be used to read/take samples
*/
DataReader& default_filter_state(const dds::sub::status::DataState& state);
//== Streaming read/take
/**
* This operation reads a sequence of typed samples from the DataReader by means
* of the shift operator.
*
* What samples are read depends on what @link dds::sub::DataReader::default_filter_state(const dds::sub::status::DataState& state)
* default state filter @endlink has been set (default any).
*
* This operation reads a sequence of typed samples from the DataReader<type>. The
* data is put into a dds::sub::LoanedSamples, which is basically a sequence of samples,
* which in turn contains the actual data and meta information.
*
* The memory used for storing the sample may be loaned by the middleware thus allowing zero
* copy operations.
*
* If the DataReader has no samples that meet the constraints, the resulting
* dds::sub::LoanedSamples will be empty.
* @code{.cpp}
* dds::domain::DomainParticipant participant(org::eclipse::cyclonedds::domain::default_id());
* dds::topic::Topic<Foo::Bar> topic(participant, "TopicName");
* dds::sub::Subscriber subscriber(participant);
* dds::sub::DataReader<Foo::Bar> reader(subscriber, topic);
*
* {
* dds::sub::LoanedSamples<Foo::Bar> samples;
* reader >> samples;
* }
* // The LoanedSamples went out of scope, meaning the loan was returned.
* @endcode
*
* <b><i>Take</i></b><br>
* The default behaviour of the DataReader stream operator>> is to read samples. It can be
* explicitly stated if the operator should do a read or take.
* @code{.cpp}
* reader >> dds::sub::read >> samples;
* reader >> dds::sub::take >> samples;
* @endcode
* These are two of the available convenience manipulators (see next paragraph).
*
* <b><i>Manipulators</i></b><br>
* Manipulators are defined externally to make it possible to control which data is read
* and whether the streaming operators reads or takes.
*
* Available convenience stream manipulators:
* - dds::sub::read
* - dds::sub::take
* - dds::sub::max_samples
* - dds::sub::content
* - dds::sub::state
* - dds::sub::instance
* - dds::sub::next_instance
*
* The manipulators can be concatenated:
* @code{.cpp}
* // Take (iso read) a maximum of 3 new samples of a certain instance.
* reader >> dds::sub::take
* >> dds::sub::max_samples(3)
* >> dds::sub::state(dds::sub::status::DataState::new_data())
* >> dds::sub::instance(someValidInstanceHandle)
* >> samples;
* @endcode
*
* <i>Please be aware that using pre-set filters on the DataReader and then
* call read() or take() on that reader explicitly will perform better than
* having to create Manipulators for every read (which is what essentially
* happens in the code example above). Performance can be increase by creating
* a manipulator up front and using that multiple times
* (see dds::sub::DataReader::ManipulatorSelector).</i>
*
* <b><i>Invalid Data</i></b><br>
* Some elements in the returned sequence may not have valid data: the valid_data
* field in the SampleInfo indicates whether the corresponding data value contains
* any meaningful data. If not, the data value is just a dummy sample for which only
* the keyfields have been assigned. It is used to accompany the SampleInfo that
* communicates a change in the instance_state of an instance for which there is
* no real sample available.
*
* For example, when an application always takes all available samples of a
* particular instance, there is no sample available to report the disposal of that
* instance. In such a case the DataReader will insert a dummy sample into the
* data_values sequence to accompany the SampleInfo element in the info_seq
* sequence that communicates the disposal of the instance.
*
* The act of reading a sample sets its sample_state to READ_SAMPLE_STATE. If
* the sample belongs to the most recent generation of the instance, it also sets the
* view_state of the instance to NOT_NEW_VIEW_STATE. It does not affect the
* instance_state of the instance.
*
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
DataReader& operator>>(dds::sub::LoanedSamples<T>& ls);
/** @copydoc dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls) */
ManipulatorSelector
operator>> (ManipulatorSelector & (manipulator)(ManipulatorSelector&));
/** @copydoc dds::sub::DataReader::operator>>(dds::sub::LoanedSamples<T>& ls) */
template <typename Functor>
ManipulatorSelector
operator>> (Functor f);
///////////////////////////////////////////////////////////////////////
public:
//== Loan Read/Take API ==================================================
/**
* This operation reads a sequence of typed samples from the DataReader.
*
* What samples are read depends on what @link dds::sub::DataReader::default_filter_state(const dds::sub::status::DataState& state)
* default state filter @endlink has been set (default any).
*
* This operation reads a sequence of typed samples from the DataReader<type>. The
* data is put into a dds::sub::LoanedSamples, which is basically a sequence of samples,
* which in turn contains the actual data and meta information.
*
* The memory used for storing the sample may be loaned by the middleware thus allowing zero
* copy operations.
*
* If the DataReader has no samples that meet the constraints, the resulting
* dds::sub::LoanedSamples will be empty.
* @code{.cpp}
* dds::domain::DomainParticipant participant(org::eclipse::cyclonedds::domain::default_id());
* dds::topic::Topic<Foo::Bar> topic(participant, "TopicName");
* dds::sub::Subscriber subscriber(participant);
* dds::sub::DataReader<Foo::Bar> reader(subscriber, topic);
*
* {
* // Read the available samples.
* dds::sub::LoanedSamples<Foo::Bar> samples;
* samples = reader.read();
*
* // Access the information.
* dds::sub::LoanedSamples<Foo::Bar>::const_iterator it;
* for (it = samples.begin(); it != samples.end(); ++it) {
* const dds::sub::Sample<Foo::Bar>& sample = *it;
* }
* }
* // The LoanedSamples went out of scope, meaning the loan resources were taken care of.
* @endcode
*
* <b><i>Selectors</i></b><br>
* What data is read already depends on the
* @ref anchor_dds_sub_datareader_defaultstatefilter "default state filter".
* But it can be manipulated even more when using dds::sub::DataReader::select()
* operation.
*
* @anchor anchor_dds_sub_datareader_invalidsamples
* <b><i>Invalid Data</i></b><br>
* Some elements in the returned sequence may not have valid data: the valid_data
* field in the SampleInfo indicates whether the corresponding data value contains
* any meaningful data. If not, the data value is just a dummy sample for which only
* the keyfields have been assigned. It is used to accompany the SampleInfo that
* communicates a change in the instance_state of an instance for which there is
* no real sample available.
*
* For example, when an application always takes all available samples of a
* particular instance, there is no sample available to report the disposal of that
* instance. In such a case the DataReader will insert a dummy sample into the
* data_values sequence to accompany the SampleInfo element in the info_seq
* sequence that communicates the disposal of the instance.
*
* The act of reading a sample sets its sample_state to READ_SAMPLE_STATE. If
* the sample belongs to the most recent generation of the instance, it also sets the
* view_state of the instance to NOT_NEW_VIEW_STATE. It does not affect the
* instance_state of the instance.
*
* @return The samples in the LoanedSamples container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
LoanedSamples<T> read();
/**
* This operation takes a sequence of typed samples from the DataReader.
*
* The behaviour is identical to read except for that the samples are removed
* from the DataReader.
*
* What samples are taken depends on what @link dds::sub::DataReader::default_filter_state(const dds::sub::status::DataState& state)
* default state filter @endlink has been set (default any).
*
* This operation takes a sequence of typed samples from the DataReader<type>. The
* data is put into a dds::sub::LoanedSamples, which is basically a sequence of samples,
* which in turn contains the actual data and meta information.
*
* The memory used for storing the sample may be loaned by the middleware thus allowing zero
* copy operations.
*
* If the DataReader has no samples that meet the constraints, the resulting
* dds::sub::LoanedSamples will be empty.
* @code{.cpp}
* dds::domain::DomainParticipant participant(org::eclipse::cyclonedds::domain::default_id());
* dds::topic::Topic<Foo::Bar> topic(participant, "TopicName");
* dds::sub::Subscriber subscriber(participant);
* dds::sub::DataReader<Foo::Bar> reader(subscriber, topic);
*
* {
* // Take the available samples.
* dds::sub::LoanedSamples<Foo::Bar> samples;
* samples = reader.take();
*
* // Access the information.
* dds::sub::LoanedSamples<Foo::Bar>::const_iterator it;
* for (it = samples.begin(); it != samples.end(); ++it) {
* const dds::sub::Sample<Foo::Bar>& sample = *it;
* }
* }
* // The LoanedSamples went out of scope, meaning the loan resources were taken care of.
* @endcode
*
* <b><i>Selectors</i></b><br>
* What data is taken, already depends on the
* @ref anchor_dds_sub_datareader_defaultstatefilter "default state filter".
* But it can be manipulated even more when using dds::sub::DataReader::select()
* operation.
*
* <b><i>Invalid Data</i></b><br>
* Some elements in the returned sequence may not have valid data: the valid_data
* field in the SampleInfo indicates whether the corresponding data value contains
* any meaningful data.<br>
* Look @ref anchor_dds_sub_datareader_invalidsamples "here" for more information.
*
* @return The samples in the LoanedSamples container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
LoanedSamples<T> take();
//== Copy Read/Take API ==================================================
// --- Forward Iterators: --- //
/**
* This operation reads a sequence of typed samples from the DataReader.
*
* What samples are read depends on what @link dds::sub::DataReader::default_filter_state(const dds::sub::status::DataState& state)
* default state filter @endlink has been set (default any).
*
* The samples are copied into the application provided container using the
* forward iterator parameter.
*
* If the DataReader has no samples that meet the constraints, the resulting
* dds::sub::LoanedSamples will be empty.
* @code{.cpp}
* dds::domain::DomainParticipant participant(org::eclipse::cyclonedds::domain::default_id());
* dds::topic::Topic<Foo::Bar> topic(participant, "TopicName");
* dds::sub::Subscriber subscriber(participant);
* dds::sub::DataReader<Foo::Bar> reader(subscriber, topic);
*
* // Prepare container to store samples in
* const uint32_t MAX_SAMPLES (3)
* std::vector<dds::sub::Sample<Foo::Bar> > samples(MAX_SAMPLES);
* std::vector<dds::sub::Sample<Foo::Bar> >::iterator iter = samples.begin();
*
* // Read and copy the available samples into the vector by means of the iterator
* uint32_t len = reader.read(iter, MAX_SAMPLES);
*
* // Access the information.
* for (iter = samples.begin(); iter != samples.end(); ++iter) {
* const dds::sub::Sample<Foo::Bar>& sample = *iter;
* }
* @endcode
*
* <b><i>Selectors</i></b><br>
* What data is read already depends on the
* @ref anchor_dds_sub_datareader_defaultstatefilter "default state filter".
* But it can be manipulated even more when using dds::sub::DataReader::select()
* operation.
*
* <b><i>Invalid Data</i></b><br>
* Some elements in the returned sequence may not have valid data: the valid_data
* field in the SampleInfo indicates whether the corresponding data value contains
* any meaningful data.<br>
* Look @ref anchor_dds_sub_datareader_invalidsamples "here" for more information.
*
* @param sfit Forward-inserting container iterator
* @param max_samples Maximum samples to read and copy into the given container
* @return The number of samples in the LoanedSamples container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
template <typename SamplesFWIterator>
uint32_t
read(SamplesFWIterator sfit,
uint32_t max_samples);
/**
* This operation takes a sequence of typed samples from the DataReader.
*
* What samples are take depends on what @link dds::sub::DataReader::default_filter_state(const dds::sub::status::DataState& state)
* default state filter @endlink has been set (default any).
*
* The samples are copied into the application provided container using the
* forward iterator parameter.
*
* If the DataReader has no samples that meet the constraints, the resulting
* dds::sub::LoanedSamples will be empty.
* @code{.cpp}
* dds::domain::DomainParticipant participant(org::eclipse::cyclonedds::domain::default_id());
* dds::topic::Topic<Foo::Bar> topic(participant, "TopicName");
* dds::sub::Subscriber subscriber(participant);
* dds::sub::DataReader<Foo::Bar> reader(subscriber, topic);
*
* // Prepare container to store samples in
* const uint32_t MAX_SAMPLES (3)
* std::vector<dds::sub::Sample<Foo::Bar> > samples(MAX_SAMPLES);
* std::vector<dds::sub::Sample<Foo::Bar> >::iterator iter = samples.begin();
*
* // Take and copy the available samples into the vector by means of the iterator
* uint32_t len = reader.take(iter, MAX_SAMPLES);
*
* // Access the information.
* for (iter = samples.begin(); iter != samples.end(); ++iter) {
* const dds::sub::Sample<Foo::Bar>& sample = *iter;
* }
* @endcode
*
* <b><i>Selectors</i></b><br>
* What data is taken, already depends on the
* @ref anchor_dds_sub_datareader_defaultstatefilter "default state filter".
* But it can be manipulated even more when using dds::sub::DataReader::select()
* operation.
*
* <b><i>Invalid Data</i></b><br>
* Some elements in the returned sequence may not have valid data: the valid_data
* field in the SampleInfo indicates whether the corresponding data value contains
* any meaningful data.<br>
* Look @ref anchor_dds_sub_datareader_invalidsamples "here" for more information.
*
* @param sfit Forward-inserting container iterator
* @param max_samples Maximum samples to take and copy into the given container
* @return The number of samples in the given container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
template <typename SamplesFWIterator>
uint32_t
take(SamplesFWIterator sfit,
uint32_t max_samples);
// --- Back-Inserting Iterators: --- //
/**
* This operation reads a sequence of typed samples from the DataReader.
*
* What samples are read depends on what @link dds::sub::DataReader::default_filter_state(const dds::sub::status::DataState& state)
* default state filter @endlink has been set (default any).
*
* The samples are copied into the application provided container using a
* back-inserting iterator. Notice that as a consequence of using a back-inserting
* iterator, this operation may allocate memory to resize the underlying container.
*
* If the DataReader has no samples that meet the constraints, the resulting
* dds::sub::LoanedSamples will be empty.
* @code{.cpp}
* dds::domain::DomainParticipant participant(org::eclipse::cyclonedds::domain::default_id());
* dds::topic::Topic<Foo::Bar> topic(participant, "TopicName");
* dds::sub::Subscriber subscriber(participant);
* dds::sub::DataReader<Foo::Bar> reader(subscriber, topic);
*
* // Prepare container to store samples in
* std::vector<dds::sub::Sample<Foo::Bar> > samples;
* std::back_insert_iterator< std::vector<dds::sub::Sample<Foo::Bar> > > bi(samples);
*
* // Read and copy the available samples into the vector by means of the iterator
* uint32_t len = reader.read(bi);
*
* // Access the information.
* std::vector<dds::sub::Sample<Space::Type1> >::iterator iter = samples.begin();
* for (iter = samples.begin(); iter != samples.end(); ++iter) {
* const dds::sub::Sample<Foo::Bar>& sample = *iter;
* }
* @endcode
*
* <b><i>Selectors</i></b><br>
* What data is read already depends on the
* @ref anchor_dds_sub_datareader_defaultstatefilter "default state filter".
* But it can be manipulated even more when using dds::sub::DataReader::select()
* operation.
*
* <b><i>Invalid Data</i></b><br>
* Some elements in the returned sequence may not have valid data: the valid_data
* field in the SampleInfo indicates whether the corresponding data value contains
* any meaningful data.<br>
* Look @ref anchor_dds_sub_datareader_invalidsamples "here" for more information.
*
* @param sbit Back-inserting container iterator
* @return The number of samples in the given container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
template <typename SamplesBIIterator>
uint32_t
read(SamplesBIIterator sbit);
/**
* This operation takes a sequence of typed samples from the DataReader.
*
* What samples are take depends on what @link dds::sub::DataReader::default_filter_state(const dds::sub::status::DataState& state)
* default state filter @endlink has been set (default any).
*
* The samples are copied into the application provided container using a
* back-inserting iterator. Notice that as a consequence of using a back-inserting
* iterator, this operation may allocate memory to resize the underlying container.
*
* If the DataReader has no samples that meet the constraints, the resulting
* dds::sub::LoanedSamples will be empty.
* @code{.cpp}
* dds::domain::DomainParticipant participant(org::eclipse::cyclonedds::domain::default_id());
* dds::topic::Topic<Foo::Bar> topic(participant, "TopicName");
* dds::sub::Subscriber subscriber(participant);
* dds::sub::DataReader<Foo::Bar> reader(subscriber, topic);
*
* // Prepare container to store samples in
* std::vector<dds::sub::Sample<Foo::Bar> > samples;
* std::back_insert_iterator< std::vector<dds::sub::Sample<Foo::Bar> > > bi(samples);
*
* // Take and copy the available samples into the vector by means of the iterator
* uint32_t len = reader.take(bi);
*
* // Access the information.
* std::vector<dds::sub::Sample<Space::Type1> >::iterator iter = samples.begin();
* for (iter = samples.begin(); iter != samples.end(); ++iter) {
* const dds::sub::Sample<Foo::Bar>& sample = *iter;
* }
* @endcode
*
* <b><i>Selectors</i></b><br>
* What data is taken, already depends on the
* @ref anchor_dds_sub_datareader_defaultstatefilter "default state filter".
* But it can be manipulated even more when using dds::sub::DataReader::select()
* operation.
*
* <b><i>Invalid Data</i></b><br>
* Some elements in the returned sequence may not have valid data: the valid_data
* field in the SampleInfo indicates whether the corresponding data value contains
* any meaningful data.<br>
* Look @ref anchor_dds_sub_datareader_invalidsamples "here" for more information.
*
* @param sbit Back-inserting container iterator
* @return The number of samples in the given container
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
template <typename SamplesBIIterator>
uint32_t
take(SamplesBIIterator sbit);
public:
//========================================================================
//== DSL Method for dealing with instances, content and status filters.
/**
* Get a dds::sub::DataReader::Selector instance that acts on this DataReader.
*
* The DataReader::read and DataReader::take read all samples that are
* available within the DataReader (provided that the
* @ref anchor_dds_sub_datareader_defaultstatefilter "default state filter"
* hasn't been changed).
*
* <b><i>Selectors</i></b><br>
* A Selector can perform complex data selections, such as per-instance selection,
* content and status filtering, etc when reading or taking. Such a selector is
* returned by this operation. Setting filters on the Selector can be concatenated,
* resulting in the following example code.
* @code{.cpp}
* dds::domain::DomainParticipant participant(org::eclipse::cyclonedds::domain::default_id());
* dds::topic::Topic<Foo::Bar> topic(participant, "TopicName");
* dds::sub::Subscriber subscriber(participant);
* dds::sub::DataReader<Foo::Bar> reader(subscriber, topic);
*
* // Take a maximum of 3 new samples of a certain instance.
* {
* dds::sub::LoanedSamples<Foo::Bar> samples;
* samples = reader.select()
* .max_samples(3)
* .state(dds::sub::status::DataState::new_data())
* .instance(someValidInstanceHandle)
* .take();
* }
* @endcode
*
* <i>Please be aware that using pre-set filters on the DataReader and then
* call read() or take() on that reader explicitly will perform better than
* having to create Selectors for every read (which is what essentially
* happens in the code example above). Performance can be increase by creating
* a selector up front and using that multiple times
* (see dds::sub::DataReader::Selector).</i>
*
* @return A Selector that acts on the DataReader
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
*/
Selector select();
//========================================================================
//== Instance Management
public:
/**
* This operation retrieves the key value of a specific instance.
*
* This operation can be used to retrieve the instance key that corresponds
* to an instance_handle. The operation will only fill the fields that form
* the key inside the sample instance.
*
* This operation may raise a InvalidArgumentError exception if the InstanceHandle
* does not correspond to an existing data-object known to the DataReader.
* If the implementation is not able to check invalid handles, then the
* result in this situation is unspecified.
*
* @param h The instance handle
* @return A topic instance with the handle and key fields set
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::InvalidArgumentError
* The InstanceHandle is not a valid handle.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
* @throws dds::core::PreconditionNotMetError
* The handle has not been registered with this DataReader.
*/
dds::topic::TopicInstance<T> key_value(const dds::core::InstanceHandle& h);
/**
* This operation retrieves the key value of a specific instance.
*
* This operation can be used to retrieve the instance key that corresponds
* to an instance_handle. The operation will only fill the fields that form
* the key inside the sample instance.
*
* This operation may raise a InvalidArgumentError exception if the InstanceHandle
* does not correspond to an existing data-object known to the DataReader.
* If the implementation is not able to check invalid handles, then the
* result in this situation is unspecified.
*
* The Sample is added as parameter to be able to overload this operation.
*
* @param[out] sample A sample to set the key fields of
* @param[in] h The instance handle
* @return The given sample with the key fields set
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::InvalidArgumentError
* The InstanceHandle is not a valid handle.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
* @throws dds::core::NotEnabledError
* The DataReader has not yet been enabled.
* @throws dds::core::PreconditionNotMetError
* The handle has not been registered with this DataReader.
*/
T& key_value(T& sample, const dds::core::InstanceHandle& h);
/**
* This operation returns the value of the instance handle which corresponds
* to the instance_data.
*
* The instance handle can be used in read operations that operate
* on a specific instance. Note that DataReader instance handles are local, and are
* not interchangeable with DataWriter instance handles nor with instance handles
* of an other DataReader.
*
* This operation does not register the instance in question. If the instance has not been
* previously registered or if for any other
* reason the Service is unable to provide an instance handle, the Service will return
* the default nil handle (InstanceHandle.is_nil() == true).
*
* @param key the sample
* @return the instance handle
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
*/
const dds::core::InstanceHandle
lookup_instance(const T& key) const;
public:
/**
* Register a listener with the DataReader.
*
* This operation attaches a DataReaderListener to the DataReader. Only one
* DataReaderListener can be attached to each DataReader. If a
* DataReaderListener was already attached, the operation will replace it with the
* new one. When the listener is the NULL pointer, it represents a listener that is
* treated as a NOOP for all statuses activated in the bit mask.
*
* Listener un-registration is performed by setting the listener to NULL and mask none().
*
* @anchor anchor_dds_sub_datareader_commstatus
* <i>Communication Status</i><br>
* For each communication status, the StatusChangedFlag flag is initially set to
* FALSE. It becomes TRUE whenever that communication status changes. For each
* communication status activated in the mask, the associated DataReaderListener
* operation is invoked and the communication status is reset to FALSE, as the listener
* implicitly accesses the status which is passed as a parameter to that operation. The
* status is reset prior to calling the listener, so if the application calls the
* get_<status_name>_status from inside the listener it will see the status
* already reset. An exception to this rule is the NULL listener, which does not reset the
* communication statuses for which it is invoked.
*
* The following statuses are applicable to the DataReaderListener:
* - dds::core::status::StatusMask::requested_deadline_missed()
* - dds::core::status::StatusMask::requested_incompatible_qos()
* - dds::core::status::StatusMask::sample_lost()
* - dds::core::status::StatusMask::sample_rejected()
* - dds::core::status::StatusMask::data_available()
* - dds::core::status::StatusMask::liveliness_changed()
* - dds::core::status::StatusMask::subscription_matched()
*
* Be aware that the SUBSCRIPTION_MATCHED_STATUS is not applicable when the
* infrastructure does not have the information available to determine connectivity.
* This is the case when OpenSplice is configured not to maintain discovery
* information in the Networking Service. (See the description for the
* NetworkingService/Discovery/enabled property in the Deployment
* Manual for more information about this subject.) In this case the operation will
* throw UnsupportedError.
*
* Status bits are declared as a constant and can be used by the application in an OR
* operation to create a tailored mask. The special constant dds::core::status::StatusMask::none()
* can be used to indicate that the created entity should not respond to any of its available
* statuses. The DDS will therefore attempt to propagate these statuses to its factory.
* The special constant dds::core::status::StatusMask::all() can be used to select all applicable
* statuses specified in the "Data Distribution Service for Real-time Systems Version
* 1.2" specification which are applicable to the PublisherListener.
*
* @anchor anchor_dds_sub_datareader_commpropagation
* <i>Status Propagation</i><br>
* In case a communication status is not activated in the mask of the
* DataReaderListener, the SubscriberListener of the containing Subscriber
* is invoked (if attached and activated for the status that occurred). This allows the
* application to set a default behaviour in the SubscriberListener of the containing
* Subscriber and a DataReader specific behaviour when needed. In case the
* communication status is not activated in the mask of the SubscriberListener as
* well, the communication status will be propagated to the
* DomainParticipantListener of the containing DomainParticipant. In case
* the DomainParticipantListener is also not attached or the communication
* status is not activated in its mask, the application is not notified of the change.
*
* The statuses DATA_ON_READERS_STATUS and DATA_AVAILABLE_STATUS are
* "Read Communication Statuses" and are an exception to all other plain
* communication statuses: they have no corresponding status structure that can be
* obtained with a get_<status_name>_status operation and they are mutually
* exclusive. When new information becomes available to a DataReader, the Data
* Distribution Service will first look in an attached and activated
* SubscriberListener or DomainParticipantListener (in that order) for the
* DATA_ON_READERS_STATUS. In case the DATA_ON_READERS_STATUS can not be
* handled, the Data Distribution Service will look in an attached and activated
* DataReaderListener, SubscriberListener or DomainParticipant
* Listener for the DATA_AVAILABLE_STATUS (in that order).
*
* See also @ref DCPS_Modules_Infrastructure_Listener "listener information".
*
* @param listener the listener
* @param event_mask the mask defining the events for which the listener
* will be notified.
* @throws dds::core::Error
* An internal error has occurred.
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
* @throws dds::core::AlreadyClosedError
* The entity has already been closed.
* @throws dds::core::UnsupportedError
* A status was selected that cannot be supported because
* the infrastructure does not maintain the required connectivity information.
* @throws dds::core::OutOfResourcesError
* The Data Distribution Service ran out of resources to
* complete this operation.
*/
void listener(Listener* listener,
const dds::core::status::StatusMask& event_mask);
/**
* Get the listener of this DataReader.
*
* See also @ref DCPS_Modules_Infrastructure_Listener "listener information".
*
* @return the listener
* @throws dds::core::NullReferenceError
* The entity was not properly created and references to dds::core::null.
*/
Listener* listener() const;
};
#endif /* OMG_DDS_SUB_TDATA_READER_HPP_ */