LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/base - proto.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 274 286 95.8 %
Date: 2026-11-09 02:10:49 Functions: 1262 1375 91.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #ifndef ctrlplane_proto_h
       7             : #define ctrlplane_proto_h
       8             : 
       9             : #define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
      10             : #define BOOST_MPL_LIMIT_MAP_SIZE 30
      11             : 
      12             : #include <map>
      13             : #include <memory>
      14             : 
      15             : #include <vector>
      16             : 
      17             : #include <boost/ptr_container/ptr_vector.hpp>
      18             : #include <boost/function.hpp>
      19             : #include <boost/type_traits/is_same.hpp>
      20             : #include <boost/type_traits/is_base_of.hpp>
      21             : #include <boost/mpl/equal_to.hpp>
      22             : #include <boost/mpl/for_each.hpp>
      23             : #include <boost/mpl/greater.hpp>
      24             : #include <boost/mpl/list.hpp>
      25             : #include <boost/mpl/map.hpp>
      26             : #include <boost/mpl/or.hpp>
      27             : #include <boost/mpl/vector.hpp>
      28             : #include <boost/mpl/string.hpp>
      29             : 
      30             : #include "base/compiler.h"
      31             : #include "base/logging.h"
      32             : #include "base/parse_object.h"
      33             : 
      34             : namespace mpl = boost::mpl;
      35             : 
      36             : class ParseContext {
      37             : public:
      38             : 
      39             :     ParseContext();
      40             :     ~ParseContext();
      41             : 
      42             :     ParseObject *release();
      43             : 
      44             :     void Push(ParseObject *data);
      45             :     ParseObject *Pop();
      46             : 
      47             :     void SwapData(ParseObject *obj);
      48             :     void ReleaseData();
      49             : 
      50             :     ParseObject *data();
      51             : 
      52             :     void advance(int delta);
      53      195410 :     int offset() const { return offset_; }
      54             : 
      55             :     void set_lensize(int lensize);
      56             :     int lensize() const;
      57             :     void set_size(size_t length);
      58             :     size_t size() const;
      59             :     void set_total_size();
      60             :     size_t total_size() const;
      61             : 
      62             :     void SetError(int error, int subcode, std::string type, const uint8_t *data,
      63             :                   int data_size);
      64         139 :     const ParseErrorContext &error_context() { return error_context_; }
      65             : private:
      66             : 
      67             :     ParseErrorContext error_context_;
      68             :     struct StackFrame;
      69             :     int offset_;
      70             :     std::vector<StackFrame *> stack_;
      71             : };
      72             : 
      73             : class EncodeContext {
      74             : public:
      75             :     typedef boost::function<void(EncodeContext *, uint8_t *, int, int)> CallbackType;
      76             : 
      77             :     EncodeContext();
      78             :     ~EncodeContext();
      79             : 
      80             :     void Push();
      81             :     void Pop(bool callback);
      82             :     void AddCallback(CallbackType cb, uint8_t *data, int arg);
      83             : 
      84             :     void advance(int delta);
      85             :     int length() const;
      86             : 
      87             :     void SaveOffset(std::string);
      88      155459 :     EncodeOffsets &encode_offsets() { return offsets_; }
      89             : private:
      90             :     struct StackFrame;
      91             :     boost::ptr_vector<StackFrame> stack_;
      92             :     EncodeOffsets offsets_;
      93             : };
      94             : 
      95             : template <class C, typename T, T C::* Member>
      96             : struct Accessor {
      97             :     typedef T C::* member_ptr_t;
      98     2369158 :     static void set(C *obj, T value) {
      99     2369158 :         obj->*Member = value;
     100     2369158 :     }
     101     3025617 :     static T get(const C *obj) {
     102     3025617 :         return obj->*Member;
     103             :     }
     104             : };
     105             : 
     106             : template <class C, std::string C::* Member>
     107             : struct Accessor<C, std::string, Member> {
     108        4928 :     static void set(C*obj, const uint8_t *data, size_t elem_size) {
     109        4928 :         obj->*Member = std::string((const char *) data, elem_size);
     110        4928 :     }
     111        7582 :     static int size(const C *obj) {
     112        7582 :         return (obj->*Member).size();
     113             :     }
     114        7584 :     static std::string::const_iterator begin(const C *obj) {
     115        7584 :         return (obj->*Member).begin();
     116             :     }
     117        7583 :     static std::string::const_iterator end(const C *obj) {
     118        7583 :         return (obj->*Member).end();
     119             :     }
     120             : };
     121             : 
     122             : template <class C, typename T, std::vector<T> C::* Member>
     123             : struct VectorAccessor {
     124     1547510 :     static void set(C*obj, const uint8_t *data, size_t elem_size) {
     125     1547510 :         obj->*Member = std::vector<T>();
     126     1547599 :         size_t size = sizeof(T);
     127    13346422 :         for (size_t i = 0; i < elem_size; i += size) {
     128    11798826 :             T value = get_value(data, size);
     129    11798804 :             data += size;
     130    11798804 :             (obj->*Member).push_back(value);
     131             :         }
     132     1547596 :     }
     133     2134181 :     static int size(const C *obj) {
     134     2134181 :         return (obj->*Member).size() * sizeof(T);
     135             :     }
     136     2134046 :     static typename std::vector<T>::const_iterator begin(const C *obj) {
     137     2134046 :         return (obj->*Member).begin();
     138             :     }
     139     2134020 :     static typename std::vector<T>::const_iterator end(const C *obj) {
     140     2134020 :         return (obj->*Member).end();
     141             :     }
     142             : };
     143             : 
     144             : // Extract the underlying type for pointer types.
     145             : template <typename T>
     146             : struct ValueType {
     147             :     typedef T type;
     148             : };
     149             : template <typename T>
     150             : struct ValueType<T *> {
     151             :     typedef T type;
     152             : };
     153             : 
     154             : template <typename Obj, typename Col, Col Obj::* Member>
     155             : struct CollectionAccessor {
     156             :     typedef typename ValueType<typename Col::value_type>::type ValueType;
     157             :     typedef Col CollectionType;
     158             :     typedef typename CollectionType::const_iterator iterator;
     159     1792336 :     static void insert(Obj *obj, ValueType *element) {
     160     1792336 :         (obj->*Member).push_back(element);
     161     1792283 :     }
     162      960381 :     static iterator begin(const Obj *obj) {
     163      960381 :         return (obj->*Member).begin();
     164             :     }
     165     3292212 :     static iterator end(const Obj *obj) {
     166     3292212 :         return (obj->*Member).end();
     167             :     }
     168             : };
     169             : 
     170             : // Interface
     171             : struct ElementBase {
     172             :     static const int kSize = 0;
     173             :     static const int kErrorCode = 0;
     174             :     static const int kErrorSubcode = 0;
     175             :     struct NullCtxInit {
     176     5747789 :         void operator()(void *) {
     177     5747789 :         }
     178             :     };
     179             :     struct NoMatch {
     180             :         bool match(const void *) {
     181             :             return false;
     182             :         }
     183             :     };
     184     6209407 :     static bool Verifier(const void * obj, const uint8_t *data, size_t size,
     185             :                          ParseContext *context) {
     186     6209407 :         return true;
     187             :     }
     188             : 
     189             :     typedef void SaveOffset;            // Save the offset in encode context
     190             :     typedef void ContextType;           // push a new context on the stack
     191             :     typedef NullCtxInit ContextInit;    // initialize the context data
     192             :     typedef NoMatch ContextMatch;
     193             :     typedef void Setter;
     194             :     typedef void EncodingCallback;
     195             :     typedef void ContextSwap;           // swap a context with another one
     196             :     typedef void SizeSetter;            // set the size of the element
     197             : };
     198             : 
     199             : struct ChoiceBase : public ElementBase {
     200             :     typedef void ContextStorer; // store the context data on pop.
     201             : };
     202             : 
     203             : class SequenceBase : public ElementBase {
     204             : public:
     205             :     static const int kMinOccurs = 1;
     206             :     static const int kMaxOccurs = 1;
     207             :     typedef void ContextStorer; // store the context data on pop.
     208             : };
     209             : 
     210             : #include "base/proto_impl.h"
     211             : 
     212             : template<class Derived>
     213             : class ProtoElement : public ElementBase {
     214             : public:
     215             :     typedef void SequenceLength;
     216             : 
     217             :     template <typename T>
     218     6944272 :     static void Writer(T *msg, uint8_t *data, size_t size) {
     219             :         typedef typename Derived::Setter setter_t;
     220             :         typedef typename mpl::if_<
     221             :             mpl::equal_to<
     222             :                 mpl::int_<Derived::kSize>, mpl::int_<-1> >,
     223             :             detail::VariableLengthWriter<typename Derived::Setter, T>,
     224             :             detail::ApplyGetter<setter_t>
     225             :         >::type writer_t;
     226             :         writer_t writer;
     227     6944272 :         writer(data, Derived::kSize, msg);
     228     6944490 :     }
     229             : 
     230             :     template <typename T>
     231     5752385 :     static int Parse(const uint8_t *data, size_t size, ParseContext *context,
     232             :                      T *obj) {
     233             :         typedef typename mpl::if_<
     234             :             mpl::greater<
     235             :                 mpl::int_<Derived::kSize>, mpl::int_<0> >,
     236             :             detail::SizeComparer<Derived>,
     237             :             detail::NopComparer
     238             :         >::type cmp_t;
     239             : 
     240             :         cmp_t cmp;
     241     5752385 :         if (!cmp(size)) {
     242           8 :             PROTO_DEBUG("Error: cmp(size) failed");
     243           8 :             context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
     244             :                     TYPE_NAME(Derived), data,
     245           0 :                     Derived::kSize > 0 ? Derived::kSize : context->size());
     246           8 :             return -1;
     247             :         }
     248     5752378 :         if (!Derived::Verifier(obj, data, size, context)) {
     249        4240 :             PROTO_DEBUG(TYPE_NAME(Derived) << " Verifier failed");
     250        4240 :             context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
     251             :                     TYPE_NAME(Derived), data,
     252         109 :                     Derived::kSize > 0 ? Derived::kSize : context->size());
     253        4240 :             return -1;
     254             :         }
     255             : 
     256             :         typedef typename Derived::ContextInit ctx_init_t;
     257             :         ctx_init_t initializer;
     258     5748128 :         initializer(obj);
     259             : 
     260             :         detail::SequenceLengthSetter<typename Derived::SequenceLength, T> slen;
     261     5748122 :         int res = slen(context, data, Derived::kSize, size, obj);
     262     5748090 :         if (res < 0) {
     263         163 :             PROTO_DEBUG(TYPE_NAME(Derived) << ": error: Length Setter failed");
     264         163 :             context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
     265             :                               TYPE_NAME(Derived), data, context->lensize());
     266         163 :             return -1;
     267             :         }
     268             : 
     269             :         typedef typename mpl::if_<boost::is_same<typename Derived::SizeSetter, void>,
     270             :             typename mpl::if_<
     271             :                 mpl::equal_to<mpl::int_<Derived::kSize>, mpl::int_<-1> >,
     272             :                 detail::VariableLengthSetter<typename Derived::Setter, T>,
     273             :                 typename mpl::if_<
     274             :                     mpl::greater<mpl::int_<Derived::kSize>, mpl::int_<0> >,
     275             :                     detail::FixedLengthSetter<Derived, T>,
     276             :                     detail::NopSetter<Derived, T>
     277             :                 >::type
     278             :             >::type,
     279             :             detail::LengthSizeSetter<typename Derived::SizeSetter, T>
     280             :         >::type setter_t;
     281             : 
     282             :         setter_t setter;
     283     5747927 :         res = setter(data, size, context, obj);
     284     5748017 :         if (res < 0) {
     285           2 :             context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
     286             :                     TYPE_NAME(Derived), data,
     287           0 :                     Derived::kSize > 0 ? Derived::kSize : context->size());
     288             :         }
     289     5748020 :         return res;
     290             :     }
     291             : 
     292             :     template <typename T>
     293     7281671 :     static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
     294             :                       size_t size) {
     295             :         typedef typename
     296             :             mpl::if_<boost::is_same<typename Derived::SizeSetter, void>,
     297             :             typename mpl::if_<mpl::equal_to<mpl::int_<Derived::kSize>, mpl::int_<-1> >,
     298             :                      detail::VarLengthSizeValue<typename Derived::Setter, T>,
     299             :                      detail::FixedLengthSizeValue<Derived> >::type,
     300             :             typename Derived::SizeSetter
     301             :         >::type size_value_t;
     302             : 
     303     7281671 :         int element_size = size_value_t::get(msg);
     304     7281879 :         if (data == NULL) {
     305           8 :             context->advance(element_size);
     306           0 :             return element_size;
     307             :         }
     308     7281894 :         assert(element_size >= 0);
     309     7281894 :         if (size < (size_t) element_size) {
     310         175 :             return -1;
     311             :         }
     312             : 
     313             :         // Setter overrides SequenceLength. Do not register a sequence length
     314             :         // callback if the element has defined a Setter.
     315             :         typename mpl::if_<
     316             :             boost::is_same<typename Derived::Setter, void>,
     317             :             detail::SequenceLengthAddCallback<typename Derived::SequenceLength>,
     318             :             detail::SequenceLengthAddCallback<void> >::type slen;
     319     7281719 :         slen(&ProtoElement::SequenceLengthWriteLen, context, data, element_size);
     320             : 
     321             :         detail::AddCallback<typename Derived::EncodingCallback> cbadd;
     322     7281625 :         cbadd(context, data, element_size);
     323             : 
     324     7281647 :         detail::SaveOffset<typename Derived::SaveOffset>()(context);
     325             : 
     326     7281741 :         Derived::Writer(msg, data, size);
     327             : 
     328     7281873 :         context->advance(element_size);
     329     7281491 :         return element_size;
     330             :     }
     331             : 
     332             : private:
     333     1584885 :     static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
     334             :                                        int offset, int element_size) {
     335     1584885 :         int length = context->length() - offset - element_size;
     336     1584835 :         put_value(data, element_size, length);
     337     1584797 :     }
     338             : };
     339             : 
     340             : template <typename Setter, typename T>
     341             : struct ChoiceSetter {
     342      790019 :     void operator()(T *obj, int &value) {
     343      790019 :         Setter::set(obj, value);
     344      790017 :     }
     345             : };
     346             : 
     347             : template <typename T>
     348             : struct ChoiceSetter<void, T> {
     349      198862 :     void operator()(T* obj, int value) { }
     350             : };
     351             : 
     352             : template <class Derived>
     353             : class ProtoChoice : public ChoiceBase {
     354             : public:
     355             :     template <typename T>
     356      988876 :     static int Parse(const uint8_t *data, size_t size, ParseContext *context,
     357             :                      T *obj) {
     358      988876 :         int advance = Derived::kSize;
     359      988876 :         int value = -1;
     360             : 
     361      988876 :         if (size < (size_t) advance) {
     362           0 :             context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
     363             :                               TYPE_NAME(Derived), data, advance);
     364           0 :             return -1;
     365             :         }
     366             : 
     367      988876 :         value = get_value(data, advance);
     368             : 
     369      988873 :         data += advance;
     370      988873 :         size -= advance;
     371      988873 :         context->advance(advance);
     372             : 
     373             :         typedef typename mpl::if_<
     374             :             boost::is_same<typename Derived::Setter, void>,
     375             :             ChoiceSetter<void, T>,
     376             :             ChoiceSetter<typename Derived::Setter, T>
     377             :         >::type choice_setter_t;
     378             : 
     379             :         choice_setter_t setter;
     380      988882 :         setter(obj, value);
     381             : 
     382      988879 :         int result = ParseChoice(data, size, value, context, obj);
     383      988839 :         if (result < 0) {
     384        4188 :             PROTO_DEBUG(TYPE_NAME(Derived) << " ParseChoice failed");
     385        4188 :             if (result == -2) {
     386          45 :                 context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
     387          45 :                               TYPE_NAME(Derived), data - advance, advance);
     388             :             }
     389        4188 :             return result;
     390             :         }
     391      984651 :         advance += result;
     392      984651 :         return advance;
     393             :     }
     394             : 
     395             :     template <typename T>
     396     1070659 :     static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
     397             :                       size_t size) {
     398             :         typedef typename Derived::Choice choice_t;
     399     1070659 :         int result = 0;
     400     1070659 :         ChoiceEncoder<T> encoder(context, msg, data, size, &result);
     401     1070835 :         mpl::for_each<choice_t>(encoder);
     402     1071090 :         return result;
     403             :     }
     404             : 
     405             : private:
     406             :     template <typename T>
     407             :     struct ChoiceMatcher {
     408      988874 :         ChoiceMatcher(const uint8_t *data, size_t size, int value,
     409             :                       ParseContext *context, T *obj, int *resultp)
     410      988874 :             : data(data), size(size), value(value), context(context),
     411      988874 :               obj(obj), resultp(resultp), found(false) {
     412      988874 :         }
     413             :         template <typename U>
     414    14630330 :         void operator()(U x) {
     415    14630330 :             if (found) return;
     416     5768867 :             if (U::first::value != -1 && U::first::value != value) {
     417     4782660 :                 return;
     418             :             }
     419      988788 :             found = true;
     420             :             typedef detail::DescendentParser<Derived, typename U::second>
     421             :                 parser_t;
     422      988788 :             *resultp = parser_t::Parse(data, size, context, obj);
     423             :         }
     424             :         const uint8_t *data;
     425             :         size_t size;
     426             :         int value;
     427             :         ParseContext *context;
     428             :         T *obj;
     429             :         int *resultp;
     430             :         bool found;
     431             :     };
     432             :     template <typename T>
     433      988877 :     static int ParseChoice(const uint8_t *data, size_t size, int value,
     434             :                            ParseContext *context, T *obj) {
     435      988877 :         int result = -2;
     436      988877 :         ChoiceMatcher<T> match(data, size, value, context, obj, &result);
     437      988876 :         mpl::for_each<typename Derived::Choice>(match);
     438      988846 :         return result;
     439             :     }
     440             : 
     441             :     template <typename T>
     442             :     struct ChoiceEncoder {
     443     1070820 :         ChoiceEncoder(EncodeContext *context, const T *msg, uint8_t *data, int size,
     444             :                       int *resultp)
     445     1070820 :             : context(context), msg(msg), data(data), size(size),
     446     1070820 :             resultp(resultp), found(false) {
     447     1070820 :         }
     448             :         template <typename U, typename CtxType>
     449             :         struct EncoderTrue {
     450     1071195 :             int operator()(int opt, EncodeContext *context, const CtxType *msg,
     451             :                            uint8_t *data, int size) {
     452             :                 if (Derived::kSize) {
     453      898968 :                     if (data != NULL) {
     454      898976 :                         if (size < Derived::kSize) return -1;
     455      898976 :                         put_value(data, Derived::kSize, opt);
     456      898995 :                         data += Derived::kSize;
     457      898995 :                         size -= Derived::kSize;
     458             :                     }
     459      898987 :                     context->advance(Derived::kSize);
     460             :                 }
     461     1071121 :                 int result = U::Encode(context, msg, data, size);
     462     1071247 :                 if (result >= 0) {
     463     1070907 :                     result += Derived::kSize;
     464             :                 }
     465     1071247 :                 return result;
     466             :             }
     467             :         };
     468             :         template <typename U, typename CtxType>
     469             :         struct EncoderSetter {
     470      733814 :             int operator()(int opt, EncodeContext *context, const CtxType *msg,
     471             :                     uint8_t *data, int size) {
     472      733814 :                 int value = Derived::Setter::get(msg);
     473      733827 :                 if (value == opt || opt == -1) {
     474      677121 :                     return EncoderTrue<U, CtxType>()(value, context, msg, data, size);
     475             :                 }
     476       56706 :                 return 0;
     477             :             }
     478             :         };
     479             :         template <typename U>
     480             :         struct EncoderMatch {
     481      251224 :             int operator()(int opt, EncodeContext *context, const T *msg,
     482             :                            uint8_t *data, int size) {
     483             :                 typename U::ContextMatch matcher;
     484      251224 :                 if (matcher.match(msg)) {
     485      181729 :                     return EncoderTrue<U, T>()(opt, context, msg, data, size);
     486             :                 }
     487       69490 :                 return 0;
     488             :             }
     489             :         };
     490             :         template <typename U>
     491             :         struct EncoderRunTime {
     492     6040821 :             int operator()(int opt, EncodeContext *context, const T *msg,
     493             :                            uint8_t *data, int size) {
     494     6040821 :                 if (typeid(*msg) == typeid(typename U::ContextType)) {
     495             :                     typedef typename U::ContextType ctx_t;
     496      946024 :                     const ctx_t *ctx = static_cast<const ctx_t *>(msg);
     497             : 
     498             :                     typedef typename mpl::if_<
     499             :                         boost::is_same<typename Derived::Setter, void>,
     500             :                         EncoderTrue<U, ctx_t>,
     501             :                         EncoderSetter<U, ctx_t>
     502             :                     >::type encoder;
     503      946024 :                     return encoder()(opt, context, ctx, data, size);
     504             :                 }
     505     5094909 :                 return 0;
     506             :             }
     507             :         };
     508             :         struct EncoderNil {
     509             :             int operator()(int opt, EncodeContext *context, T *msg,
     510             :                            uint8_t *data, int size) {
     511             :                 return 0;
     512             :             }
     513             :         };
     514             :         template <typename U>
     515    15764948 :         void operator()(U x) {
     516    15764948 :             if (*resultp < 0 || found) {
     517     9472747 :                 return;
     518             :             }
     519             :             // The choice element can be determined by:
     520             :             // 1. ContextType of the descendent or
     521             :             // 2. ContextMatch type of the descendent
     522             :             // In the case of ContextType match, the match can be either
     523             :             // performed at compile type (in case of exact match) or at run
     524             :             // type using RTTI.
     525             :             typedef typename mpl::if_<
     526             :                 boost::is_same<typename U::second::ContextType, T>,
     527             :                 EncoderTrue<typename U::second, T>,
     528             :                 typename mpl::if_<
     529             :                     boost::is_same<typename U::second::ContextType, void>,
     530             :                     EncoderMatch<typename U::second>,
     531             :                     typename mpl::if_<
     532             :                         boost::is_base_of<T, typename U::second::ContextType>,
     533             :                           EncoderRunTime<typename U::second>,
     534             :                           EncoderNil
     535             :                         >::type
     536             :                     >::type
     537             :             >::type choice_t;
     538             :             choice_t choice;
     539     6292232 :             int result = choice(U::first::value, context, msg, data, size);
     540     6292303 :             if (result < 0) {
     541         334 :                 *resultp = result;
     542     6291969 :             } else if (result > 0) {
     543     1057942 :                 found = true;
     544     1057942 :                 *resultp += result;
     545             :             }
     546             :         }
     547             :     private:
     548             :         EncodeContext *context;
     549             :         const T *msg;
     550             :         uint8_t *data;
     551             :         int size;
     552             :         int *resultp;
     553             :         bool found;
     554             :     };
     555             : };
     556             : 
     557             : template <class Derived>
     558             : class ProtoSequence : public SequenceBase {
     559             : public:
     560             :     template <typename T>
     561             :     struct SequenceParser {
     562     3277131 :         SequenceParser(const uint8_t *data, size_t size, ParseContext *context,
     563             :             T *obj, int *resultp)
     564     3277131 :             : data(data), size(size), context(context), obj(obj),
     565     3277131 :               resultp(resultp) {
     566     3277131 :         }
     567             : 
     568             :         template <typename U>
     569     7881898 :         void operator()(U x) {
     570     7881898 :             if (*resultp < 0) {
     571        9007 :                 return;
     572             :             }
     573             :             typedef detail::DescendentParser<Derived, U> parser_t;
     574     7872891 :             size_t prev_size = context->size();
     575     7872850 :             int result = parser_t::Parse(data, size, context, obj);
     576     7872874 :             if (result < 0) {
     577       12393 :                 *resultp = result;
     578       12393 :                 return;
     579             :             }
     580             : 
     581     7860481 :             data += result;
     582     7860481 :             size -= result;
     583     7860481 :             context->advance(result);
     584     7860496 :             *resultp += result;
     585             : 
     586     7860496 :             if (context->size() != prev_size) {
     587     2778389 :                 size = context->size();
     588     2778437 :                 context->set_total_size();
     589             :             } else {
     590     5082065 :                 context->set_size(prev_size - result);
     591             :             }
     592             :         }
     593             : 
     594             :         const uint8_t *data;
     595             :         size_t size;
     596             :         ParseContext *context;
     597             :         T *obj;
     598             :         int *resultp;
     599             :     };
     600             : 
     601             :     template <typename T>
     602     2317023 :     static int Parse(const uint8_t *data, size_t size, ParseContext *context,
     603             :                      T *obj) {
     604     2317023 :         int min = Derived::kMinOccurs;
     605     2317023 :         if (min == 0 && size == 0) {
     606      206557 :             return 0;
     607             :         }
     608     2110466 :         if (!Derived::Verifier(obj, data, size, context)) {
     609          48 :             PROTO_DEBUG(TYPE_NAME(Derived) << " Verifier failed");
     610          48 :             context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
     611             :                     TYPE_NAME(Derived), data,
     612          48 :                     Derived::kSize > 0 ? Derived::kSize : context->size());
     613          48 :             return -1;
     614             :         }
     615     2110423 :         int lensize = Derived::kSize;
     616     2110423 :         int length = size;
     617     2110423 :         if (lensize) {
     618      361525 :             if (size < (size_t) lensize) {
     619           0 :                 PROTO_DEBUG("Error: size = " << size << " lensize = " << lensize);
     620           0 :                 context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
     621             :                                   TYPE_NAME(Derived), data, lensize);
     622           0 :                 return -1;
     623             :             }
     624             :             // TODO: options for length (include or exclude length field).
     625      361525 :             length = get_value(data, lensize);
     626      361527 :             assert(length >= 0);
     627      361525 :             size -= lensize;
     628      361525 :             if ((size_t) length > size) {
     629        3036 :                 PROTO_DEBUG("Error: length = " << length << " size = " << size);
     630        3036 :                 context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
     631             :                                   TYPE_NAME(Derived), data, lensize);
     632        3036 :                 return -1;
     633             :             }
     634      358489 :             data += lensize;
     635      358489 :             context->advance(lensize);
     636             :         }
     637     2107371 :         int result = lensize;
     638     2107371 :         int max = Derived::kMaxOccurs;
     639     5372025 :         for (int i = 0; (max == -1 || i < max) && (length > 0); i++) {
     640     3277087 :             int sublen = 0;
     641             :             typedef typename Derived::ContextStorer ctx_access_t;
     642             :             typedef typename
     643             :             detail::ContextElementType<ctx_access_t>::ValueType child_obj_t;
     644             :             typedef typename mpl::if_<boost::is_same<typename Derived::ContextSwap, void>,
     645             :                     detail::ContextPush<T, child_obj_t>,
     646             :                     detail::NoContextPush<T>
     647             :             >::type ContextPush;
     648             :             ContextPush pushfn;
     649             :             typedef typename mpl::if_<boost::is_same<child_obj_t, void>,
     650             :                         T, child_obj_t>::type ctx_t;
     651     3277087 :             ctx_t *child_obj = pushfn(context, obj);
     652             : 
     653     3277131 :             SequenceParser<ctx_t> parser(data, length, context, child_obj, &sublen);
     654     3277138 :             mpl::for_each<typename Derived::Sequence>(parser);
     655     3277085 :             if (sublen < 0) {
     656       12393 :                 PROTO_DEBUG(TYPE_NAME(Derived) << ": error: sublen " << sublen);
     657       12393 :                 return -1;
     658             :             }
     659     3264692 :             if (sublen < (int)(context->size() + context->lensize())) {
     660           0 :                 PROTO_DEBUG(TYPE_NAME(Derived) << ": error: sublen " << sublen
     661             :                         << " < " << context->size() << "+" << context->lensize());
     662           0 :                 context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
     663             :                         TYPE_NAME(Derived), data,
     664           0 :                         context->size()+context->lensize());
     665           0 :                 return -1;
     666             :             }
     667     3264707 :             result += sublen;
     668     3264707 :             data += sublen;
     669     3264707 :             length -= sublen;
     670             : 
     671             :             typedef typename mpl::if_<boost::is_same<typename Derived::ContextSwap, void>,
     672             :                     detail::ContextPop<Derived, T, child_obj_t>,
     673             :                     detail::ContextPop<Derived, void, void>
     674             :             >::type ContextPop;
     675             :             ContextPop popfn;
     676     3264707 :             popfn(context, obj);
     677             :         }
     678     2094938 :         return result;
     679             :     }
     680             : 
     681             :     template <typename T>
     682             :     struct SingleEncoder {
     683             :         typedef typename Derived::Sequence sequence_t;
     684     1773443 :         int operator()(EncodeContext *context, const T *msg, uint8_t *data,
     685             :                        size_t size) {
     686     1773443 :             int result = 0;
     687     1773443 :             SequenceEncoder<T> encoder(context, msg, data, size, &result);
     688     1773470 :             mpl::for_each<sequence_t>(encoder);
     689     1773507 :             return result;
     690             :         }
     691             :     };
     692             : 
     693             :     template <typename T>
     694             :     struct ListEncoder {
     695             :         typedef typename Derived::Sequence sequence_t;
     696      960425 :         int operator()(EncodeContext *context, const T *msg, uint8_t *data,
     697             :                        size_t size) {
     698             :             typedef typename Derived::ContextStorer ctx_access_t;
     699             :             typedef typename
     700             :             detail::ContextElementType<ctx_access_t>::ValueType child_obj_t;
     701      960425 :             int result = 0;
     702             : 
     703      960425 :             detail::ContextIterator<ctx_access_t> iter(msg);
     704     3292318 :             while (iter.HasNext(msg)) {
     705     2332058 :                 child_obj_t *child_obj = iter.Next();
     706     2332042 :                 int subres = 0;
     707     2332042 :                 context->Push();
     708     2332046 :                 SequenceEncoder<child_obj_t> encoder(context, child_obj,
     709             :                                                      data, size, &subres);
     710     2332041 :                 mpl::for_each<sequence_t>(encoder);
     711     2332163 :                 if (subres < 0) {
     712         223 :                     result = subres;
     713         223 :                     break;
     714             :                 }
     715     2331940 :                 result += subres;
     716     2331940 :                 if (data != NULL) {
     717     2331959 :                     data += subres;
     718     2331959 :                     size -= subres;
     719             :                 }
     720     2331940 :                 context->Pop(data != NULL);
     721             :             }
     722      960382 :             return result;
     723             :         }
     724             :     };
     725             : 
     726             :     template <typename T>
     727     2733754 :     static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
     728             :                       size_t size) {
     729     2733754 :         context->Push();
     730     2733956 :         detail::SaveOffset<typename Derived::SaveOffset>()(context);
     731             :         if (Derived::kSize > 0) {
     732             :             // context push callback
     733      395821 :             if (data != NULL) {
     734      395821 :                 context->AddCallback(&SequenceLengthWriteLen, data, Derived::kSize);
     735      395741 :                 data += Derived::kSize;
     736      395741 :                 size -= Derived::kSize;
     737             :             }
     738      395741 :             context->advance(Derived::kSize);
     739             :         }
     740             :         typedef typename mpl::if_<
     741             :             mpl::or_<
     742             :                 mpl::equal_to<mpl::int_<Derived::kMaxOccurs>,
     743             :                               mpl::int_<-1> >,
     744             :                 mpl::greater<mpl::int_<Derived::kMaxOccurs>,
     745             :                              mpl::int_<1> >
     746             :                 >,
     747             :             ListEncoder<T>,
     748             :             SingleEncoder<T> >::type encoder_t;
     749             :         encoder_t encoder;
     750     2733973 :         int result = encoder(context, msg, data, size);
     751     2734012 :         if (result >= 0) {
     752     2733328 :             result += Derived::kSize;
     753     2733328 :             context->Pop(data != NULL);
     754             :         }
     755     2734110 :         return result;
     756             :     }
     757             : 
     758             : private:
     759             :     template <typename T>
     760             :     struct SequenceEncoder {
     761     4105471 :         SequenceEncoder(EncodeContext *context, const T *msg, uint8_t *data,
     762             :                         size_t size, int *resultp)
     763     4105471 :         : context(context), msg(msg), data(data), size(size),
     764     4105471 :           resultp(resultp) {
     765     4105471 :         }
     766             :         template <typename U>
     767     9739685 :         void operator()(U element) {
     768     9739685 :             if (*resultp < 0) {
     769         241 :                 return;
     770             :             }
     771     9739444 :             int res = U::Encode(context, msg, data, size);
     772     9739751 :             if (res < 0) {
     773         734 :                 *resultp = res;
     774             :             } else {
     775     9739017 :                 *resultp += res;
     776             :             }
     777     9739751 :             if (data != NULL) {
     778     9739781 :                 data += res;
     779     9739781 :                 size -= res;
     780             :             }
     781             :         }
     782             : 
     783             :     private:
     784             :         EncodeContext *context;
     785             :         const T *msg;
     786             :         uint8_t *data;
     787             :         size_t size;
     788             :         int *resultp;
     789             :     };
     790             : 
     791      395617 :     static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
     792             :                                        int offset, int arg) {
     793      395617 :         int length = context->length() - Derived::kSize;
     794      395609 :         put_value(data, Derived::kSize, length);
     795      395607 :     }
     796             : };
     797             : 
     798             : #endif

Generated by: LCOV version 1.14