#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 #include #include #include #include #include namespace dds { namespace sub { template class DELEGATE> class DataReader; template 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 classes. For each application data type that is used as Topic /// data type, a typed class DataReader 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. /// /// General note: The name ccpp_Foo.h is derived from the IDL file Foo.idl, /// that defines Foo::Bar, for all relevant DataReader 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 /// Example /// @code{.cpp} /// // Default creation of a DataReader /// dds::domain::DomainParticipant participant(org::eclipse::cyclonedds::domain::default_id()); /// dds::topic::Topic topic(participant, "TopicName"); /// dds::sub::Subscriber subscriber(participant); /// dds::sub::DataReader reader(subscriber, topic); /// /// { /// // Default read of a sample on the DataReader /// dds::sub::LoanedSamples samples; /// samples = reader.read(); /// /// // Default way of accessing the loaned samples /// dds::sub::LoanedSamples::const_iterator it; /// for (it = samples.begin(); it != samples.end(); ++it) { /// const dds::sub::Sample& 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 class DELEGATE> class dds::sub::DataReader final : public dds::sub::TAnyDataReader< DELEGATE > { public: /** * Local convenience typedef for dds::sub::DataReaderListener. */ typedef ::dds::sub::DataReaderListener 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::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 /// /// Defaults /// 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. /// /// Example
/// 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::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. /// /// Example
/// 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& 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::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& 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. /// /// Example
/// 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::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. /// /// Example
/// 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::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. /// /// Example
/// 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::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 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 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 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 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 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 uint32_t take(SamplesBIIterator sbit); private: typename DELEGATE::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. /// /// Convenience functors
/// 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::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 /// /// Defaults /// 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& ls) DataReader stream operator>> @endlink class ManipulatorSelector { public: /** * Construct a ManipulatorSelector for a DataReader. * * See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples& 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 /// /// Convenience Functor: dds::sub::read
/// Convenience Functor: dds::sub::take /// /// Example
/// 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::ManipulatorSelector readingReader(reader); /// readingReader.read_mode(true); // Read, which is already the default. /// readingReader >> samples; /// /// dds::sub::DataReader::ManipulatorSelector takingReader(reader); /// takingReader.read_mode(false); // Take. /// takingReader >> samples; /// @endcode /// See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples& 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. /// /// Convenience Functor: dds::sub::max_samples /// /// Example
/// 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::ManipulatorSelector selectiveReader(reader); /// selectiveReader.max_samples(3); /// selectiveReader >> samples; /// @endcode /// See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples& 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. /// /// Convenience Functor: dds::sub::instance /// /// Example
/// 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::ManipulatorSelector selectiveReader(reader); /// selectiveReader.instance(hdl); /// selectiveReader >> samples; /// @endcode /// See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples& 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. /// /// Convenience Functor: dds::sub::next_instance /// /// Example
/// 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& 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::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& 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& 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. /// /// Convenience Functor: dds::sub::state /// /// Example
/// 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::ManipulatorSelector selectiveReader(reader); /// selectiveReader.state(newData); /// selectiveReader.read() >> samples; /// @endcode /// See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples& 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. /// /// Convenience Functor: dds::sub::content /// /// Example
/// 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::ManipulatorSelector selectiveReader(reader); /// selectiveReader.content(query); /// selectiveReader >> read; /// @endcode /// See also @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples& 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& 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& samples); /** * This operation works the same as the @link dds::sub::DataReader::operator>>(dds::sub::LoanedSamples& 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& 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 ManipulatorSelector operator >> (Functor f); private: typename DELEGATE::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. * * QoS
* 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& 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. /// /// QoS
/// 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 reader(subscriber, topic, readerQos); /// @endcode /// /// Listener
/// 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& topic, const dds::sub::qos::DataReaderQos& qos, dds::sub::DataReaderListener* 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& topic) */ DataReader(const dds::sub::Subscriber& sub, const ::dds::topic::ContentFilteredTopic& topic); /** @copydoc dds::sub::DataReader::DataReader(const dds::sub::Subscriber& sub, const ::dds::topic::Topic& topic, const dds::sub::qos::DataReaderQos& qos, dds::sub::DataReaderListener* listener, const dds::core::status::StatusMask& mask) */ DataReader(const dds::sub::Subscriber& sub, const ::dds::topic::ContentFilteredTopic& topic, const dds::sub::qos::DataReaderQos& qos, dds::sub::DataReaderListener* 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& topic) */ DataReader(const dds::sub::Subscriber& sub, const ::dds::topic::MultiTopic& topic); /** @copydoc dds::sub::DataReader::DataReader(const dds::sub::Subscriber& sub, const ::dds::topic::Topic& topic, const dds::sub::qos::DataReaderQos& qos, dds::sub::DataReaderListener* listener, const dds::core::status::StatusMask& mask) */ DataReader(const dds::sub::Subscriber& sub, const ::dds::topic::MultiTopic& topic, const dds::sub::qos::DataReaderQos& qos, dds::sub::DataReaderListener* 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 * Default State Filter
* 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. 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 topic(participant, "TopicName"); /// dds::sub::Subscriber subscriber(participant); /// dds::sub::DataReader reader(subscriber, topic); /// /// { /// dds::sub::LoanedSamples samples; /// reader >> samples; /// } /// // The LoanedSamples went out of scope, meaning the loan was returned. /// @endcode /// /// Take
/// 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). /// /// Manipulators
/// 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 /// /// 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). /// /// Invalid Data
/// 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& ls); /** @copydoc dds::sub::DataReader::operator>>(dds::sub::LoanedSamples& ls) */ ManipulatorSelector operator>> (ManipulatorSelector & (manipulator)(ManipulatorSelector&)); /** @copydoc dds::sub::DataReader::operator>>(dds::sub::LoanedSamples& ls) */ template 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. 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 topic(participant, "TopicName"); /// dds::sub::Subscriber subscriber(participant); /// dds::sub::DataReader reader(subscriber, topic); /// /// { /// // Read the available samples. /// dds::sub::LoanedSamples samples; /// samples = reader.read(); /// /// // Access the information. /// dds::sub::LoanedSamples::const_iterator it; /// for (it = samples.begin(); it != samples.end(); ++it) { /// const dds::sub::Sample& sample = *it; /// } /// } /// // The LoanedSamples went out of scope, meaning the loan resources were taken care of. /// @endcode /// /// Selectors
/// 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 /// Invalid Data
/// 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 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. 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 topic(participant, "TopicName"); /// dds::sub::Subscriber subscriber(participant); /// dds::sub::DataReader reader(subscriber, topic); /// /// { /// // Take the available samples. /// dds::sub::LoanedSamples samples; /// samples = reader.take(); /// /// // Access the information. /// dds::sub::LoanedSamples::const_iterator it; /// for (it = samples.begin(); it != samples.end(); ++it) { /// const dds::sub::Sample& sample = *it; /// } /// } /// // The LoanedSamples went out of scope, meaning the loan resources were taken care of. /// @endcode /// /// Selectors
/// 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. /// /// Invalid Data
/// 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.
/// 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 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 topic(participant, "TopicName"); /// dds::sub::Subscriber subscriber(participant); /// dds::sub::DataReader reader(subscriber, topic); /// /// // Prepare container to store samples in /// const uint32_t MAX_SAMPLES (3) /// std::vector > samples(MAX_SAMPLES); /// std::vector >::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& sample = *iter; /// } /// @endcode /// /// Selectors
/// 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. /// /// Invalid Data
/// 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.
/// 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 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 topic(participant, "TopicName"); /// dds::sub::Subscriber subscriber(participant); /// dds::sub::DataReader reader(subscriber, topic); /// /// // Prepare container to store samples in /// const uint32_t MAX_SAMPLES (3) /// std::vector > samples(MAX_SAMPLES); /// std::vector >::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& sample = *iter; /// } /// @endcode /// /// Selectors
/// 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. /// /// Invalid Data
/// 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.
/// 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 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 topic(participant, "TopicName"); /// dds::sub::Subscriber subscriber(participant); /// dds::sub::DataReader reader(subscriber, topic); /// /// // Prepare container to store samples in /// std::vector > samples; /// std::back_insert_iterator< std::vector > > 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 >::iterator iter = samples.begin(); /// for (iter = samples.begin(); iter != samples.end(); ++iter) { /// const dds::sub::Sample& sample = *iter; /// } /// @endcode /// /// Selectors
/// 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. /// /// Invalid Data
/// 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.
/// 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 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 topic(participant, "TopicName"); /// dds::sub::Subscriber subscriber(participant); /// dds::sub::DataReader reader(subscriber, topic); /// /// // Prepare container to store samples in /// std::vector > samples; /// std::back_insert_iterator< std::vector > > 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 >::iterator iter = samples.begin(); /// for (iter = samples.begin(); iter != samples.end(); ++iter) { /// const dds::sub::Sample& sample = *iter; /// } /// @endcode /// /// Selectors
/// 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. /// /// Invalid Data
/// 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.
/// 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 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). /// /// Selectors
/// 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 topic(participant, "TopicName"); /// dds::sub::Subscriber subscriber(participant); /// dds::sub::DataReader reader(subscriber, topic); /// /// // Take a maximum of 3 new samples of a certain instance. /// { /// dds::sub::LoanedSamples samples; /// samples = reader.select() /// .max_samples(3) /// .state(dds::sub::status::DataState::new_data()) /// .instance(someValidInstanceHandle) /// .take(); /// } /// @endcode /// /// 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). /// /// @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 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 * Communication Status
* 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 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. * 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 * Status Propagation
* 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 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_ */