Home | History | Annotate | Download | only in pyext
      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 (at) google.com (Anuraag Agrawal)
     32 // Author: tibell (at) 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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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).
    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 
    714 int Release(RepeatedScalarContainer* self) {
    715   return InitializeAndCopyToParentContainer(self, self);
    716 }
    717 
    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 
    738 static void Dealloc(RepeatedScalarContainer* self) {
    739   self->owner.reset();
    740   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
    741 }
    742 
    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