1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Author: anuraag@google.com (Anuraag Agrawal)
32 // Author: tibell@google.com (Johan Tibell)
33
34 #include <google/protobuf/pyext/repeated_scalar_container.h>
35
36 #include <cstdint>
37 #include <memory>
38
39 #include <google/protobuf/stubs/common.h>
40 #include <google/protobuf/stubs/logging.h>
41 #include <google/protobuf/descriptor.h>
42 #include <google/protobuf/dynamic_message.h>
43 #include <google/protobuf/message.h>
44 #include <google/protobuf/pyext/descriptor.h>
45 #include <google/protobuf/pyext/descriptor_pool.h>
46 #include <google/protobuf/pyext/message.h>
47 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
48
49 #define PyString_AsString(ob) \
50 (PyUnicode_Check(ob) ? PyUnicode_AsUTF8(ob) : PyBytes_AsString(ob))
51
52 namespace google {
53 namespace protobuf {
54 namespace python {
55
56 namespace repeated_scalar_container {
57
InternalAssignRepeatedField(RepeatedScalarContainer * self,PyObject * list)58 static int InternalAssignRepeatedField(RepeatedScalarContainer* self,
59 PyObject* list) {
60 Message* message = self->parent->message;
61 message->GetReflection()->ClearField(message, self->parent_field_descriptor);
62 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(list); ++i) {
63 PyObject* value = PyList_GET_ITEM(list, i);
64 if (ScopedPyObjectPtr(Append(self, value)) == nullptr) {
65 return -1;
66 }
67 }
68 return 0;
69 }
70
Len(PyObject * pself)71 static Py_ssize_t Len(PyObject* pself) {
72 RepeatedScalarContainer* self =
73 reinterpret_cast<RepeatedScalarContainer*>(pself);
74 Message* message = self->parent->message;
75 return message->GetReflection()->FieldSize(*message,
76 self->parent_field_descriptor);
77 }
78
AssignItem(PyObject * pself,Py_ssize_t index,PyObject * arg)79 static int AssignItem(PyObject* pself, Py_ssize_t index, PyObject* arg) {
80 RepeatedScalarContainer* self =
81 reinterpret_cast<RepeatedScalarContainer*>(pself);
82
83 cmessage::AssureWritable(self->parent);
84 Message* message = self->parent->message;
85 const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
86
87 const Reflection* reflection = message->GetReflection();
88 int field_size = reflection->FieldSize(*message, field_descriptor);
89 if (index < 0) {
90 index = field_size + index;
91 }
92 if (index < 0 || index >= field_size) {
93 PyErr_Format(PyExc_IndexError, "list assignment index (%d) out of range",
94 static_cast<int>(index));
95 return -1;
96 }
97
98 if (arg == nullptr) {
99 ScopedPyObjectPtr py_index(PyLong_FromLong(index));
100 return cmessage::DeleteRepeatedField(self->parent, field_descriptor,
101 py_index.get());
102 }
103
104 if (PySequence_Check(arg) && !(PyBytes_Check(arg) || PyUnicode_Check(arg))) {
105 PyErr_SetString(PyExc_TypeError, "Value must be scalar");
106 return -1;
107 }
108
109 switch (field_descriptor->cpp_type()) {
110 case FieldDescriptor::CPPTYPE_INT32: {
111 GOOGLE_CHECK_GET_INT32(arg, value, -1);
112 reflection->SetRepeatedInt32(message, field_descriptor, index, value);
113 break;
114 }
115 case FieldDescriptor::CPPTYPE_INT64: {
116 GOOGLE_CHECK_GET_INT64(arg, value, -1);
117 reflection->SetRepeatedInt64(message, field_descriptor, index, value);
118 break;
119 }
120 case FieldDescriptor::CPPTYPE_UINT32: {
121 GOOGLE_CHECK_GET_UINT32(arg, value, -1);
122 reflection->SetRepeatedUInt32(message, field_descriptor, index, value);
123 break;
124 }
125 case FieldDescriptor::CPPTYPE_UINT64: {
126 GOOGLE_CHECK_GET_UINT64(arg, value, -1);
127 reflection->SetRepeatedUInt64(message, field_descriptor, index, value);
128 break;
129 }
130 case FieldDescriptor::CPPTYPE_FLOAT: {
131 GOOGLE_CHECK_GET_FLOAT(arg, value, -1);
132 reflection->SetRepeatedFloat(message, field_descriptor, index, value);
133 break;
134 }
135 case FieldDescriptor::CPPTYPE_DOUBLE: {
136 GOOGLE_CHECK_GET_DOUBLE(arg, value, -1);
137 reflection->SetRepeatedDouble(message, field_descriptor, index, value);
138 break;
139 }
140 case FieldDescriptor::CPPTYPE_BOOL: {
141 GOOGLE_CHECK_GET_BOOL(arg, value, -1);
142 reflection->SetRepeatedBool(message, field_descriptor, index, value);
143 break;
144 }
145 case FieldDescriptor::CPPTYPE_STRING: {
146 if (!CheckAndSetString(arg, message, field_descriptor, reflection, false,
147 index)) {
148 return -1;
149 }
150 break;
151 }
152 case FieldDescriptor::CPPTYPE_ENUM: {
153 GOOGLE_CHECK_GET_INT32(arg, value, -1);
154 if (reflection->SupportsUnknownEnumValues()) {
155 reflection->SetRepeatedEnumValue(message, field_descriptor, index,
156 value);
157 } else {
158 const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
159 const EnumValueDescriptor* enum_value =
160 enum_descriptor->FindValueByNumber(value);
161 if (enum_value != nullptr) {
162 reflection->SetRepeatedEnum(message, field_descriptor, index,
163 enum_value);
164 } else {
165 ScopedPyObjectPtr s(PyObject_Str(arg));
166 if (s != nullptr) {
167 PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
168 PyString_AsString(s.get()));
169 }
170 return -1;
171 }
172 }
173 break;
174 }
175 default:
176 PyErr_Format(PyExc_SystemError,
177 "Adding value to a field of unknown type %d",
178 field_descriptor->cpp_type());
179 return -1;
180 }
181 return 0;
182 }
183
Item(PyObject * pself,Py_ssize_t index)184 static PyObject* Item(PyObject* pself, Py_ssize_t index) {
185 RepeatedScalarContainer* self =
186 reinterpret_cast<RepeatedScalarContainer*>(pself);
187
188 Message* message = self->parent->message;
189 const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
190 const Reflection* reflection = message->GetReflection();
191
192 int field_size = reflection->FieldSize(*message, field_descriptor);
193 if (index < 0) {
194 index = field_size + index;
195 }
196 if (index < 0 || index >= field_size) {
197 PyErr_Format(PyExc_IndexError, "list index (%zd) out of range", index);
198 return nullptr;
199 }
200
201 PyObject* result = nullptr;
202 switch (field_descriptor->cpp_type()) {
203 case FieldDescriptor::CPPTYPE_INT32: {
204 int32_t value =
205 reflection->GetRepeatedInt32(*message, field_descriptor, index);
206 result = PyLong_FromLong(value);
207 break;
208 }
209 case FieldDescriptor::CPPTYPE_INT64: {
210 int64_t value =
211 reflection->GetRepeatedInt64(*message, field_descriptor, index);
212 result = PyLong_FromLongLong(value);
213 break;
214 }
215 case FieldDescriptor::CPPTYPE_UINT32: {
216 uint32_t value =
217 reflection->GetRepeatedUInt32(*message, field_descriptor, index);
218 result = PyLong_FromLongLong(value);
219 break;
220 }
221 case FieldDescriptor::CPPTYPE_UINT64: {
222 uint64_t value =
223 reflection->GetRepeatedUInt64(*message, field_descriptor, index);
224 result = PyLong_FromUnsignedLongLong(value);
225 break;
226 }
227 case FieldDescriptor::CPPTYPE_FLOAT: {
228 float value =
229 reflection->GetRepeatedFloat(*message, field_descriptor, index);
230 result = PyFloat_FromDouble(value);
231 break;
232 }
233 case FieldDescriptor::CPPTYPE_DOUBLE: {
234 double value =
235 reflection->GetRepeatedDouble(*message, field_descriptor, index);
236 result = PyFloat_FromDouble(value);
237 break;
238 }
239 case FieldDescriptor::CPPTYPE_BOOL: {
240 bool value =
241 reflection->GetRepeatedBool(*message, field_descriptor, index);
242 result = PyBool_FromLong(value ? 1 : 0);
243 break;
244 }
245 case FieldDescriptor::CPPTYPE_ENUM: {
246 const EnumValueDescriptor* enum_value =
247 message->GetReflection()->GetRepeatedEnum(*message, field_descriptor,
248 index);
249 result = PyLong_FromLong(enum_value->number());
250 break;
251 }
252 case FieldDescriptor::CPPTYPE_STRING: {
253 std::string scratch;
254 const std::string& value = reflection->GetRepeatedStringReference(
255 *message, field_descriptor, index, &scratch);
256 result = ToStringObject(field_descriptor, value);
257 break;
258 }
259 default:
260 PyErr_Format(PyExc_SystemError,
261 "Getting value from a repeated field of unknown type %d",
262 field_descriptor->cpp_type());
263 }
264
265 return result;
266 }
267
Subscript(PyObject * pself,PyObject * slice)268 static PyObject* Subscript(PyObject* pself, PyObject* slice) {
269 Py_ssize_t from;
270 Py_ssize_t to;
271 Py_ssize_t step;
272 Py_ssize_t length;
273 Py_ssize_t slicelength;
274 bool return_list = false;
275 if (PyLong_Check(slice)) {
276 from = to = PyLong_AsLong(slice);
277 } else if (PyIndex_Check(slice)) {
278 from = to = PyNumber_AsSsize_t(slice, PyExc_ValueError);
279 if (from == -1 && PyErr_Occurred()) {
280 return nullptr;
281 }
282 } else if (PySlice_Check(slice)) {
283 length = Len(pself);
284 if (PySlice_GetIndicesEx(slice, length, &from, &to, &step, &slicelength) ==
285 -1) {
286 return nullptr;
287 }
288 return_list = true;
289 } else {
290 PyErr_SetString(PyExc_TypeError, "list indices must be integers");
291 return nullptr;
292 }
293
294 if (!return_list) {
295 return Item(pself, from);
296 }
297
298 PyObject* list = PyList_New(0);
299 if (list == nullptr) {
300 return nullptr;
301 }
302 if (from <= to) {
303 if (step < 0) {
304 return list;
305 }
306 for (Py_ssize_t index = from; index < to; index += step) {
307 if (index < 0 || index >= length) {
308 break;
309 }
310 ScopedPyObjectPtr s(Item(pself, index));
311 PyList_Append(list, s.get());
312 }
313 } else {
314 if (step > 0) {
315 return list;
316 }
317 for (Py_ssize_t index = from; index > to; index += step) {
318 if (index < 0 || index >= length) {
319 break;
320 }
321 ScopedPyObjectPtr s(Item(pself, index));
322 PyList_Append(list, s.get());
323 }
324 }
325 return list;
326 }
327
Append(RepeatedScalarContainer * self,PyObject * item)328 PyObject* Append(RepeatedScalarContainer* self, PyObject* item) {
329 cmessage::AssureWritable(self->parent);
330 Message* message = self->parent->message;
331 const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
332
333 const Reflection* reflection = message->GetReflection();
334 switch (field_descriptor->cpp_type()) {
335 case FieldDescriptor::CPPTYPE_INT32: {
336 GOOGLE_CHECK_GET_INT32(item, value, nullptr);
337 reflection->AddInt32(message, field_descriptor, value);
338 break;
339 }
340 case FieldDescriptor::CPPTYPE_INT64: {
341 GOOGLE_CHECK_GET_INT64(item, value, nullptr);
342 reflection->AddInt64(message, field_descriptor, value);
343 break;
344 }
345 case FieldDescriptor::CPPTYPE_UINT32: {
346 GOOGLE_CHECK_GET_UINT32(item, value, nullptr);
347 reflection->AddUInt32(message, field_descriptor, value);
348 break;
349 }
350 case FieldDescriptor::CPPTYPE_UINT64: {
351 GOOGLE_CHECK_GET_UINT64(item, value, nullptr);
352 reflection->AddUInt64(message, field_descriptor, value);
353 break;
354 }
355 case FieldDescriptor::CPPTYPE_FLOAT: {
356 GOOGLE_CHECK_GET_FLOAT(item, value, nullptr);
357 reflection->AddFloat(message, field_descriptor, value);
358 break;
359 }
360 case FieldDescriptor::CPPTYPE_DOUBLE: {
361 GOOGLE_CHECK_GET_DOUBLE(item, value, nullptr);
362 reflection->AddDouble(message, field_descriptor, value);
363 break;
364 }
365 case FieldDescriptor::CPPTYPE_BOOL: {
366 GOOGLE_CHECK_GET_BOOL(item, value, nullptr);
367 reflection->AddBool(message, field_descriptor, value);
368 break;
369 }
370 case FieldDescriptor::CPPTYPE_STRING: {
371 if (!CheckAndSetString(item, message, field_descriptor, reflection, true,
372 -1)) {
373 return nullptr;
374 }
375 break;
376 }
377 case FieldDescriptor::CPPTYPE_ENUM: {
378 GOOGLE_CHECK_GET_INT32(item, value, nullptr);
379 if (reflection->SupportsUnknownEnumValues()) {
380 reflection->AddEnumValue(message, field_descriptor, value);
381 } else {
382 const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
383 const EnumValueDescriptor* enum_value =
384 enum_descriptor->FindValueByNumber(value);
385 if (enum_value != nullptr) {
386 reflection->AddEnum(message, field_descriptor, enum_value);
387 } else {
388 ScopedPyObjectPtr s(PyObject_Str(item));
389 if (s != nullptr) {
390 PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
391 PyString_AsString(s.get()));
392 }
393 return nullptr;
394 }
395 }
396 break;
397 }
398 default:
399 PyErr_Format(PyExc_SystemError,
400 "Adding value to a field of unknown type %d",
401 field_descriptor->cpp_type());
402 return nullptr;
403 }
404
405 Py_RETURN_NONE;
406 }
407
AppendMethod(PyObject * self,PyObject * item)408 static PyObject* AppendMethod(PyObject* self, PyObject* item) {
409 return Append(reinterpret_cast<RepeatedScalarContainer*>(self), item);
410 }
411
AssSubscript(PyObject * pself,PyObject * slice,PyObject * value)412 static int AssSubscript(PyObject* pself, PyObject* slice, PyObject* value) {
413 RepeatedScalarContainer* self =
414 reinterpret_cast<RepeatedScalarContainer*>(pself);
415
416 Py_ssize_t from;
417 Py_ssize_t to;
418 Py_ssize_t step;
419 Py_ssize_t length;
420 Py_ssize_t slicelength;
421 bool create_list = false;
422
423 cmessage::AssureWritable(self->parent);
424 Message* message = self->parent->message;
425 const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
426
427 if (PyLong_Check(slice)) {
428 from = to = PyLong_AsLong(slice);
429 } else if (PySlice_Check(slice)) {
430 const Reflection* reflection = message->GetReflection();
431 length = reflection->FieldSize(*message, field_descriptor);
432 if (PySlice_GetIndicesEx(slice, length, &from, &to, &step, &slicelength) ==
433 -1) {
434 return -1;
435 }
436 create_list = true;
437 } else {
438 PyErr_SetString(PyExc_TypeError, "list indices must be integers");
439 return -1;
440 }
441
442 if (value == nullptr) {
443 return cmessage::DeleteRepeatedField(self->parent, field_descriptor, slice);
444 }
445
446 if (!create_list) {
447 return AssignItem(pself, from, value);
448 }
449
450 ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
451 if (full_slice == nullptr) {
452 return -1;
453 }
454 ScopedPyObjectPtr new_list(Subscript(pself, full_slice.get()));
455 if (new_list == nullptr) {
456 return -1;
457 }
458 if (PySequence_SetSlice(new_list.get(), from, to, value) < 0) {
459 return -1;
460 }
461
462 return InternalAssignRepeatedField(self, new_list.get());
463 }
464
Extend(RepeatedScalarContainer * self,PyObject * value)465 PyObject* Extend(RepeatedScalarContainer* self, PyObject* value) {
466 cmessage::AssureWritable(self->parent);
467
468 // TODO(ptucker): Deprecate this behavior. b/18413862
469 if (value == Py_None) {
470 Py_RETURN_NONE;
471 }
472 if ((Py_TYPE(value)->tp_as_sequence == nullptr) && PyObject_Not(value)) {
473 Py_RETURN_NONE;
474 }
475
476 ScopedPyObjectPtr iter(PyObject_GetIter(value));
477 if (iter == nullptr) {
478 PyErr_SetString(PyExc_TypeError, "Value must be iterable");
479 return nullptr;
480 }
481 ScopedPyObjectPtr next;
482 while ((next.reset(PyIter_Next(iter.get()))) != nullptr) {
483 if (ScopedPyObjectPtr(Append(self, next.get())) == nullptr) {
484 return nullptr;
485 }
486 }
487 if (PyErr_Occurred()) {
488 return nullptr;
489 }
490 Py_RETURN_NONE;
491 }
492
Insert(PyObject * pself,PyObject * args)493 static PyObject* Insert(PyObject* pself, PyObject* args) {
494 RepeatedScalarContainer* self =
495 reinterpret_cast<RepeatedScalarContainer*>(pself);
496
497 Py_ssize_t index;
498 PyObject* value;
499 if (!PyArg_ParseTuple(args, "lO", &index, &value)) {
500 return nullptr;
501 }
502 ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
503 ScopedPyObjectPtr new_list(Subscript(pself, full_slice.get()));
504 if (PyList_Insert(new_list.get(), index, value) < 0) {
505 return nullptr;
506 }
507 int ret = InternalAssignRepeatedField(self, new_list.get());
508 if (ret < 0) {
509 return nullptr;
510 }
511 Py_RETURN_NONE;
512 }
513
Remove(PyObject * pself,PyObject * value)514 static PyObject* Remove(PyObject* pself, PyObject* value) {
515 Py_ssize_t match_index = -1;
516 for (Py_ssize_t i = 0; i < Len(pself); ++i) {
517 ScopedPyObjectPtr elem(Item(pself, i));
518 if (PyObject_RichCompareBool(elem.get(), value, Py_EQ)) {
519 match_index = i;
520 break;
521 }
522 }
523 if (match_index == -1) {
524 PyErr_SetString(PyExc_ValueError, "remove(x): x not in container");
525 return nullptr;
526 }
527 if (AssignItem(pself, match_index, nullptr) < 0) {
528 return nullptr;
529 }
530 Py_RETURN_NONE;
531 }
532
ExtendMethod(PyObject * self,PyObject * value)533 static PyObject* ExtendMethod(PyObject* self, PyObject* value) {
534 return Extend(reinterpret_cast<RepeatedScalarContainer*>(self), value);
535 }
536
RichCompare(PyObject * pself,PyObject * other,int opid)537 static PyObject* RichCompare(PyObject* pself, PyObject* other, int opid) {
538 if (opid != Py_EQ && opid != Py_NE) {
539 Py_INCREF(Py_NotImplemented);
540 return Py_NotImplemented;
541 }
542
543 // Copy the contents of this repeated scalar container, and other if it is
544 // also a repeated scalar container, into Python lists so we can delegate
545 // to the list's compare method.
546
547 ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
548 if (full_slice == nullptr) {
549 return nullptr;
550 }
551
552 ScopedPyObjectPtr other_list_deleter;
553 if (PyObject_TypeCheck(other, &RepeatedScalarContainer_Type)) {
554 other_list_deleter.reset(Subscript(other, full_slice.get()));
555 other = other_list_deleter.get();
556 }
557
558 ScopedPyObjectPtr list(Subscript(pself, full_slice.get()));
559 if (list == nullptr) {
560 return nullptr;
561 }
562 return PyObject_RichCompare(list.get(), other, opid);
563 }
564
Reduce(PyObject * unused_self,PyObject * unused_other)565 PyObject* Reduce(PyObject* unused_self, PyObject* unused_other) {
566 PyErr_Format(PickleError_class,
567 "can't pickle repeated message fields, convert to list first");
568 return nullptr;
569 }
570
Sort(PyObject * pself,PyObject * args,PyObject * kwds)571 static PyObject* Sort(PyObject* pself, PyObject* args, PyObject* kwds) {
572 // Support the old sort_function argument for backwards
573 // compatibility.
574 if (kwds != nullptr) {
575 PyObject* sort_func = PyDict_GetItemString(kwds, "sort_function");
576 if (sort_func != nullptr) {
577 // Must set before deleting as sort_func is a borrowed reference
578 // and kwds might be the only thing keeping it alive.
579 if (PyDict_SetItemString(kwds, "cmp", sort_func) == -1) return nullptr;
580 if (PyDict_DelItemString(kwds, "sort_function") == -1) return nullptr;
581 }
582 }
583
584 ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
585 if (full_slice == nullptr) {
586 return nullptr;
587 }
588 ScopedPyObjectPtr list(Subscript(pself, full_slice.get()));
589 if (list == nullptr) {
590 return nullptr;
591 }
592 ScopedPyObjectPtr m(PyObject_GetAttrString(list.get(), "sort"));
593 if (m == nullptr) {
594 return nullptr;
595 }
596 ScopedPyObjectPtr res(PyObject_Call(m.get(), args, kwds));
597 if (res == nullptr) {
598 return nullptr;
599 }
600 int ret = InternalAssignRepeatedField(
601 reinterpret_cast<RepeatedScalarContainer*>(pself), list.get());
602 if (ret < 0) {
603 return nullptr;
604 }
605 Py_RETURN_NONE;
606 }
607
Reverse(PyObject * pself)608 static PyObject* Reverse(PyObject* pself) {
609 ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
610 if (full_slice == nullptr) {
611 return nullptr;
612 }
613 ScopedPyObjectPtr list(Subscript(pself, full_slice.get()));
614 if (list == nullptr) {
615 return nullptr;
616 }
617 ScopedPyObjectPtr res(PyObject_CallMethod(list.get(), "reverse", nullptr));
618 if (res == nullptr) {
619 return nullptr;
620 }
621 int ret = InternalAssignRepeatedField(
622 reinterpret_cast<RepeatedScalarContainer*>(pself), list.get());
623 if (ret < 0) {
624 return nullptr;
625 }
626 Py_RETURN_NONE;
627 }
628
Pop(PyObject * pself,PyObject * args)629 static PyObject* Pop(PyObject* pself, PyObject* args) {
630 Py_ssize_t index = -1;
631 if (!PyArg_ParseTuple(args, "|n", &index)) {
632 return nullptr;
633 }
634 PyObject* item = Item(pself, index);
635 if (item == nullptr) {
636 PyErr_Format(PyExc_IndexError, "list index (%zd) out of range", index);
637 return nullptr;
638 }
639 if (AssignItem(pself, index, nullptr) < 0) {
640 return nullptr;
641 }
642 return item;
643 }
644
ToStr(PyObject * pself)645 static PyObject* ToStr(PyObject* pself) {
646 ScopedPyObjectPtr full_slice(PySlice_New(nullptr, nullptr, nullptr));
647 if (full_slice == nullptr) {
648 return nullptr;
649 }
650 ScopedPyObjectPtr list(Subscript(pself, full_slice.get()));
651 if (list == nullptr) {
652 return nullptr;
653 }
654 return PyObject_Repr(list.get());
655 }
656
MergeFrom(PyObject * pself,PyObject * arg)657 static PyObject* MergeFrom(PyObject* pself, PyObject* arg) {
658 return Extend(reinterpret_cast<RepeatedScalarContainer*>(pself), arg);
659 }
660
661 // The private constructor of RepeatedScalarContainer objects.
NewContainer(CMessage * parent,const FieldDescriptor * parent_field_descriptor)662 RepeatedScalarContainer* NewContainer(
663 CMessage* parent, const FieldDescriptor* parent_field_descriptor) {
664 if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
665 return nullptr;
666 }
667
668 RepeatedScalarContainer* self = reinterpret_cast<RepeatedScalarContainer*>(
669 PyType_GenericAlloc(&RepeatedScalarContainer_Type, 0));
670 if (self == nullptr) {
671 return nullptr;
672 }
673
674 Py_INCREF(parent);
675 self->parent = parent;
676 self->parent_field_descriptor = parent_field_descriptor;
677
678 return self;
679 }
680
DeepCopy(PyObject * pself,PyObject * arg)681 PyObject* DeepCopy(PyObject* pself, PyObject* arg) {
682 return reinterpret_cast<RepeatedScalarContainer*>(pself)->DeepCopy();
683 }
684
Dealloc(PyObject * pself)685 static void Dealloc(PyObject* pself) {
686 reinterpret_cast<RepeatedScalarContainer*>(pself)->RemoveFromParentCache();
687 Py_TYPE(pself)->tp_free(pself);
688 }
689
690 static PySequenceMethods SqMethods = {
691 Len, /* sq_length */
692 nullptr, /* sq_concat */
693 nullptr, /* sq_repeat */
694 Item, /* sq_item */
695 nullptr, /* sq_slice */
696 AssignItem /* sq_ass_item */
697 };
698
699 static PyMappingMethods MpMethods = {
700 Len, /* mp_length */
701 Subscript, /* mp_subscript */
702 AssSubscript, /* mp_ass_subscript */
703 };
704
705 static PyMethodDef Methods[] = {
706 {"__deepcopy__", DeepCopy, METH_VARARGS, "Makes a deep copy of the class."},
707 {"__reduce__", Reduce, METH_NOARGS,
708 "Outputs picklable representation of the repeated field."},
709 {"append", AppendMethod, METH_O,
710 "Appends an object to the repeated container."},
711 {"extend", ExtendMethod, METH_O,
712 "Appends objects to the repeated container."},
713 {"insert", Insert, METH_VARARGS,
714 "Inserts an object at the specified position in the container."},
715 {"pop", Pop, METH_VARARGS,
716 "Removes an object from the repeated container and returns it."},
717 {"remove", Remove, METH_O,
718 "Removes an object from the repeated container."},
719 {"sort", reinterpret_cast<PyCFunction>(Sort), METH_VARARGS | METH_KEYWORDS,
720 "Sorts the repeated container."},
721 {"reverse", reinterpret_cast<PyCFunction>(Reverse), METH_NOARGS,
722 "Reverses elements order of the repeated container."},
723 {"MergeFrom", static_cast<PyCFunction>(MergeFrom), METH_O,
724 "Merges a repeated container into the current container."},
725 {nullptr, nullptr}};
726
727 } // namespace repeated_scalar_container
728
729 PyTypeObject RepeatedScalarContainer_Type = {
730 PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
731 ".RepeatedScalarContainer", // tp_name
732 sizeof(RepeatedScalarContainer), // tp_basicsize
733 0, // tp_itemsize
734 repeated_scalar_container::Dealloc, // tp_dealloc
735 #if PY_VERSION_HEX >= 0x03080000
736 0, // tp_vectorcall_offset
737 #else
738 nullptr, // tp_print
739 #endif
740 nullptr, // tp_getattr
741 nullptr, // tp_setattr
742 nullptr, // tp_compare
743 repeated_scalar_container::ToStr, // tp_repr
744 nullptr, // tp_as_number
745 &repeated_scalar_container::SqMethods, // tp_as_sequence
746 &repeated_scalar_container::MpMethods, // tp_as_mapping
747 PyObject_HashNotImplemented, // tp_hash
748 nullptr, // tp_call
749 nullptr, // tp_str
750 nullptr, // tp_getattro
751 nullptr, // tp_setattro
752 nullptr, // tp_as_buffer
753 Py_TPFLAGS_DEFAULT, // tp_flags
754 "A Repeated scalar container", // tp_doc
755 nullptr, // tp_traverse
756 nullptr, // tp_clear
757 repeated_scalar_container::RichCompare, // tp_richcompare
758 0, // tp_weaklistoffset
759 nullptr, // tp_iter
760 nullptr, // tp_iternext
761 repeated_scalar_container::Methods, // tp_methods
762 nullptr, // tp_members
763 nullptr, // tp_getset
764 nullptr, // tp_base
765 nullptr, // tp_dict
766 nullptr, // tp_descr_get
767 nullptr, // tp_descr_set
768 0, // tp_dictoffset
769 nullptr, // tp_init
770 };
771
772 } // namespace python
773 } // namespace protobuf
774 } // namespace google
775