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

1690 lines
78 KiB
C++
Raw Normal View History

2024-01-04 03:45:40 +08:00
#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_ */