@@ -39,6 +39,12 @@ namespace frame
3939// / @li @ref comms::option::ExtendingClass - Use this option to provide a class
4040// / name of the extending class, which can be used to extend existing functionality.
4141// / See also @ref page_custom_sync_prefix_layer.
42+ // / @li @ref comms::option::def::FrameLayerSeekField - By default, the
43+ // / @b SyncSuffixLayer will invoke @b read operation of inner (wrapped) layers
44+ // / and only if it is successful. Usage of @ref comms::option::def::FrameLayerSeekField
45+ // / modifies the default behaviour by forcing layer to seek the field in the
46+ // / buffer (until the successful read and verification)
47+ // / prior to invocation of @b read operation in the wrapped layer(s).
4248// / @headerfile comms/frame/SyncPrefixLayer.h
4349// / @extends comms::frame::FrameLayerBase
4450template <typename TField, typename TNextLayer, typename ... TOptions>
@@ -85,7 +91,7 @@ class SyncPrefixLayer : public comms::frame::details::SyncPrefixLayerBase<TField
8591 // / the next layer is called.
8692 // / @tparam TMsg Type of the @b msg parameter.
8793 // / @tparam TIter Type of iterator used for reading.
88- // / @tparam TNextLayerReader next layer reader object type.
94+ // / @tparam TNextLayerReader Next layer reader object type.
8995 // / @param[out] field Field object to read.
9096 // / @param[in, out] msg Reference to smart pointer, that already holds or
9197 // / will hold allocated message object, or reference to actual message
@@ -114,26 +120,23 @@ class SyncPrefixLayer : public comms::frame::details::SyncPrefixLayerBase<TField
114120 TNextLayerReader&& nextLayerReader,
115121 TExtraValues... extraValues)
116122 {
117- auto & thisObj = BaseImpl::thisLayer ();
118- auto * msgPtr = BaseImpl::toMsgPtr (msg);
119- auto beforeReadIter = iter;
120-
121- auto es = thisObj.doReadField (msgPtr, field, iter, size);
122- if (es == comms::ErrorStatus::NotEnoughData) {
123- BaseImpl::updateMissingSize (field, size, extraValues...);
124- }
125-
126- if (es != comms::ErrorStatus::Success) {
127- return es;
128- }
129-
130- bool verified = thisObj.verifyFieldValue (field);
131- if (!verified) {
132- return comms::ErrorStatus::ProtocolError;
133- }
123+ using SeekTag =
124+ typename comms::util::LazyShallowConditional<
125+ ParsedOptionsInternal::HasSeekField
126+ >::template Type<
127+ SeekFieldTag,
128+ InstantOpTag
129+ >;
134130
135- auto fieldLen = static_cast <std::size_t >(std::distance (beforeReadIter, iter));
136- return nextLayerReader.read (msg, iter, size - fieldLen, extraValues...);
131+ return
132+ readInternal (
133+ field,
134+ msg,
135+ iter,
136+ size,
137+ std::forward<TNextLayerReader>(nextLayerReader),
138+ SeekTag (),
139+ extraValues...);
137140 }
138141
139142 // / @brief Customized write functionality, invoked by @ref comms::frame::FrameLayerBase::write() "write()".
@@ -195,6 +198,95 @@ class SyncPrefixLayer : public comms::frame::details::SyncPrefixLayerBase<TField
195198 {
196199 static_cast <void >(field);
197200 }
201+
202+ private:
203+ template <typename ... TParams>
204+ using SeekFieldTag = comms::details::tag::Tag1<>;
205+
206+ template <typename ... TParams>
207+ using InstantOpTag = comms::details::tag::Tag2<>;
208+
209+ template <typename TMsg, typename TIter, typename TReader, typename ... TExtraValues>
210+ ErrorStatus readInternal (
211+ Field& field,
212+ TMsg& msg,
213+ TIter& iter,
214+ std::size_t size,
215+ TReader&& nextLayerReader,
216+ SeekFieldTag<>,
217+ TExtraValues... extraValues)
218+ {
219+ using IterType = typename std::decay<decltype (iter)>::type;
220+ static_assert (std::is_same<typename std::iterator_traits<IterType>::iterator_category, std::random_access_iterator_tag>::value,
221+ " The read operation is expected to use random access iterator" );
222+
223+ auto & thisObj = BaseImpl::thisLayer ();
224+ auto * msgPtr = BaseImpl::toMsgPtr (msg);
225+
226+ auto fromIter = iter;
227+ std::size_t consumed = 0U ;
228+ while (consumed < size) {
229+ auto iterTmp = iter;
230+ auto remSize = size - consumed;
231+
232+ auto fieldEs = thisObj.doReadField (msgPtr, field, iterTmp, remSize);
233+ if (fieldEs == ErrorStatus::NotEnoughData) {
234+ BaseImpl::updateMissingSize (field, remSize, extraValues...);
235+ BaseImpl::resetMsg (msg);
236+ return fieldEs;
237+ }
238+
239+ if ((fieldEs == ErrorStatus::Success) &&
240+ (thisObj.verifyFieldValue (field))) {
241+ // Set iter to point after field
242+ iter = iterTmp;
243+ break ;
244+ }
245+
246+ ++iter;
247+ ++consumed;
248+ }
249+
250+ if (size <= consumed) {
251+ // Field hasn't been recognized
252+ return ErrorStatus::NotEnoughData;
253+ }
254+
255+ auto remSize = size - static_cast <std::size_t >(std::distance (fromIter, iter));
256+ return nextLayerReader.read (msg, iter, remSize, extraValues...);
257+ }
258+
259+ template <typename TMsg, typename TIter, typename TReader, typename ... TExtraValues>
260+ ErrorStatus readInternal (
261+ Field& field,
262+ TMsg& msg,
263+ TIter& iter,
264+ std::size_t size,
265+ TReader&& nextLayerReader,
266+ InstantOpTag<>,
267+ TExtraValues... extraValues)
268+ {
269+ auto & thisObj = BaseImpl::thisLayer ();
270+ auto * msgPtr = BaseImpl::toMsgPtr (msg);
271+ auto beforeReadIter = iter;
272+
273+ auto es = thisObj.doReadField (msgPtr, field, iter, size);
274+ if (es == comms::ErrorStatus::NotEnoughData) {
275+ BaseImpl::updateMissingSize (field, size, extraValues...);
276+ }
277+
278+ if (es != comms::ErrorStatus::Success) {
279+ return es;
280+ }
281+
282+ bool verified = thisObj.verifyFieldValue (field);
283+ if (!verified) {
284+ return comms::ErrorStatus::ProtocolError;
285+ }
286+
287+ auto fieldLen = static_cast <std::size_t >(std::distance (beforeReadIter, iter));
288+ return nextLayerReader.read (msg, iter, size - fieldLen, extraValues...);
289+ }
198290};
199291
200292namespace details
0 commit comments