• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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