DCCL v4
field_codec_message_stack.cpp
1 // Copyright 2011-2023:
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 // File authors:
6 // Toby Schneider <toby@gobysoft.org>
7 //
8 //
9 // This file is part of the Dynamic Compact Control Language Library
10 // ("DCCL").
11 //
12 // DCCL is free software: you can redistribute it and/or modify
13 // it under the terms of the GNU Lesser General Public License as published by
14 // the Free Software Foundation, either version 2.1 of the License, or
15 // (at your option) any later version.
16 //
17 // DCCL is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU Lesser General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public License
23 // along with DCCL. If not, see <http://www.gnu.org/licenses/>.
24 #include "field_codec_message_stack.h"
25 #include "../field_codec.h"
26 
27 // MessageStack
28 //
29 
30 void dccl::internal::MessageStack::push(const google::protobuf::Descriptor* desc)
31 
32 {
33  data_.desc.push_back(desc);
34  ++descriptors_pushed_;
35 }
36 
37 void dccl::internal::MessageStack::push(const google::protobuf::FieldDescriptor* field)
38 {
39  data_.field.push_back(field);
40  ++fields_pushed_;
41 }
42 
43 void dccl::internal::MessageStack::push(MessagePart part)
44 {
45  data_.parts.push_back(part);
46  ++parts_pushed_;
47 }
48 
49 void dccl::internal::MessageStack::__pop_desc()
50 {
51  if (!data_.desc.empty())
52  data_.desc.pop_back();
53  --descriptors_pushed_;
54 }
55 
56 void dccl::internal::MessageStack::__pop_field()
57 {
58  if (!data_.field.empty())
59  data_.field.pop_back();
60  --fields_pushed_;
61 }
62 
63 void dccl::internal::MessageStack::__pop_parts()
64 {
65  if (!data_.parts.empty())
66  data_.parts.pop_back();
67  --parts_pushed_;
68 }
69 
70 void dccl::internal::MessageStack::__pop_messages()
71 {
72  if (!data_.messages.empty())
73  data_.messages.pop_back();
74  --messages_pushed_;
75 }
76 
77 dccl::internal::MessageStack::MessageStack(const google::protobuf::Message* root_message,
78  MessageStackData& data,
79  const google::protobuf::FieldDescriptor* field)
80  : data_(data), descriptors_pushed_(0), fields_pushed_(0), parts_pushed_(0), messages_pushed_(0)
81 {
82  if (field)
83  {
84  if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
85  {
86  MessagePart part = UNKNOWN;
87  if (field->options().GetExtension(dccl::field).has_in_head())
88  {
89  // if explicitly set, set part (HEAD or BODY) of message for all children of this message
90  part = field->options().GetExtension(dccl::field).in_head() ? HEAD : BODY;
91  }
92  else
93  {
94  // use the parent's current part
95  part = current_part();
96  }
97  push(part);
98  push(field->message_type());
99  }
100  push_message(root_message, field);
101  push(field);
102  }
103 }
104 
105 void dccl::internal::MessageStack::update_index(const google::protobuf::Message* root_message,
106  const google::protobuf::FieldDescriptor* field,
107  int index)
108 {
109  push_message(root_message, field, index);
110 }
111 
112 void dccl::internal::MessageStack::push_message(const google::protobuf::Message* root_message,
113  const google::protobuf::FieldDescriptor* field,
114  int index)
115 {
116  if (data_.messages.empty() && root_message)
117  {
118  data_.messages.push_back({root_message, nullptr});
119  ++messages_pushed_;
120  }
121 
122  if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
123  {
124  // replace if the previous push was the same field
125  if (!data_.messages.empty() && field == data_.messages.back().field &&
126  !data_.messages.empty())
127  {
128  data_.messages.pop_back();
129  --messages_pushed_;
130  }
131 
132  // add the new message + field if possible
133  if (data_.messages.size() &&
134  data_.messages.back().msg->GetDescriptor() == field->containing_type())
135  {
136  const auto* refl = data_.messages.back().msg->GetReflection();
137  if (field->is_repeated())
138  {
139  if (index >= 0 && index < refl->FieldSize(*data_.messages.back().msg, field))
140  {
141  data_.messages.push_back(
142  {&refl->GetRepeatedMessage(*data_.messages.back().msg, field, index),
143  field});
144  ++messages_pushed_;
145  }
146  }
147  else
148  {
149  data_.messages.push_back(
150  {&refl->GetMessage(*data_.messages.back().msg, field), field});
151  ++messages_pushed_;
152  }
153  }
154  }
155 }
156 
157 dccl::internal::MessageStack::~MessageStack()
158 {
159  while (fields_pushed_ > 0) __pop_field();
160  while (descriptors_pushed_ > 0) __pop_desc();
161  while (parts_pushed_ > 0) __pop_parts();
162  while (messages_pushed_ > 0) __pop_messages();
163 }
Message
dccl::FieldCodecBase::part
MessagePart part()
the part of the message currently being encoded (head or body)
Definition: field_codec.cpp:698