• 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 <memory>
37 #ifndef _SHARED_PTR_H
38 #include <google/protobuf/stubs/shared_ptr.h>
39 #endif
40 
41 #include <google/protobuf/stubs/common.h>
42 #include <google/protobuf/descriptor.h>
43 #include <google/protobuf/dynamic_message.h>
44 #include <google/protobuf/message.h>
45 #include <google/protobuf/pyext/descriptor.h>
46 #include <google/protobuf/pyext/message.h>
47 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
48 
49 #if PY_MAJOR_VERSION >= 3
50   #define PyInt_FromLong PyLong_FromLong
51   #if PY_VERSION_HEX < 0x03030000
52     #error "Python 3.0 - 3.2 are not supported."
53   #else
54   #define PyString_AsString(ob) \
55     (PyUnicode_Check(ob)? PyUnicode_AsUTF8(ob): PyBytes_AS_STRING(ob))
56   #endif
57 #endif
58 
59 namespace google {
60 namespace protobuf {
61 namespace python {
62 
63 extern google::protobuf::DynamicMessageFactory* global_message_factory;
64 
65 namespace repeated_scalar_container {
66 
InternalAssignRepeatedField(RepeatedScalarContainer * self,PyObject * list)67 static int InternalAssignRepeatedField(
68     RepeatedScalarContainer* self, PyObject* list) {
69   self->message->GetReflection()->ClearField(self->message,
70                                              self->parent_field->descriptor);
71   for (Py_ssize_t i = 0; i < PyList_GET_SIZE(list); ++i) {
72     PyObject* value = PyList_GET_ITEM(list, i);
73     if (Append(self, value) == NULL) {
74       return -1;
75     }
76   }
77   return 0;
78 }
79 
Len(RepeatedScalarContainer * self)80 static Py_ssize_t Len(RepeatedScalarContainer* self) {
81   google::protobuf::Message* message = self->message;
82   return message->GetReflection()->FieldSize(*message,
83                                              self->parent_field->descriptor);
84 }
85 
AssignItem(RepeatedScalarContainer * self,Py_ssize_t index,PyObject * arg)86 static int AssignItem(RepeatedScalarContainer* self,
87                       Py_ssize_t index,
88                       PyObject* arg) {
89   cmessage::AssureWritable(self->parent);
90   google::protobuf::Message* message = self->message;
91   const google::protobuf::FieldDescriptor* field_descriptor =
92       self->parent_field->descriptor;
93   if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
94     PyErr_SetString(
95         PyExc_KeyError, "Field does not belong to message!");
96     return -1;
97   }
98 
99   const google::protobuf::Reflection* reflection = message->GetReflection();
100   int field_size = reflection->FieldSize(*message, field_descriptor);
101   if (index < 0) {
102     index = field_size + index;
103   }
104   if (index < 0 || index >= field_size) {
105     PyErr_Format(PyExc_IndexError,
106                  "list assignment index (%d) out of range",
107                  static_cast<int>(index));
108     return -1;
109   }
110 
111   if (arg == NULL) {
112     ScopedPyObjectPtr py_index(PyLong_FromLong(index));
113     return cmessage::InternalDeleteRepeatedField(message, field_descriptor,
114                                                  py_index, NULL);
115   }
116 
117   if (PySequence_Check(arg) && !(PyBytes_Check(arg) || PyUnicode_Check(arg))) {
118     PyErr_SetString(PyExc_TypeError, "Value must be scalar");
119     return -1;
120   }
121 
122   switch (field_descriptor->cpp_type()) {
123     case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
124       GOOGLE_CHECK_GET_INT32(arg, value, -1);
125       reflection->SetRepeatedInt32(message, field_descriptor, index, value);
126       break;
127     }
128     case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
129       GOOGLE_CHECK_GET_INT64(arg, value, -1);
130       reflection->SetRepeatedInt64(message, field_descriptor, index, value);
131       break;
132     }
133     case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
134       GOOGLE_CHECK_GET_UINT32(arg, value, -1);
135       reflection->SetRepeatedUInt32(message, field_descriptor, index, value);
136       break;
137     }
138     case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
139       GOOGLE_CHECK_GET_UINT64(arg, value, -1);
140       reflection->SetRepeatedUInt64(message, field_descriptor, index, value);
141       break;
142     }
143     case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
144       GOOGLE_CHECK_GET_FLOAT(arg, value, -1);
145       reflection->SetRepeatedFloat(message, field_descriptor, index, value);
146       break;
147     }
148     case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
149       GOOGLE_CHECK_GET_DOUBLE(arg, value, -1);
150       reflection->SetRepeatedDouble(message, field_descriptor, index, value);
151       break;
152     }
153     case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
154       GOOGLE_CHECK_GET_BOOL(arg, value, -1);
155       reflection->SetRepeatedBool(message, field_descriptor, index, value);
156       break;
157     }
158     case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
159       if (!CheckAndSetString(
160           arg, message, field_descriptor, reflection, false, index)) {
161         return -1;
162       }
163       break;
164     }
165     case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
166       GOOGLE_CHECK_GET_INT32(arg, value, -1);
167       const google::protobuf::EnumDescriptor* enum_descriptor =
168           field_descriptor->enum_type();
169       const google::protobuf::EnumValueDescriptor* enum_value =
170           enum_descriptor->FindValueByNumber(value);
171       if (enum_value != NULL) {
172         reflection->SetRepeatedEnum(message, field_descriptor, index,
173                                     enum_value);
174       } else {
175         ScopedPyObjectPtr s(PyObject_Str(arg));
176         if (s != NULL) {
177           PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
178                        PyString_AsString(s.get()));
179         }
180         return -1;
181       }
182       break;
183     }
184     default:
185       PyErr_Format(
186           PyExc_SystemError, "Adding value to a field of unknown type %d",
187           field_descriptor->cpp_type());
188       return -1;
189   }
190   return 0;
191 }
192 
Item(RepeatedScalarContainer * self,Py_ssize_t index)193 static PyObject* Item(RepeatedScalarContainer* self, Py_ssize_t index) {
194   google::protobuf::Message* message = self->message;
195   const google::protobuf::FieldDescriptor* field_descriptor =
196       self->parent_field->descriptor;
197   const google::protobuf::Reflection* reflection = message->GetReflection();
198 
199   int field_size = reflection->FieldSize(*message, field_descriptor);
200   if (index < 0) {
201     index = field_size + index;
202   }
203   if (index < 0 || index >= field_size) {
204     PyErr_Format(PyExc_IndexError,
205                  "list assignment index (%d) out of range",
206                  static_cast<int>(index));
207     return NULL;
208   }
209 
210   PyObject* result = NULL;
211   switch (field_descriptor->cpp_type()) {
212     case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
213       int32 value = reflection->GetRepeatedInt32(
214           *message, field_descriptor, index);
215       result = PyInt_FromLong(value);
216       break;
217     }
218     case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
219       int64 value = reflection->GetRepeatedInt64(
220           *message, field_descriptor, index);
221       result = PyLong_FromLongLong(value);
222       break;
223     }
224     case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
225       uint32 value = reflection->GetRepeatedUInt32(
226           *message, field_descriptor, index);
227       result = PyLong_FromLongLong(value);
228       break;
229     }
230     case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
231       uint64 value = reflection->GetRepeatedUInt64(
232           *message, field_descriptor, index);
233       result = PyLong_FromUnsignedLongLong(value);
234       break;
235     }
236     case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
237       float value = reflection->GetRepeatedFloat(
238           *message, field_descriptor, index);
239       result = PyFloat_FromDouble(value);
240       break;
241     }
242     case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
243       double value = reflection->GetRepeatedDouble(
244           *message, field_descriptor, index);
245       result = PyFloat_FromDouble(value);
246       break;
247     }
248     case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
249       bool value = reflection->GetRepeatedBool(
250           *message, field_descriptor, index);
251       result = PyBool_FromLong(value ? 1 : 0);
252       break;
253     }
254     case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
255       const google::protobuf::EnumValueDescriptor* enum_value =
256           message->GetReflection()->GetRepeatedEnum(
257               *message, field_descriptor, index);
258       result = PyInt_FromLong(enum_value->number());
259       break;
260     }
261     case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
262       string value = reflection->GetRepeatedString(
263           *message, field_descriptor, index);
264       result = ToStringObject(field_descriptor, value);
265       break;
266     }
267     case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
268       PyObject* py_cmsg = PyObject_CallObject(reinterpret_cast<PyObject*>(
269           &CMessage_Type), NULL);
270       if (py_cmsg == NULL) {
271         return NULL;
272       }
273       CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
274       const google::protobuf::Message& msg = reflection->GetRepeatedMessage(
275           *message, field_descriptor, index);
276       cmsg->owner = self->owner;
277       cmsg->parent = self->parent;
278       cmsg->message = const_cast<google::protobuf::Message*>(&msg);
279       cmsg->read_only = false;
280       result = reinterpret_cast<PyObject*>(py_cmsg);
281       break;
282     }
283     default:
284       PyErr_Format(
285           PyExc_SystemError,
286           "Getting value from a repeated field of unknown type %d",
287           field_descriptor->cpp_type());
288   }
289 
290   return result;
291 }
292 
Subscript(RepeatedScalarContainer * self,PyObject * slice)293 static PyObject* Subscript(RepeatedScalarContainer* self, PyObject* slice) {
294   Py_ssize_t from;
295   Py_ssize_t to;
296   Py_ssize_t step;
297   Py_ssize_t length;
298   Py_ssize_t slicelength;
299   bool return_list = false;
300 #if PY_MAJOR_VERSION < 3
301   if (PyInt_Check(slice)) {
302     from = to = PyInt_AsLong(slice);
303   } else  // NOLINT
304 #endif
305   if (PyLong_Check(slice)) {
306     from = to = PyLong_AsLong(slice);
307   } else if (PySlice_Check(slice)) {
308     length = Len(self);
309 #if PY_MAJOR_VERSION >= 3
310     if (PySlice_GetIndicesEx(slice,
311 #else
312     if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice),
313 #endif
314                              length, &from, &to, &step, &slicelength) == -1) {
315       return NULL;
316     }
317     return_list = true;
318   } else {
319     PyErr_SetString(PyExc_TypeError, "list indices must be integers");
320     return NULL;
321   }
322 
323   if (!return_list) {
324     return Item(self, from);
325   }
326 
327   PyObject* list = PyList_New(0);
328   if (list == NULL) {
329     return NULL;
330   }
331   if (from <= to) {
332     if (step < 0) {
333       return list;
334     }
335     for (Py_ssize_t index = from; index < to; index += step) {
336       if (index < 0 || index >= length) {
337         break;
338       }
339       ScopedPyObjectPtr s(Item(self, index));
340       PyList_Append(list, s);
341     }
342   } else {
343     if (step > 0) {
344       return list;
345     }
346     for (Py_ssize_t index = from; index > to; index += step) {
347       if (index < 0 || index >= length) {
348         break;
349       }
350       ScopedPyObjectPtr s(Item(self, index));
351       PyList_Append(list, s);
352     }
353   }
354   return list;
355 }
356 
Append(RepeatedScalarContainer * self,PyObject * item)357 PyObject* Append(RepeatedScalarContainer* self, PyObject* item) {
358   cmessage::AssureWritable(self->parent);
359   google::protobuf::Message* message = self->message;
360   const google::protobuf::FieldDescriptor* field_descriptor =
361       self->parent_field->descriptor;
362 
363   if (!FIELD_BELONGS_TO_MESSAGE(field_descriptor, message)) {
364     PyErr_SetString(
365         PyExc_KeyError, "Field does not belong to message!");
366     return NULL;
367   }
368 
369   const google::protobuf::Reflection* reflection = message->GetReflection();
370   switch (field_descriptor->cpp_type()) {
371     case google::protobuf::FieldDescriptor::CPPTYPE_INT32: {
372       GOOGLE_CHECK_GET_INT32(item, value, NULL);
373       reflection->AddInt32(message, field_descriptor, value);
374       break;
375     }
376     case google::protobuf::FieldDescriptor::CPPTYPE_INT64: {
377       GOOGLE_CHECK_GET_INT64(item, value, NULL);
378       reflection->AddInt64(message, field_descriptor, value);
379       break;
380     }
381     case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: {
382       GOOGLE_CHECK_GET_UINT32(item, value, NULL);
383       reflection->AddUInt32(message, field_descriptor, value);
384       break;
385     }
386     case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: {
387       GOOGLE_CHECK_GET_UINT64(item, value, NULL);
388       reflection->AddUInt64(message, field_descriptor, value);
389       break;
390     }
391     case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: {
392       GOOGLE_CHECK_GET_FLOAT(item, value, NULL);
393       reflection->AddFloat(message, field_descriptor, value);
394       break;
395     }
396     case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: {
397       GOOGLE_CHECK_GET_DOUBLE(item, value, NULL);
398       reflection->AddDouble(message, field_descriptor, value);
399       break;
400     }
401     case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: {
402       GOOGLE_CHECK_GET_BOOL(item, value, NULL);
403       reflection->AddBool(message, field_descriptor, value);
404       break;
405     }
406     case google::protobuf::FieldDescriptor::CPPTYPE_STRING: {
407       if (!CheckAndSetString(
408           item, message, field_descriptor, reflection, true, -1)) {
409         return NULL;
410       }
411       break;
412     }
413     case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: {
414       GOOGLE_CHECK_GET_INT32(item, value, NULL);
415       const google::protobuf::EnumDescriptor* enum_descriptor =
416           field_descriptor->enum_type();
417       const google::protobuf::EnumValueDescriptor* enum_value =
418           enum_descriptor->FindValueByNumber(value);
419       if (enum_value != NULL) {
420         reflection->AddEnum(message, field_descriptor, enum_value);
421       } else {
422         ScopedPyObjectPtr s(PyObject_Str(item));
423         if (s != NULL) {
424           PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
425                        PyString_AsString(s.get()));
426         }
427         return NULL;
428       }
429       break;
430     }
431     default:
432       PyErr_Format(
433           PyExc_SystemError, "Adding value to a field of unknown type %d",
434           field_descriptor->cpp_type());
435       return NULL;
436   }
437 
438   Py_RETURN_NONE;
439 }
440 
AssSubscript(RepeatedScalarContainer * self,PyObject * slice,PyObject * value)441 static int AssSubscript(RepeatedScalarContainer* self,
442                         PyObject* slice,
443                         PyObject* value) {
444   Py_ssize_t from;
445   Py_ssize_t to;
446   Py_ssize_t step;
447   Py_ssize_t length;
448   Py_ssize_t slicelength;
449   bool create_list = false;
450 
451   cmessage::AssureWritable(self->parent);
452   google::protobuf::Message* message = self->message;
453   const google::protobuf::FieldDescriptor* field_descriptor =
454       self->parent_field->descriptor;
455 
456 #if PY_MAJOR_VERSION < 3
457   if (PyInt_Check(slice)) {
458     from = to = PyInt_AsLong(slice);
459   } else
460 #endif
461   if (PyLong_Check(slice)) {
462     from = to = PyLong_AsLong(slice);
463   } else if (PySlice_Check(slice)) {
464     const google::protobuf::Reflection* reflection = message->GetReflection();
465     length = reflection->FieldSize(*message, field_descriptor);
466 #if PY_MAJOR_VERSION >= 3
467     if (PySlice_GetIndicesEx(slice,
468 #else
469     if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice),
470 #endif
471                              length, &from, &to, &step, &slicelength) == -1) {
472       return -1;
473     }
474     create_list = true;
475   } else {
476     PyErr_SetString(PyExc_TypeError, "list indices must be integers");
477     return -1;
478   }
479 
480   if (value == NULL) {
481     return cmessage::InternalDeleteRepeatedField(
482         message, field_descriptor, slice, NULL);
483   }
484 
485   if (!create_list) {
486     return AssignItem(self, from, value);
487   }
488 
489   ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
490   if (full_slice == NULL) {
491     return -1;
492   }
493   ScopedPyObjectPtr new_list(Subscript(self, full_slice));
494   if (new_list == NULL) {
495     return -1;
496   }
497   if (PySequence_SetSlice(new_list, from, to, value) < 0) {
498     return -1;
499   }
500 
501   return InternalAssignRepeatedField(self, new_list);
502 }
503 
Extend(RepeatedScalarContainer * self,PyObject * value)504 PyObject* Extend(RepeatedScalarContainer* self, PyObject* value) {
505   cmessage::AssureWritable(self->parent);
506   if (PyObject_Not(value)) {
507     Py_RETURN_NONE;
508   }
509   ScopedPyObjectPtr iter(PyObject_GetIter(value));
510   if (iter == NULL) {
511     PyErr_SetString(PyExc_TypeError, "Value must be iterable");
512     return NULL;
513   }
514   ScopedPyObjectPtr next;
515   while ((next.reset(PyIter_Next(iter))) != NULL) {
516     if (Append(self, next) == NULL) {
517       return NULL;
518     }
519   }
520   if (PyErr_Occurred()) {
521     return NULL;
522   }
523   Py_RETURN_NONE;
524 }
525 
Insert(RepeatedScalarContainer * self,PyObject * args)526 static PyObject* Insert(RepeatedScalarContainer* self, PyObject* args) {
527   Py_ssize_t index;
528   PyObject* value;
529   if (!PyArg_ParseTuple(args, "lO", &index, &value)) {
530     return NULL;
531   }
532   ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
533   ScopedPyObjectPtr new_list(Subscript(self, full_slice));
534   if (PyList_Insert(new_list, index, value) < 0) {
535     return NULL;
536   }
537   int ret = InternalAssignRepeatedField(self, new_list);
538   if (ret < 0) {
539     return NULL;
540   }
541   Py_RETURN_NONE;
542 }
543 
Remove(RepeatedScalarContainer * self,PyObject * value)544 static PyObject* Remove(RepeatedScalarContainer* self, PyObject* value) {
545   Py_ssize_t match_index = -1;
546   for (Py_ssize_t i = 0; i < Len(self); ++i) {
547     ScopedPyObjectPtr elem(Item(self, i));
548     if (PyObject_RichCompareBool(elem, value, Py_EQ)) {
549       match_index = i;
550       break;
551     }
552   }
553   if (match_index == -1) {
554     PyErr_SetString(PyExc_ValueError, "remove(x): x not in container");
555     return NULL;
556   }
557   if (AssignItem(self, match_index, NULL) < 0) {
558     return NULL;
559   }
560   Py_RETURN_NONE;
561 }
562 
RichCompare(RepeatedScalarContainer * self,PyObject * other,int opid)563 static PyObject* RichCompare(RepeatedScalarContainer* self,
564                              PyObject* other,
565                              int opid) {
566   if (opid != Py_EQ && opid != Py_NE) {
567     Py_INCREF(Py_NotImplemented);
568     return Py_NotImplemented;
569   }
570 
571   // Copy the contents of this repeated scalar container, and other if it is
572   // also a repeated scalar container, into Python lists so we can delegate
573   // to the list's compare method.
574 
575   ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
576   if (full_slice == NULL) {
577     return NULL;
578   }
579 
580   ScopedPyObjectPtr other_list_deleter;
581   if (PyObject_TypeCheck(other, &RepeatedScalarContainer_Type)) {
582     other_list_deleter.reset(Subscript(
583         reinterpret_cast<RepeatedScalarContainer*>(other), full_slice));
584     other = other_list_deleter.get();
585   }
586 
587   ScopedPyObjectPtr list(Subscript(self, full_slice));
588   if (list == NULL) {
589     return NULL;
590   }
591   return PyObject_RichCompare(list, other, opid);
592 }
593 
Reduce(RepeatedScalarContainer * unused_self)594 PyObject* Reduce(RepeatedScalarContainer* unused_self) {
595   PyErr_Format(
596       PickleError_class,
597       "can't pickle repeated message fields, convert to list first");
598   return NULL;
599 }
600 
Sort(RepeatedScalarContainer * self,PyObject * args,PyObject * kwds)601 static PyObject* Sort(RepeatedScalarContainer* self,
602                       PyObject* args,
603                       PyObject* kwds) {
604   // Support the old sort_function argument for backwards
605   // compatibility.
606   if (kwds != NULL) {
607     PyObject* sort_func = PyDict_GetItemString(kwds, "sort_function");
608     if (sort_func != NULL) {
609       // Must set before deleting as sort_func is a borrowed reference
610       // and kwds might be the only thing keeping it alive.
611       if (PyDict_SetItemString(kwds, "cmp", sort_func) == -1)
612         return NULL;
613       if (PyDict_DelItemString(kwds, "sort_function") == -1)
614         return NULL;
615     }
616   }
617 
618   ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
619   if (full_slice == NULL) {
620     return NULL;
621   }
622   ScopedPyObjectPtr list(Subscript(self, full_slice));
623   if (list == NULL) {
624     return NULL;
625   }
626   ScopedPyObjectPtr m(PyObject_GetAttrString(list, "sort"));
627   if (m == NULL) {
628     return NULL;
629   }
630   ScopedPyObjectPtr res(PyObject_Call(m, args, kwds));
631   if (res == NULL) {
632     return NULL;
633   }
634   int ret = InternalAssignRepeatedField(self, list);
635   if (ret < 0) {
636     return NULL;
637   }
638   Py_RETURN_NONE;
639 }
640 
Init(RepeatedScalarContainer * self,PyObject * args,PyObject * kwargs)641 static int Init(RepeatedScalarContainer* self,
642                 PyObject* args,
643                 PyObject* kwargs) {
644   PyObject* py_parent;
645   PyObject* py_parent_field;
646   if (!PyArg_UnpackTuple(args, "__init__()", 2, 2, &py_parent,
647                          &py_parent_field)) {
648     return -1;
649   }
650 
651   if (!PyObject_TypeCheck(py_parent, &CMessage_Type)) {
652     PyErr_Format(PyExc_TypeError,
653                  "expect %s, but got %s",
654                  CMessage_Type.tp_name,
655                  Py_TYPE(py_parent)->tp_name);
656     return -1;
657   }
658 
659   if (!PyObject_TypeCheck(py_parent_field, &CFieldDescriptor_Type)) {
660     PyErr_Format(PyExc_TypeError,
661                  "expect %s, but got %s",
662                  CFieldDescriptor_Type.tp_name,
663                  Py_TYPE(py_parent_field)->tp_name);
664     return -1;
665   }
666 
667   CMessage* cmessage = reinterpret_cast<CMessage*>(py_parent);
668   CFieldDescriptor* cdescriptor = reinterpret_cast<CFieldDescriptor*>(
669       py_parent_field);
670 
671   if (!FIELD_BELONGS_TO_MESSAGE(cdescriptor->descriptor, cmessage->message)) {
672     PyErr_SetString(
673         PyExc_KeyError, "Field does not belong to message!");
674     return -1;
675   }
676 
677   self->message = cmessage->message;
678   self->parent = cmessage;
679   self->parent_field = cdescriptor;
680   self->owner = cmessage->owner;
681   return 0;
682 }
683 
684 // Initializes the underlying Message object of "to" so it becomes a new parent
685 // repeated scalar, and copies all the values from "from" to it. A child scalar
686 // container can be released by passing it as both from and to (e.g. making it
687 // the recipient of the new parent message and copying the values from itself).
InitializeAndCopyToParentContainer(RepeatedScalarContainer * from,RepeatedScalarContainer * to)688 static int InitializeAndCopyToParentContainer(
689     RepeatedScalarContainer* from,
690     RepeatedScalarContainer* to) {
691   ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
692   if (full_slice == NULL) {
693     return -1;
694   }
695   ScopedPyObjectPtr values(Subscript(from, full_slice));
696   if (values == NULL) {
697     return -1;
698   }
699   google::protobuf::Message* new_message = global_message_factory->GetPrototype(
700       from->message->GetDescriptor())->New();
701   to->parent = NULL;
702   // TODO(anuraag): Document why it's OK to hang on to parent_field,
703   //     even though it's a weak reference. It ought to be enough to
704   //     hold on to the FieldDescriptor only.
705   to->parent_field = from->parent_field;
706   to->message = new_message;
707   to->owner.reset(new_message);
708   if (InternalAssignRepeatedField(to, values) < 0) {
709     return -1;
710   }
711   return 0;
712 }
713 
Release(RepeatedScalarContainer * self)714 int Release(RepeatedScalarContainer* self) {
715   return InitializeAndCopyToParentContainer(self, self);
716 }
717 
DeepCopy(RepeatedScalarContainer * self,PyObject * arg)718 PyObject* DeepCopy(RepeatedScalarContainer* self, PyObject* arg) {
719   ScopedPyObjectPtr init_args(
720       PyTuple_Pack(2, self->parent, self->parent_field));
721   PyObject* clone = PyObject_CallObject(
722       reinterpret_cast<PyObject*>(&RepeatedScalarContainer_Type), init_args);
723   if (clone == NULL) {
724     return NULL;
725   }
726   if (!PyObject_TypeCheck(clone, &RepeatedScalarContainer_Type)) {
727     Py_DECREF(clone);
728     return NULL;
729   }
730   if (InitializeAndCopyToParentContainer(
731           self, reinterpret_cast<RepeatedScalarContainer*>(clone)) < 0) {
732     Py_DECREF(clone);
733     return NULL;
734   }
735   return clone;
736 }
737 
Dealloc(RepeatedScalarContainer * self)738 static void Dealloc(RepeatedScalarContainer* self) {
739   self->owner.reset();
740   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
741 }
742 
SetOwner(RepeatedScalarContainer * self,const shared_ptr<Message> & new_owner)743 void SetOwner(RepeatedScalarContainer* self,
744               const shared_ptr<Message>& new_owner) {
745   self->owner = new_owner;
746 }
747 
748 static PySequenceMethods SqMethods = {
749   (lenfunc)Len,           /* sq_length */
750   0, /* sq_concat */
751   0, /* sq_repeat */
752   (ssizeargfunc)Item, /* sq_item */
753   0, /* sq_slice */
754   (ssizeobjargproc)AssignItem /* sq_ass_item */
755 };
756 
757 static PyMappingMethods MpMethods = {
758   (lenfunc)Len,               /* mp_length */
759   (binaryfunc)Subscript,      /* mp_subscript */
760   (objobjargproc)AssSubscript, /* mp_ass_subscript */
761 };
762 
763 static PyMethodDef Methods[] = {
764   { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
765     "Makes a deep copy of the class." },
766   { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
767     "Outputs picklable representation of the repeated field." },
768   { "append", (PyCFunction)Append, METH_O,
769     "Appends an object to the repeated container." },
770   { "extend", (PyCFunction)Extend, METH_O,
771     "Appends objects to the repeated container." },
772   { "insert", (PyCFunction)Insert, METH_VARARGS,
773     "Appends objects to the repeated container." },
774   { "remove", (PyCFunction)Remove, METH_O,
775     "Removes an object from the repeated container." },
776   { "sort", (PyCFunction)Sort, METH_VARARGS | METH_KEYWORDS,
777     "Sorts the repeated container."},
778   { NULL, NULL }
779 };
780 
781 }  // namespace repeated_scalar_container
782 
783 PyTypeObject RepeatedScalarContainer_Type = {
784   PyVarObject_HEAD_INIT(&PyType_Type, 0)
785   "google.protobuf.internal."
786   "cpp._message.RepeatedScalarContainer",  // tp_name
787   sizeof(RepeatedScalarContainer),     // tp_basicsize
788   0,                                   //  tp_itemsize
789   (destructor)repeated_scalar_container::Dealloc,  //  tp_dealloc
790   0,                                   //  tp_print
791   0,                                   //  tp_getattr
792   0,                                   //  tp_setattr
793   0,                                   //  tp_compare
794   0,                                   //  tp_repr
795   0,                                   //  tp_as_number
796   &repeated_scalar_container::SqMethods,   //  tp_as_sequence
797   &repeated_scalar_container::MpMethods,   //  tp_as_mapping
798   0,                                   //  tp_hash
799   0,                                   //  tp_call
800   0,                                   //  tp_str
801   0,                                   //  tp_getattro
802   0,                                   //  tp_setattro
803   0,                                   //  tp_as_buffer
804   Py_TPFLAGS_DEFAULT,                  //  tp_flags
805   "A Repeated scalar container",       //  tp_doc
806   0,                                   //  tp_traverse
807   0,                                   //  tp_clear
808   (richcmpfunc)repeated_scalar_container::RichCompare,  //  tp_richcompare
809   0,                                   //  tp_weaklistoffset
810   0,                                   //  tp_iter
811   0,                                   //  tp_iternext
812   repeated_scalar_container::Methods,      //  tp_methods
813   0,                                   //  tp_members
814   0,                                   //  tp_getset
815   0,                                   //  tp_base
816   0,                                   //  tp_dict
817   0,                                   //  tp_descr_get
818   0,                                   //  tp_descr_set
819   0,                                   //  tp_dictoffset
820   (initproc)repeated_scalar_container::Init,  //  tp_init
821 };
822 
823 }  // namespace python
824 }  // namespace protobuf
825 }  // namespace google
826