1 /*
2  * Copyright (c) 2009-2021, Google LLC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of Google LLC nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include "protos_generator/gen_repeated_fields.h"
28 
29 #include <string>
30 #include <vector>
31 
32 #include "google/protobuf/descriptor.pb.h"
33 #include "google/protobuf/descriptor.h"
34 #include "protos_generator/gen_accessors.h"
35 #include "protos_generator/gen_enums.h"
36 #include "protos_generator/gen_extensions.h"
37 #include "protos_generator/gen_utils.h"
38 #include "protos_generator/output.h"
39 #include "upbc/common.h"
40 #include "upbc/file_layout.h"
41 
42 namespace protos_generator {
43 namespace protobuf = ::google::protobuf;
44 
45 // Adds using accessors to reuse base Access class members from a Proxy/CProxy.
WriteRepeatedFieldUsingAccessors(const protobuf::FieldDescriptor * field,absl::string_view class_name,absl::string_view resolved_field_name,Output & output,bool read_only)46 void WriteRepeatedFieldUsingAccessors(const protobuf::FieldDescriptor* field,
47                                       absl::string_view class_name,
48                                       absl::string_view resolved_field_name,
49                                       Output& output, bool read_only) {
50   if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
51     output(
52         R"cc(
53           using $0Access::$1;
54           using $0Access::$1_size;
55           using $0Access::mutable_$1;
56         )cc",
57         class_name, resolved_field_name);
58     if (!read_only) {
59       output(
60           R"cc(
61             using $0Access::add_$1;
62             using $0Access::clear_$1;
63           )cc",
64           class_name, resolved_field_name);
65     }
66   } else {
67     output(
68         R"cc(
69           using $0Access::$1;
70           using $0Access::$1_size;
71         )cc",
72         class_name, resolved_field_name);
73     if (!read_only) {
74       output(
75           R"cc(
76             using $0Access::add_$1;
77             using $0Access::clear_$1;
78             using $0Access::resize_$1;
79             using $0Access::set_$1;
80           )cc",
81           class_name, resolved_field_name);
82     }
83   }
84 }
85 
WriteRepeatedFieldsInMessageHeader(const protobuf::Descriptor * desc,const protobuf::FieldDescriptor * field,absl::string_view resolved_field_name,absl::string_view resolved_upbc_name,Output & output)86 void WriteRepeatedFieldsInMessageHeader(const protobuf::Descriptor* desc,
87                                         const protobuf::FieldDescriptor* field,
88                                         absl::string_view resolved_field_name,
89                                         absl::string_view resolved_upbc_name,
90                                         Output& output) {
91   output(
92       R"cc(
93         inline size_t $1_size() const {
94           size_t len;
95           $0_$2(msg_, &len);
96           return len;
97         }
98 
99         inline void clear_$1() { $0_clear_$2(msg_); }
100       )cc",
101       MessageName(desc), resolved_field_name, resolved_upbc_name);
102 
103   if (field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
104     output(
105         R"cc(
106           $1 $2(size_t index) const;
107           absl::StatusOr<$0> add_$2();
108           $0 mutable_$2(size_t index) const;
109         )cc",
110         MessagePtrConstType(field, /* const */ false),
111         MessagePtrConstType(field, /* const */ true), resolved_field_name,
112         resolved_upbc_name);
113   } else {
114     output(
115         R"cc(
116           $0 $1(size_t index) const;
117           bool add_$1($0 val);
118           void set_$1(size_t index, $0 val);
119           bool resize_$1(size_t len);
120         )cc",
121         CppConstType(field), resolved_field_name);
122   }
123 }
124 
WriteRepeatedMessageAccessor(const protobuf::Descriptor * message,const protobuf::FieldDescriptor * field,const absl::string_view resolved_field_name,const absl::string_view class_name,Output & output)125 void WriteRepeatedMessageAccessor(const protobuf::Descriptor* message,
126                                   const protobuf::FieldDescriptor* field,
127                                   const absl::string_view resolved_field_name,
128                                   const absl::string_view class_name,
129                                   Output& output) {
130   const char arena_expression[] = "arena_";
131   absl::string_view upbc_name = field->name();
132   output(
133       R"cc(
134         $1 $0::$2(size_t index) const {
135           size_t len;
136           auto* ptr = $3_$5(msg_, &len);
137           assert(index < len);
138           return ::protos::internal::CreateMessage<$4>((upb_Message*)*(ptr + index));
139         }
140       )cc",
141       class_name, MessagePtrConstType(field, /* is_const */ true),
142       resolved_field_name, MessageName(message),
143       MessageBaseType(field, /* maybe_const */ false), upbc_name);
144   output(
145       R"cc(
146         absl::StatusOr<$1> $0::add_$2() {
147           auto new_msg = $3_add_$6(msg_, $5);
148           if (!new_msg) {
149             return ::protos::MessageAllocationError();
150           }
151           return ::protos::internal::CreateMessageProxy<$4>((upb_Message*)new_msg, $5);
152         }
153       )cc",
154       class_name, MessagePtrConstType(field, /* const */ false),
155       resolved_field_name, MessageName(message),
156       MessageBaseType(field, /* maybe_const */ false), arena_expression,
157       upbc_name);
158   output(
159       R"cc(
160         $1 $0::mutable_$2(size_t index) const {
161           size_t len;
162           auto* ptr = $3_$6(msg_, &len);
163           assert(index < len);
164           return ::protos::internal::CreateMessageProxy<$4>(
165               (upb_Message*)*(ptr + index), $5);
166         }
167       )cc",
168       class_name, MessagePtrConstType(field, /* is_const */ false),
169       resolved_field_name, MessageName(message),
170       MessageBaseType(field, /* maybe_const */ false), arena_expression,
171       upbc_name);
172 }
173 
WriteRepeatedStringAccessor(const protobuf::Descriptor * message,const protobuf::FieldDescriptor * field,const absl::string_view resolved_field_name,const absl::string_view class_name,Output & output)174 void WriteRepeatedStringAccessor(const protobuf::Descriptor* message,
175                                  const protobuf::FieldDescriptor* field,
176                                  const absl::string_view resolved_field_name,
177                                  const absl::string_view class_name,
178                                  Output& output) {
179   absl::string_view upbc_name = field->name();
180   output(
181       R"cc(
182         $1 $0::$2(size_t index) const {
183           size_t len;
184           auto* ptr = $3_mutable_$4(msg_, &len);
185           assert(index < len);
186           return ::protos::UpbStrToStringView(*(ptr + index));
187         }
188       )cc",
189       class_name, CppConstType(field), resolved_field_name,
190       MessageName(message), upbc_name);
191   output(
192       R"cc(
193         bool $0::resize_$1(size_t len) {
194           return $2_resize_$3(msg_, len, arena_);
195         }
196       )cc",
197       class_name, resolved_field_name, MessageName(message), upbc_name);
198   output(
199       R"cc(
200         bool $0::add_$2($1 val) {
201           return $3_add_$4(msg_, ::protos::UpbStrFromStringView(val, arena_), arena_);
202         }
203       )cc",
204       class_name, CppConstType(field), resolved_field_name,
205       MessageName(message), upbc_name);
206   output(
207       R"cc(
208         void $0::set_$2(size_t index, $1 val) {
209           size_t len;
210           auto* ptr = $3_mutable_$4(msg_, &len);
211           assert(index < len);
212           *(ptr + index) = ::protos::UpbStrFromStringView(val, arena_);
213         }
214       )cc",
215       class_name, CppConstType(field), resolved_field_name,
216       MessageName(message), upbc_name);
217 }
218 
WriteRepeatedScalarAccessor(const protobuf::Descriptor * message,const protobuf::FieldDescriptor * field,const absl::string_view resolved_field_name,const absl::string_view class_name,Output & output)219 void WriteRepeatedScalarAccessor(const protobuf::Descriptor* message,
220                                  const protobuf::FieldDescriptor* field,
221                                  const absl::string_view resolved_field_name,
222                                  const absl::string_view class_name,
223                                  Output& output) {
224   absl::string_view upbc_name = field->name();
225   output(
226       R"cc(
227         $1 $0::$2(size_t index) const {
228           size_t len;
229           auto* ptr = $3_mutable_$4(msg_, &len);
230           assert(index < len);
231           return *(ptr + index);
232         }
233       )cc",
234       class_name, CppConstType(field), resolved_field_name,
235       MessageName(message), upbc_name);
236   output(
237       R"cc(
238         bool $0::resize_$1(size_t len) {
239           return $2_resize_$3(msg_, len, arena_);
240         }
241       )cc",
242       class_name, resolved_field_name, MessageName(message), upbc_name);
243   output(
244       R"cc(
245         bool $0::add_$2($1 val) { return $3_add_$4(msg_, val, arena_); }
246       )cc",
247       class_name, CppConstType(field), resolved_field_name,
248       MessageName(message), upbc_name);
249   output(
250       R"cc(
251         void $0::set_$2(size_t index, $1 val) {
252           size_t len;
253           auto* ptr = $3_mutable_$4(msg_, &len);
254           assert(index < len);
255           *(ptr + index) = val;
256         }
257       )cc",
258       class_name, CppConstType(field), resolved_field_name,
259       MessageName(message), upbc_name);
260 }
261 
262 }  // namespace protos_generator
263