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: haberman (at) google.com (Josh Haberman)
     32 
     33 #include <google/protobuf/pyext/map_container.h>
     34 
     35 #include <memory>
     36 #ifndef _SHARED_PTR_H
     37 #include <google/protobuf/stubs/shared_ptr.h>
     38 #endif
     39 
     40 #include <google/protobuf/stubs/logging.h>
     41 #include <google/protobuf/stubs/common.h>
     42 #include <google/protobuf/stubs/scoped_ptr.h>
     43 #include <google/protobuf/map_field.h>
     44 #include <google/protobuf/map.h>
     45 #include <google/protobuf/message.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   #define PyInt_FromSize_t PyLong_FromSize_t
     52 #endif
     53 
     54 namespace google {
     55 namespace protobuf {
     56 namespace python {
     57 
     58 // Functions that need access to map reflection functionality.
     59 // They need to be contained in this class because it is friended.
     60 class MapReflectionFriend {
     61  public:
     62   // Methods that are in common between the map types.
     63   static PyObject* Contains(PyObject* _self, PyObject* key);
     64   static Py_ssize_t Length(PyObject* _self);
     65   static PyObject* GetIterator(PyObject *_self);
     66   static PyObject* IterNext(PyObject* _self);
     67 
     68   // Methods that differ between the map types.
     69   static PyObject* ScalarMapGetItem(PyObject* _self, PyObject* key);
     70   static PyObject* MessageMapGetItem(PyObject* _self, PyObject* key);
     71   static int ScalarMapSetItem(PyObject* _self, PyObject* key, PyObject* v);
     72   static int MessageMapSetItem(PyObject* _self, PyObject* key, PyObject* v);
     73 };
     74 
     75 struct MapIterator {
     76   PyObject_HEAD;
     77 
     78   google::protobuf::scoped_ptr< ::google::protobuf::MapIterator> iter;
     79 
     80   // A pointer back to the container, so we can notice changes to the version.
     81   // We own a ref on this.
     82   MapContainer* container;
     83 
     84   // We need to keep a ref on the Message* too, because
     85   // MapIterator::~MapIterator() accesses it.  Normally this would be ok because
     86   // the ref on container (above) would guarantee outlive semantics.  However in
     87   // the case of ClearField(), InitializeAndCopyToParentContainer() resets the
     88   // message pointer (and the owner) to a different message, a copy of the
     89   // original.  But our iterator still points to the original, which could now
     90   // get deleted before us.
     91   //
     92   // To prevent this, we ensure that the Message will always stay alive as long
     93   // as this iterator does.  This is solely for the benefit of the MapIterator
     94   // destructor -- we should never actually access the iterator in this state
     95   // except to delete it.
     96   shared_ptr<Message> owner;
     97 
     98   // The version of the map when we took the iterator to it.
     99   //
    100   // We store this so that if the map is modified during iteration we can throw
    101   // an error.
    102   uint64 version;
    103 
    104   // True if the container is empty.  We signal this separately to avoid calling
    105   // any of the iteration methods, which are non-const.
    106   bool empty;
    107 };
    108 
    109 Message* MapContainer::GetMutableMessage() {
    110   cmessage::AssureWritable(parent);
    111   return const_cast<Message*>(message);
    112 }
    113 
    114 // Consumes a reference on the Python string object.
    115 static bool PyStringToSTL(PyObject* py_string, string* stl_string) {
    116   char *value;
    117   Py_ssize_t value_len;
    118 
    119   if (!py_string) {
    120     return false;
    121   }
    122   if (PyBytes_AsStringAndSize(py_string, &value, &value_len) < 0) {
    123     Py_DECREF(py_string);
    124     return false;
    125   } else {
    126     stl_string->assign(value, value_len);
    127     Py_DECREF(py_string);
    128     return true;
    129   }
    130 }
    131 
    132 static bool PythonToMapKey(PyObject* obj,
    133                            const FieldDescriptor* field_descriptor,
    134                            MapKey* key) {
    135   switch (field_descriptor->cpp_type()) {
    136     case FieldDescriptor::CPPTYPE_INT32: {
    137       GOOGLE_CHECK_GET_INT32(obj, value, false);
    138       key->SetInt32Value(value);
    139       break;
    140     }
    141     case FieldDescriptor::CPPTYPE_INT64: {
    142       GOOGLE_CHECK_GET_INT64(obj, value, false);
    143       key->SetInt64Value(value);
    144       break;
    145     }
    146     case FieldDescriptor::CPPTYPE_UINT32: {
    147       GOOGLE_CHECK_GET_UINT32(obj, value, false);
    148       key->SetUInt32Value(value);
    149       break;
    150     }
    151     case FieldDescriptor::CPPTYPE_UINT64: {
    152       GOOGLE_CHECK_GET_UINT64(obj, value, false);
    153       key->SetUInt64Value(value);
    154       break;
    155     }
    156     case FieldDescriptor::CPPTYPE_BOOL: {
    157       GOOGLE_CHECK_GET_BOOL(obj, value, false);
    158       key->SetBoolValue(value);
    159       break;
    160     }
    161     case FieldDescriptor::CPPTYPE_STRING: {
    162       string str;
    163       if (!PyStringToSTL(CheckString(obj, field_descriptor), &str)) {
    164         return false;
    165       }
    166       key->SetStringValue(str);
    167       break;
    168     }
    169     default:
    170       PyErr_Format(
    171           PyExc_SystemError, "Type %d cannot be a map key",
    172           field_descriptor->cpp_type());
    173       return false;
    174   }
    175   return true;
    176 }
    177 
    178 static PyObject* MapKeyToPython(const FieldDescriptor* field_descriptor,
    179                                 const MapKey& key) {
    180   switch (field_descriptor->cpp_type()) {
    181     case FieldDescriptor::CPPTYPE_INT32:
    182       return PyInt_FromLong(key.GetInt32Value());
    183     case FieldDescriptor::CPPTYPE_INT64:
    184       return PyLong_FromLongLong(key.GetInt64Value());
    185     case FieldDescriptor::CPPTYPE_UINT32:
    186       return PyInt_FromSize_t(key.GetUInt32Value());
    187     case FieldDescriptor::CPPTYPE_UINT64:
    188       return PyLong_FromUnsignedLongLong(key.GetUInt64Value());
    189     case FieldDescriptor::CPPTYPE_BOOL:
    190       return PyBool_FromLong(key.GetBoolValue());
    191     case FieldDescriptor::CPPTYPE_STRING:
    192       return ToStringObject(field_descriptor, key.GetStringValue());
    193     default:
    194       PyErr_Format(
    195           PyExc_SystemError, "Couldn't convert type %d to value",
    196           field_descriptor->cpp_type());
    197       return NULL;
    198   }
    199 }
    200 
    201 // This is only used for ScalarMap, so we don't need to handle the
    202 // CPPTYPE_MESSAGE case.
    203 PyObject* MapValueRefToPython(const FieldDescriptor* field_descriptor,
    204                               MapValueRef* value) {
    205   switch (field_descriptor->cpp_type()) {
    206     case FieldDescriptor::CPPTYPE_INT32:
    207       return PyInt_FromLong(value->GetInt32Value());
    208     case FieldDescriptor::CPPTYPE_INT64:
    209       return PyLong_FromLongLong(value->GetInt64Value());
    210     case FieldDescriptor::CPPTYPE_UINT32:
    211       return PyInt_FromSize_t(value->GetUInt32Value());
    212     case FieldDescriptor::CPPTYPE_UINT64:
    213       return PyLong_FromUnsignedLongLong(value->GetUInt64Value());
    214     case FieldDescriptor::CPPTYPE_FLOAT:
    215       return PyFloat_FromDouble(value->GetFloatValue());
    216     case FieldDescriptor::CPPTYPE_DOUBLE:
    217       return PyFloat_FromDouble(value->GetDoubleValue());
    218     case FieldDescriptor::CPPTYPE_BOOL:
    219       return PyBool_FromLong(value->GetBoolValue());
    220     case FieldDescriptor::CPPTYPE_STRING:
    221       return ToStringObject(field_descriptor, value->GetStringValue());
    222     case FieldDescriptor::CPPTYPE_ENUM:
    223       return PyInt_FromLong(value->GetEnumValue());
    224     default:
    225       PyErr_Format(
    226           PyExc_SystemError, "Couldn't convert type %d to value",
    227           field_descriptor->cpp_type());
    228       return NULL;
    229   }
    230 }
    231 
    232 // This is only used for ScalarMap, so we don't need to handle the
    233 // CPPTYPE_MESSAGE case.
    234 static bool PythonToMapValueRef(PyObject* obj,
    235                                 const FieldDescriptor* field_descriptor,
    236                                 bool allow_unknown_enum_values,
    237                                 MapValueRef* value_ref) {
    238   switch (field_descriptor->cpp_type()) {
    239     case FieldDescriptor::CPPTYPE_INT32: {
    240       GOOGLE_CHECK_GET_INT32(obj, value, false);
    241       value_ref->SetInt32Value(value);
    242       return true;
    243     }
    244     case FieldDescriptor::CPPTYPE_INT64: {
    245       GOOGLE_CHECK_GET_INT64(obj, value, false);
    246       value_ref->SetInt64Value(value);
    247       return true;
    248     }
    249     case FieldDescriptor::CPPTYPE_UINT32: {
    250       GOOGLE_CHECK_GET_UINT32(obj, value, false);
    251       value_ref->SetUInt32Value(value);
    252       return true;
    253     }
    254     case FieldDescriptor::CPPTYPE_UINT64: {
    255       GOOGLE_CHECK_GET_UINT64(obj, value, false);
    256       value_ref->SetUInt64Value(value);
    257       return true;
    258     }
    259     case FieldDescriptor::CPPTYPE_FLOAT: {
    260       GOOGLE_CHECK_GET_FLOAT(obj, value, false);
    261       value_ref->SetFloatValue(value);
    262       return true;
    263     }
    264     case FieldDescriptor::CPPTYPE_DOUBLE: {
    265       GOOGLE_CHECK_GET_DOUBLE(obj, value, false);
    266       value_ref->SetDoubleValue(value);
    267       return true;
    268     }
    269     case FieldDescriptor::CPPTYPE_BOOL: {
    270       GOOGLE_CHECK_GET_BOOL(obj, value, false);
    271       value_ref->SetBoolValue(value);
    272       return true;;
    273     }
    274     case FieldDescriptor::CPPTYPE_STRING: {
    275       string str;
    276       if (!PyStringToSTL(CheckString(obj, field_descriptor), &str)) {
    277         return false;
    278       }
    279       value_ref->SetStringValue(str);
    280       return true;
    281     }
    282     case FieldDescriptor::CPPTYPE_ENUM: {
    283       GOOGLE_CHECK_GET_INT32(obj, value, false);
    284       if (allow_unknown_enum_values) {
    285         value_ref->SetEnumValue(value);
    286         return true;
    287       } else {
    288         const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
    289         const EnumValueDescriptor* enum_value =
    290             enum_descriptor->FindValueByNumber(value);
    291         if (enum_value != NULL) {
    292           value_ref->SetEnumValue(value);
    293           return true;
    294         } else {
    295           PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value);
    296           return false;
    297         }
    298       }
    299       break;
    300     }
    301     default:
    302       PyErr_Format(
    303           PyExc_SystemError, "Setting value to a field of unknown type %d",
    304           field_descriptor->cpp_type());
    305       return false;
    306   }
    307 }
    308 
    309 // Map methods common to ScalarMap and MessageMap //////////////////////////////
    310 
    311 static MapContainer* GetMap(PyObject* obj) {
    312   return reinterpret_cast<MapContainer*>(obj);
    313 }
    314 
    315 Py_ssize_t MapReflectionFriend::Length(PyObject* _self) {
    316   MapContainer* self = GetMap(_self);
    317   const google::protobuf::Message* message = self->message;
    318   return message->GetReflection()->MapSize(*message,
    319                                            self->parent_field_descriptor);
    320 }
    321 
    322 PyObject* Clear(PyObject* _self) {
    323   MapContainer* self = GetMap(_self);
    324   Message* message = self->GetMutableMessage();
    325   const Reflection* reflection = message->GetReflection();
    326 
    327   reflection->ClearField(message, self->parent_field_descriptor);
    328 
    329   Py_RETURN_NONE;
    330 }
    331 
    332 PyObject* MapReflectionFriend::Contains(PyObject* _self, PyObject* key) {
    333   MapContainer* self = GetMap(_self);
    334 
    335   const Message* message = self->message;
    336   const Reflection* reflection = message->GetReflection();
    337   MapKey map_key;
    338 
    339   if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
    340     return NULL;
    341   }
    342 
    343   if (reflection->ContainsMapKey(*message, self->parent_field_descriptor,
    344                                  map_key)) {
    345     Py_RETURN_TRUE;
    346   } else {
    347     Py_RETURN_FALSE;
    348   }
    349 }
    350 
    351 // Initializes the underlying Message object of "to" so it becomes a new parent
    352 // repeated scalar, and copies all the values from "from" to it. A child scalar
    353 // container can be released by passing it as both from and to (e.g. making it
    354 // the recipient of the new parent message and copying the values from itself).
    355 static int InitializeAndCopyToParentContainer(MapContainer* from,
    356                                               MapContainer* to) {
    357   // For now we require from == to, re-evaluate if we want to support deep copy
    358   // as in repeated_scalar_container.cc.
    359   GOOGLE_DCHECK(from == to);
    360   Message* new_message = from->message->New();
    361 
    362   if (MapReflectionFriend::Length(reinterpret_cast<PyObject*>(from)) > 0) {
    363     // A somewhat roundabout way of copying just one field from old_message to
    364     // new_message.  This is the best we can do with what Reflection gives us.
    365     Message* mutable_old = from->GetMutableMessage();
    366     vector<const FieldDescriptor*> fields;
    367     fields.push_back(from->parent_field_descriptor);
    368 
    369     // Move the map field into the new message.
    370     mutable_old->GetReflection()->SwapFields(mutable_old, new_message, fields);
    371 
    372     // If/when we support from != to, this will be required also to copy the
    373     // map field back into the existing message:
    374     // mutable_old->MergeFrom(*new_message);
    375   }
    376 
    377   // If from == to this could delete old_message.
    378   to->owner.reset(new_message);
    379 
    380   to->parent = NULL;
    381   to->parent_field_descriptor = from->parent_field_descriptor;
    382   to->message = new_message;
    383 
    384   // Invalidate iterators, since they point to the old copy of the field.
    385   to->version++;
    386 
    387   return 0;
    388 }
    389 
    390 int MapContainer::Release() {
    391   return InitializeAndCopyToParentContainer(this, this);
    392 }
    393 
    394 
    395 // ScalarMap ///////////////////////////////////////////////////////////////////
    396 
    397 PyObject *NewScalarMapContainer(
    398     CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor) {
    399   if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
    400     return NULL;
    401   }
    402 
    403 #if PY_MAJOR_VERSION >= 3
    404   ScopedPyObjectPtr obj(PyType_GenericAlloc(
    405         reinterpret_cast<PyTypeObject *>(ScalarMapContainer_Type), 0));
    406 #else
    407   ScopedPyObjectPtr obj(PyType_GenericAlloc(&ScalarMapContainer_Type, 0));
    408 #endif
    409   if (obj.get() == NULL) {
    410     return PyErr_Format(PyExc_RuntimeError,
    411                         "Could not allocate new container.");
    412   }
    413 
    414   MapContainer* self = GetMap(obj.get());
    415 
    416   self->message = parent->message;
    417   self->parent = parent;
    418   self->parent_field_descriptor = parent_field_descriptor;
    419   self->owner = parent->owner;
    420   self->version = 0;
    421 
    422   self->key_field_descriptor =
    423       parent_field_descriptor->message_type()->FindFieldByName("key");
    424   self->value_field_descriptor =
    425       parent_field_descriptor->message_type()->FindFieldByName("value");
    426 
    427   if (self->key_field_descriptor == NULL ||
    428       self->value_field_descriptor == NULL) {
    429     return PyErr_Format(PyExc_KeyError,
    430                         "Map entry descriptor did not have key/value fields");
    431   }
    432 
    433   return obj.release();
    434 }
    435 
    436 PyObject* MapReflectionFriend::ScalarMapGetItem(PyObject* _self,
    437                                                 PyObject* key) {
    438   MapContainer* self = GetMap(_self);
    439 
    440   Message* message = self->GetMutableMessage();
    441   const Reflection* reflection = message->GetReflection();
    442   MapKey map_key;
    443   MapValueRef value;
    444 
    445   if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
    446     return NULL;
    447   }
    448 
    449   if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
    450                                          map_key, &value)) {
    451     self->version++;
    452   }
    453 
    454   return MapValueRefToPython(self->value_field_descriptor, &value);
    455 }
    456 
    457 int MapReflectionFriend::ScalarMapSetItem(PyObject* _self, PyObject* key,
    458                                           PyObject* v) {
    459   MapContainer* self = GetMap(_self);
    460 
    461   Message* message = self->GetMutableMessage();
    462   const Reflection* reflection = message->GetReflection();
    463   MapKey map_key;
    464   MapValueRef value;
    465 
    466   if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
    467     return -1;
    468   }
    469 
    470   self->version++;
    471 
    472   if (v) {
    473     // Set item to v.
    474     reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
    475                                        map_key, &value);
    476 
    477     return PythonToMapValueRef(v, self->value_field_descriptor,
    478                                reflection->SupportsUnknownEnumValues(), &value)
    479                ? 0
    480                : -1;
    481   } else {
    482     // Delete key from map.
    483     if (reflection->DeleteMapValue(message, self->parent_field_descriptor,
    484                                    map_key)) {
    485       return 0;
    486     } else {
    487       PyErr_Format(PyExc_KeyError, "Key not present in map");
    488       return -1;
    489     }
    490   }
    491 }
    492 
    493 static PyObject* ScalarMapGet(PyObject* self, PyObject* args) {
    494   PyObject* key;
    495   PyObject* default_value = NULL;
    496   if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) {
    497     return NULL;
    498   }
    499 
    500   ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key));
    501   if (is_present.get() == NULL) {
    502     return NULL;
    503   }
    504 
    505   if (PyObject_IsTrue(is_present.get())) {
    506     return MapReflectionFriend::ScalarMapGetItem(self, key);
    507   } else {
    508     if (default_value != NULL) {
    509       Py_INCREF(default_value);
    510       return default_value;
    511     } else {
    512       Py_RETURN_NONE;
    513     }
    514   }
    515 }
    516 
    517 static void ScalarMapDealloc(PyObject* _self) {
    518   MapContainer* self = GetMap(_self);
    519   self->owner.reset();
    520   Py_TYPE(_self)->tp_free(_self);
    521 }
    522 
    523 static PyMethodDef ScalarMapMethods[] = {
    524   { "__contains__", MapReflectionFriend::Contains, METH_O,
    525     "Tests whether a key is a member of the map." },
    526   { "clear", (PyCFunction)Clear, METH_NOARGS,
    527     "Removes all elements from the map." },
    528   { "get", ScalarMapGet, METH_VARARGS,
    529     "Gets the value for the given key if present, or otherwise a default" },
    530   /*
    531   { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
    532     "Makes a deep copy of the class." },
    533   { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
    534     "Outputs picklable representation of the repeated field." },
    535   */
    536   {NULL, NULL},
    537 };
    538 
    539 #if PY_MAJOR_VERSION >= 3
    540   static PyType_Slot ScalarMapContainer_Type_slots[] = {
    541       {Py_tp_dealloc, (void *)ScalarMapDealloc},
    542       {Py_mp_length, (void *)MapReflectionFriend::Length},
    543       {Py_mp_subscript, (void *)MapReflectionFriend::ScalarMapGetItem},
    544       {Py_mp_ass_subscript, (void *)MapReflectionFriend::ScalarMapSetItem},
    545       {Py_tp_methods, (void *)ScalarMapMethods},
    546       {Py_tp_iter, (void *)MapReflectionFriend::GetIterator},
    547       {0, 0},
    548   };
    549 
    550   PyType_Spec ScalarMapContainer_Type_spec = {
    551       FULL_MODULE_NAME ".ScalarMapContainer",
    552       sizeof(MapContainer),
    553       0,
    554       Py_TPFLAGS_DEFAULT,
    555       ScalarMapContainer_Type_slots
    556   };
    557   PyObject *ScalarMapContainer_Type;
    558 #else
    559   static PyMappingMethods ScalarMapMappingMethods = {
    560     MapReflectionFriend::Length,             // mp_length
    561     MapReflectionFriend::ScalarMapGetItem,   // mp_subscript
    562     MapReflectionFriend::ScalarMapSetItem,   // mp_ass_subscript
    563   };
    564 
    565   PyTypeObject ScalarMapContainer_Type = {
    566     PyVarObject_HEAD_INIT(&PyType_Type, 0)
    567     FULL_MODULE_NAME ".ScalarMapContainer",  //  tp_name
    568     sizeof(MapContainer),                //  tp_basicsize
    569     0,                                   //  tp_itemsize
    570     ScalarMapDealloc,                    //  tp_dealloc
    571     0,                                   //  tp_print
    572     0,                                   //  tp_getattr
    573     0,                                   //  tp_setattr
    574     0,                                   //  tp_compare
    575     0,                                   //  tp_repr
    576     0,                                   //  tp_as_number
    577     0,                                   //  tp_as_sequence
    578     &ScalarMapMappingMethods,            //  tp_as_mapping
    579     0,                                   //  tp_hash
    580     0,                                   //  tp_call
    581     0,                                   //  tp_str
    582     0,                                   //  tp_getattro
    583     0,                                   //  tp_setattro
    584     0,                                   //  tp_as_buffer
    585     Py_TPFLAGS_DEFAULT,                  //  tp_flags
    586     "A scalar map container",            //  tp_doc
    587     0,                                   //  tp_traverse
    588     0,                                   //  tp_clear
    589     0,                                   //  tp_richcompare
    590     0,                                   //  tp_weaklistoffset
    591     MapReflectionFriend::GetIterator,    //  tp_iter
    592     0,                                   //  tp_iternext
    593     ScalarMapMethods,                    //  tp_methods
    594     0,                                   //  tp_members
    595     0,                                   //  tp_getset
    596     0,                                   //  tp_base
    597     0,                                   //  tp_dict
    598     0,                                   //  tp_descr_get
    599     0,                                   //  tp_descr_set
    600     0,                                   //  tp_dictoffset
    601     0,                                   //  tp_init
    602   };
    603 #endif
    604 
    605 
    606 // MessageMap //////////////////////////////////////////////////////////////////
    607 
    608 static MessageMapContainer* GetMessageMap(PyObject* obj) {
    609   return reinterpret_cast<MessageMapContainer*>(obj);
    610 }
    611 
    612 static PyObject* GetCMessage(MessageMapContainer* self, Message* message) {
    613   // Get or create the CMessage object corresponding to this message.
    614   ScopedPyObjectPtr key(PyLong_FromVoidPtr(message));
    615   PyObject* ret = PyDict_GetItem(self->message_dict, key.get());
    616 
    617   if (ret == NULL) {
    618     CMessage* cmsg = cmessage::NewEmptyMessage(self->message_class);
    619     ret = reinterpret_cast<PyObject*>(cmsg);
    620 
    621     if (cmsg == NULL) {
    622       return NULL;
    623     }
    624     cmsg->owner = self->owner;
    625     cmsg->message = message;
    626     cmsg->parent = self->parent;
    627 
    628     if (PyDict_SetItem(self->message_dict, key.get(), ret) < 0) {
    629       Py_DECREF(ret);
    630       return NULL;
    631     }
    632   } else {
    633     Py_INCREF(ret);
    634   }
    635 
    636   return ret;
    637 }
    638 
    639 PyObject* NewMessageMapContainer(
    640     CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor,
    641     CMessageClass* message_class) {
    642   if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
    643     return NULL;
    644   }
    645 
    646 #if PY_MAJOR_VERSION >= 3
    647   PyObject* obj = PyType_GenericAlloc(
    648         reinterpret_cast<PyTypeObject *>(MessageMapContainer_Type), 0);
    649 #else
    650   PyObject* obj = PyType_GenericAlloc(&MessageMapContainer_Type, 0);
    651 #endif
    652   if (obj == NULL) {
    653     return PyErr_Format(PyExc_RuntimeError,
    654                         "Could not allocate new container.");
    655   }
    656 
    657   MessageMapContainer* self = GetMessageMap(obj);
    658 
    659   self->message = parent->message;
    660   self->parent = parent;
    661   self->parent_field_descriptor = parent_field_descriptor;
    662   self->owner = parent->owner;
    663   self->version = 0;
    664 
    665   self->key_field_descriptor =
    666       parent_field_descriptor->message_type()->FindFieldByName("key");
    667   self->value_field_descriptor =
    668       parent_field_descriptor->message_type()->FindFieldByName("value");
    669 
    670   self->message_dict = PyDict_New();
    671   if (self->message_dict == NULL) {
    672     return PyErr_Format(PyExc_RuntimeError,
    673                         "Could not allocate message dict.");
    674   }
    675 
    676   Py_INCREF(message_class);
    677   self->message_class = message_class;
    678 
    679   if (self->key_field_descriptor == NULL ||
    680       self->value_field_descriptor == NULL) {
    681     Py_DECREF(obj);
    682     return PyErr_Format(PyExc_KeyError,
    683                         "Map entry descriptor did not have key/value fields");
    684   }
    685 
    686   return obj;
    687 }
    688 
    689 int MapReflectionFriend::MessageMapSetItem(PyObject* _self, PyObject* key,
    690                                            PyObject* v) {
    691   if (v) {
    692     PyErr_Format(PyExc_ValueError,
    693                  "Direct assignment of submessage not allowed");
    694     return -1;
    695   }
    696 
    697   // Now we know that this is a delete, not a set.
    698 
    699   MessageMapContainer* self = GetMessageMap(_self);
    700   Message* message = self->GetMutableMessage();
    701   const Reflection* reflection = message->GetReflection();
    702   MapKey map_key;
    703   MapValueRef value;
    704 
    705   self->version++;
    706 
    707   if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
    708     return -1;
    709   }
    710 
    711   // Delete key from map.
    712   if (reflection->DeleteMapValue(message, self->parent_field_descriptor,
    713                                  map_key)) {
    714     return 0;
    715   } else {
    716     PyErr_Format(PyExc_KeyError, "Key not present in map");
    717     return -1;
    718   }
    719 }
    720 
    721 PyObject* MapReflectionFriend::MessageMapGetItem(PyObject* _self,
    722                                                  PyObject* key) {
    723   MessageMapContainer* self = GetMessageMap(_self);
    724 
    725   Message* message = self->GetMutableMessage();
    726   const Reflection* reflection = message->GetReflection();
    727   MapKey map_key;
    728   MapValueRef value;
    729 
    730   if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
    731     return NULL;
    732   }
    733 
    734   if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
    735                                          map_key, &value)) {
    736     self->version++;
    737   }
    738 
    739   return GetCMessage(self, value.MutableMessageValue());
    740 }
    741 
    742 PyObject* MessageMapGet(PyObject* self, PyObject* args) {
    743   PyObject* key;
    744   PyObject* default_value = NULL;
    745   if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) {
    746     return NULL;
    747   }
    748 
    749   ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key));
    750   if (is_present.get() == NULL) {
    751     return NULL;
    752   }
    753 
    754   if (PyObject_IsTrue(is_present.get())) {
    755     return MapReflectionFriend::MessageMapGetItem(self, key);
    756   } else {
    757     if (default_value != NULL) {
    758       Py_INCREF(default_value);
    759       return default_value;
    760     } else {
    761       Py_RETURN_NONE;
    762     }
    763   }
    764 }
    765 
    766 static void MessageMapDealloc(PyObject* _self) {
    767   MessageMapContainer* self = GetMessageMap(_self);
    768   self->owner.reset();
    769   Py_DECREF(self->message_dict);
    770   Py_DECREF(self->message_class);
    771   Py_TYPE(_self)->tp_free(_self);
    772 }
    773 
    774 static PyMethodDef MessageMapMethods[] = {
    775   { "__contains__", (PyCFunction)MapReflectionFriend::Contains, METH_O,
    776     "Tests whether the map contains this element."},
    777   { "clear", (PyCFunction)Clear, METH_NOARGS,
    778     "Removes all elements from the map."},
    779   { "get", MessageMapGet, METH_VARARGS,
    780     "Gets the value for the given key if present, or otherwise a default" },
    781   { "get_or_create", MapReflectionFriend::MessageMapGetItem, METH_O,
    782     "Alias for getitem, useful to make explicit that the map is mutated." },
    783   /*
    784   { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
    785     "Makes a deep copy of the class." },
    786   { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
    787     "Outputs picklable representation of the repeated field." },
    788   */
    789   {NULL, NULL},
    790 };
    791 
    792 #if PY_MAJOR_VERSION >= 3
    793   static PyType_Slot MessageMapContainer_Type_slots[] = {
    794       {Py_tp_dealloc, (void *)MessageMapDealloc},
    795       {Py_mp_length, (void *)MapReflectionFriend::Length},
    796       {Py_mp_subscript, (void *)MapReflectionFriend::MessageMapGetItem},
    797       {Py_mp_ass_subscript, (void *)MapReflectionFriend::MessageMapSetItem},
    798       {Py_tp_methods, (void *)MessageMapMethods},
    799       {Py_tp_iter, (void *)MapReflectionFriend::GetIterator},
    800       {0, 0}
    801   };
    802 
    803   PyType_Spec MessageMapContainer_Type_spec = {
    804       FULL_MODULE_NAME ".MessageMapContainer",
    805       sizeof(MessageMapContainer),
    806       0,
    807       Py_TPFLAGS_DEFAULT,
    808       MessageMapContainer_Type_slots
    809   };
    810 
    811   PyObject *MessageMapContainer_Type;
    812 #else
    813   static PyMappingMethods MessageMapMappingMethods = {
    814     MapReflectionFriend::Length,              // mp_length
    815     MapReflectionFriend::MessageMapGetItem,   // mp_subscript
    816     MapReflectionFriend::MessageMapSetItem,   // mp_ass_subscript
    817   };
    818 
    819   PyTypeObject MessageMapContainer_Type = {
    820     PyVarObject_HEAD_INIT(&PyType_Type, 0)
    821     FULL_MODULE_NAME ".MessageMapContainer",  //  tp_name
    822     sizeof(MessageMapContainer),         //  tp_basicsize
    823     0,                                   //  tp_itemsize
    824     MessageMapDealloc,                   //  tp_dealloc
    825     0,                                   //  tp_print
    826     0,                                   //  tp_getattr
    827     0,                                   //  tp_setattr
    828     0,                                   //  tp_compare
    829     0,                                   //  tp_repr
    830     0,                                   //  tp_as_number
    831     0,                                   //  tp_as_sequence
    832     &MessageMapMappingMethods,           //  tp_as_mapping
    833     0,                                   //  tp_hash
    834     0,                                   //  tp_call
    835     0,                                   //  tp_str
    836     0,                                   //  tp_getattro
    837     0,                                   //  tp_setattro
    838     0,                                   //  tp_as_buffer
    839     Py_TPFLAGS_DEFAULT,                  //  tp_flags
    840     "A map container for message",       //  tp_doc
    841     0,                                   //  tp_traverse
    842     0,                                   //  tp_clear
    843     0,                                   //  tp_richcompare
    844     0,                                   //  tp_weaklistoffset
    845     MapReflectionFriend::GetIterator,    //  tp_iter
    846     0,                                   //  tp_iternext
    847     MessageMapMethods,                   //  tp_methods
    848     0,                                   //  tp_members
    849     0,                                   //  tp_getset
    850     0,                                   //  tp_base
    851     0,                                   //  tp_dict
    852     0,                                   //  tp_descr_get
    853     0,                                   //  tp_descr_set
    854     0,                                   //  tp_dictoffset
    855     0,                                   //  tp_init
    856   };
    857 #endif
    858 
    859 // MapIterator /////////////////////////////////////////////////////////////////
    860 
    861 static MapIterator* GetIter(PyObject* obj) {
    862   return reinterpret_cast<MapIterator*>(obj);
    863 }
    864 
    865 PyObject* MapReflectionFriend::GetIterator(PyObject *_self) {
    866   MapContainer* self = GetMap(_self);
    867 
    868   ScopedPyObjectPtr obj(PyType_GenericAlloc(&MapIterator_Type, 0));
    869   if (obj == NULL) {
    870     return PyErr_Format(PyExc_KeyError, "Could not allocate iterator");
    871   }
    872 
    873   MapIterator* iter = GetIter(obj.get());
    874 
    875   Py_INCREF(self);
    876   iter->container = self;
    877   iter->version = self->version;
    878   iter->owner = self->owner;
    879 
    880   if (MapReflectionFriend::Length(_self) > 0) {
    881     Message* message = self->GetMutableMessage();
    882     const Reflection* reflection = message->GetReflection();
    883 
    884     iter->iter.reset(new ::google::protobuf::MapIterator(
    885         reflection->MapBegin(message, self->parent_field_descriptor)));
    886   }
    887 
    888   return obj.release();
    889 }
    890 
    891 PyObject* MapReflectionFriend::IterNext(PyObject* _self) {
    892   MapIterator* self = GetIter(_self);
    893 
    894   // This won't catch mutations to the map performed by MergeFrom(); no easy way
    895   // to address that.
    896   if (self->version != self->container->version) {
    897     return PyErr_Format(PyExc_RuntimeError,
    898                         "Map modified during iteration.");
    899   }
    900 
    901   if (self->iter.get() == NULL) {
    902     return NULL;
    903   }
    904 
    905   Message* message = self->container->GetMutableMessage();
    906   const Reflection* reflection = message->GetReflection();
    907 
    908   if (*self->iter ==
    909       reflection->MapEnd(message, self->container->parent_field_descriptor)) {
    910     return NULL;
    911   }
    912 
    913   PyObject* ret = MapKeyToPython(self->container->key_field_descriptor,
    914                                  self->iter->GetKey());
    915 
    916   ++(*self->iter);
    917 
    918   return ret;
    919 }
    920 
    921 static void DeallocMapIterator(PyObject* _self) {
    922   MapIterator* self = GetIter(_self);
    923   self->iter.reset();
    924   self->owner.reset();
    925   Py_XDECREF(self->container);
    926   Py_TYPE(_self)->tp_free(_self);
    927 }
    928 
    929 PyTypeObject MapIterator_Type = {
    930   PyVarObject_HEAD_INIT(&PyType_Type, 0)
    931   FULL_MODULE_NAME ".MapIterator",     //  tp_name
    932   sizeof(MapIterator),                 //  tp_basicsize
    933   0,                                   //  tp_itemsize
    934   DeallocMapIterator,                  //  tp_dealloc
    935   0,                                   //  tp_print
    936   0,                                   //  tp_getattr
    937   0,                                   //  tp_setattr
    938   0,                                   //  tp_compare
    939   0,                                   //  tp_repr
    940   0,                                   //  tp_as_number
    941   0,                                   //  tp_as_sequence
    942   0,                                   //  tp_as_mapping
    943   0,                                   //  tp_hash
    944   0,                                   //  tp_call
    945   0,                                   //  tp_str
    946   0,                                   //  tp_getattro
    947   0,                                   //  tp_setattro
    948   0,                                   //  tp_as_buffer
    949   Py_TPFLAGS_DEFAULT,                  //  tp_flags
    950   "A scalar map iterator",             //  tp_doc
    951   0,                                   //  tp_traverse
    952   0,                                   //  tp_clear
    953   0,                                   //  tp_richcompare
    954   0,                                   //  tp_weaklistoffset
    955   PyObject_SelfIter,                   //  tp_iter
    956   MapReflectionFriend::IterNext,       //  tp_iternext
    957   0,                                   //  tp_methods
    958   0,                                   //  tp_members
    959   0,                                   //  tp_getset
    960   0,                                   //  tp_base
    961   0,                                   //  tp_dict
    962   0,                                   //  tp_descr_get
    963   0,                                   //  tp_descr_set
    964   0,                                   //  tp_dictoffset
    965   0,                                   //  tp_init
    966 };
    967 
    968 }  // namespace python
    969 }  // namespace protobuf
    970 }  // namespace google
    971