OLD | NEW |
(Empty) | |
| 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 // Mappings and Sequences of descriptors. |
| 32 // Used by Descriptor.fields_by_name, EnumDescriptor.values... |
| 33 // |
| 34 // They avoid the allocation of a full dictionary or a full list: they simply |
| 35 // store a pointer to the parent descriptor, use the C++ Descriptor methods (see |
| 36 // google/protobuf/descriptor.h) to retrieve other descriptors, and create |
| 37 // Python objects on the fly. |
| 38 // |
| 39 // The containers fully conform to abc.Mapping and abc.Sequence, and behave just |
| 40 // like read-only dictionaries and lists. |
| 41 // |
| 42 // Because the interface of C++ Descriptors is quite regular, this file actually |
| 43 // defines only three types, the exact behavior of a container is controlled by |
| 44 // a DescriptorContainerDef structure, which contains functions that uses the |
| 45 // public Descriptor API. |
| 46 // |
| 47 // Note: This DescriptorContainerDef is similar to the "virtual methods table" |
| 48 // that a C++ compiler generates for a class. We have to make it explicit |
| 49 // because the Python API is based on C, and does not play well with C++ |
| 50 // inheritance. |
| 51 |
| 52 #include <Python.h> |
| 53 |
| 54 #include <google/protobuf/descriptor.h> |
| 55 #include <google/protobuf/pyext/descriptor_containers.h> |
| 56 #include <google/protobuf/pyext/descriptor_pool.h> |
| 57 #include <google/protobuf/pyext/descriptor.h> |
| 58 #include <google/protobuf/pyext/scoped_pyobject_ptr.h> |
| 59 |
| 60 #if PY_MAJOR_VERSION >= 3 |
| 61 #define PyString_FromStringAndSize PyUnicode_FromStringAndSize |
| 62 #define PyString_FromFormat PyUnicode_FromFormat |
| 63 #define PyInt_FromLong PyLong_FromLong |
| 64 #if PY_VERSION_HEX < 0x03030000 |
| 65 #error "Python 3.0 - 3.2 are not supported." |
| 66 #endif |
| 67 #define PyString_AsStringAndSize(ob, charpp, sizep) \ |
| 68 (PyUnicode_Check(ob)? \ |
| 69 ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \ |
| 70 PyBytes_AsStringAndSize(ob, (charpp), (sizep))) |
| 71 #endif |
| 72 |
| 73 namespace google { |
| 74 namespace protobuf { |
| 75 namespace python { |
| 76 |
| 77 struct PyContainer; |
| 78 |
| 79 typedef int (*CountMethod)(PyContainer* self); |
| 80 typedef const void* (*GetByIndexMethod)(PyContainer* self, int index); |
| 81 typedef const void* (*GetByNameMethod)(PyContainer* self, const string& name); |
| 82 typedef const void* (*GetByCamelcaseNameMethod)(PyContainer* self, |
| 83 const string& name); |
| 84 typedef const void* (*GetByNumberMethod)(PyContainer* self, int index); |
| 85 typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor); |
| 86 typedef const string& (*GetItemNameMethod)(const void* descriptor); |
| 87 typedef const string& (*GetItemCamelcaseNameMethod)(const void* descriptor); |
| 88 typedef int (*GetItemNumberMethod)(const void* descriptor); |
| 89 typedef int (*GetItemIndexMethod)(const void* descriptor); |
| 90 |
| 91 struct DescriptorContainerDef { |
| 92 const char* mapping_name; |
| 93 // Returns the number of items in the container. |
| 94 CountMethod count_fn; |
| 95 // Retrieve item by index (usually the order of declaration in the proto file) |
| 96 // Used by sequences, but also iterators. 0 <= index < Count(). |
| 97 GetByIndexMethod get_by_index_fn; |
| 98 // Retrieve item by name (usually a call to some 'FindByName' method). |
| 99 // Used by "by_name" mappings. |
| 100 GetByNameMethod get_by_name_fn; |
| 101 // Retrieve item by camelcase name (usually a call to some |
| 102 // 'FindByCamelcaseName' method). Used by "by_camelcase_name" mappings. |
| 103 GetByCamelcaseNameMethod get_by_camelcase_name_fn; |
| 104 // Retrieve item by declared number (field tag, or enum value). |
| 105 // Used by "by_number" mappings. |
| 106 GetByNumberMethod get_by_number_fn; |
| 107 // Converts a item C++ descriptor to a Python object. Returns a new reference. |
| 108 NewObjectFromItemMethod new_object_from_item_fn; |
| 109 // Retrieve the name of an item. Used by iterators on "by_name" mappings. |
| 110 GetItemNameMethod get_item_name_fn; |
| 111 // Retrieve the camelcase name of an item. Used by iterators on |
| 112 // "by_camelcase_name" mappings. |
| 113 GetItemCamelcaseNameMethod get_item_camelcase_name_fn; |
| 114 // Retrieve the number of an item. Used by iterators on "by_number" mappings. |
| 115 GetItemNumberMethod get_item_number_fn; |
| 116 // Retrieve the index of an item for the container type. |
| 117 // Used by "__contains__". |
| 118 // If not set, "x in sequence" will do a linear search. |
| 119 GetItemIndexMethod get_item_index_fn; |
| 120 }; |
| 121 |
| 122 struct PyContainer { |
| 123 PyObject_HEAD |
| 124 |
| 125 // The proto2 descriptor this container belongs to the global DescriptorPool. |
| 126 const void* descriptor; |
| 127 |
| 128 // A pointer to a static structure with function pointers that control the |
| 129 // behavior of the container. Very similar to the table of virtual functions |
| 130 // of a C++ class. |
| 131 const DescriptorContainerDef* container_def; |
| 132 |
| 133 // The kind of container: list, or dict by name or value. |
| 134 enum ContainerKind { |
| 135 KIND_SEQUENCE, |
| 136 KIND_BYNAME, |
| 137 KIND_BYCAMELCASENAME, |
| 138 KIND_BYNUMBER, |
| 139 } kind; |
| 140 }; |
| 141 |
| 142 struct PyContainerIterator { |
| 143 PyObject_HEAD |
| 144 |
| 145 // The container we are iterating over. Own a reference. |
| 146 PyContainer* container; |
| 147 |
| 148 // The current index in the iterator. |
| 149 int index; |
| 150 |
| 151 // The kind of container: list, or dict by name or value. |
| 152 enum IterKind { |
| 153 KIND_ITERKEY, |
| 154 KIND_ITERVALUE, |
| 155 KIND_ITERITEM, |
| 156 KIND_ITERVALUE_REVERSED, // For sequences |
| 157 } kind; |
| 158 }; |
| 159 |
| 160 namespace descriptor { |
| 161 |
| 162 // Returns the C++ item descriptor for a given Python key. |
| 163 // When the descriptor is found, return true and set *item. |
| 164 // When the descriptor is not found, return true, but set *item to NULL. |
| 165 // On error, returns false with an exception set. |
| 166 static bool _GetItemByKey(PyContainer* self, PyObject* key, const void** item) { |
| 167 switch (self->kind) { |
| 168 case PyContainer::KIND_BYNAME: |
| 169 { |
| 170 char* name; |
| 171 Py_ssize_t name_size; |
| 172 if (PyString_AsStringAndSize(key, &name, &name_size) < 0) { |
| 173 if (PyErr_ExceptionMatches(PyExc_TypeError)) { |
| 174 // Not a string, cannot be in the container. |
| 175 PyErr_Clear(); |
| 176 *item = NULL; |
| 177 return true; |
| 178 } |
| 179 return false; |
| 180 } |
| 181 *item = self->container_def->get_by_name_fn( |
| 182 self, string(name, name_size)); |
| 183 return true; |
| 184 } |
| 185 case PyContainer::KIND_BYCAMELCASENAME: |
| 186 { |
| 187 char* camelcase_name; |
| 188 Py_ssize_t name_size; |
| 189 if (PyString_AsStringAndSize(key, &camelcase_name, &name_size) < 0) { |
| 190 if (PyErr_ExceptionMatches(PyExc_TypeError)) { |
| 191 // Not a string, cannot be in the container. |
| 192 PyErr_Clear(); |
| 193 *item = NULL; |
| 194 return true; |
| 195 } |
| 196 return false; |
| 197 } |
| 198 *item = self->container_def->get_by_camelcase_name_fn( |
| 199 self, string(camelcase_name, name_size)); |
| 200 return true; |
| 201 } |
| 202 case PyContainer::KIND_BYNUMBER: |
| 203 { |
| 204 Py_ssize_t number = PyNumber_AsSsize_t(key, NULL); |
| 205 if (number == -1 && PyErr_Occurred()) { |
| 206 if (PyErr_ExceptionMatches(PyExc_TypeError)) { |
| 207 // Not a number, cannot be in the container. |
| 208 PyErr_Clear(); |
| 209 *item = NULL; |
| 210 return true; |
| 211 } |
| 212 return false; |
| 213 } |
| 214 *item = self->container_def->get_by_number_fn(self, number); |
| 215 return true; |
| 216 } |
| 217 default: |
| 218 PyErr_SetNone(PyExc_NotImplementedError); |
| 219 return false; |
| 220 } |
| 221 } |
| 222 |
| 223 // Returns the key of the object at the given index. |
| 224 // Used when iterating over mappings. |
| 225 static PyObject* _NewKey_ByIndex(PyContainer* self, Py_ssize_t index) { |
| 226 const void* item = self->container_def->get_by_index_fn(self, index); |
| 227 switch (self->kind) { |
| 228 case PyContainer::KIND_BYNAME: |
| 229 { |
| 230 const string& name(self->container_def->get_item_name_fn(item)); |
| 231 return PyString_FromStringAndSize(name.c_str(), name.size()); |
| 232 } |
| 233 case PyContainer::KIND_BYCAMELCASENAME: |
| 234 { |
| 235 const string& name( |
| 236 self->container_def->get_item_camelcase_name_fn(item)); |
| 237 return PyString_FromStringAndSize(name.c_str(), name.size()); |
| 238 } |
| 239 case PyContainer::KIND_BYNUMBER: |
| 240 { |
| 241 int value = self->container_def->get_item_number_fn(item); |
| 242 return PyInt_FromLong(value); |
| 243 } |
| 244 default: |
| 245 PyErr_SetNone(PyExc_NotImplementedError); |
| 246 return NULL; |
| 247 } |
| 248 } |
| 249 |
| 250 // Returns the object at the given index. |
| 251 // Also used when iterating over mappings. |
| 252 static PyObject* _NewObj_ByIndex(PyContainer* self, Py_ssize_t index) { |
| 253 return self->container_def->new_object_from_item_fn( |
| 254 self->container_def->get_by_index_fn(self, index)); |
| 255 } |
| 256 |
| 257 static Py_ssize_t Length(PyContainer* self) { |
| 258 return self->container_def->count_fn(self); |
| 259 } |
| 260 |
| 261 // The DescriptorMapping type. |
| 262 |
| 263 static PyObject* Subscript(PyContainer* self, PyObject* key) { |
| 264 const void* item = NULL; |
| 265 if (!_GetItemByKey(self, key, &item)) { |
| 266 return NULL; |
| 267 } |
| 268 if (!item) { |
| 269 PyErr_SetObject(PyExc_KeyError, key); |
| 270 return NULL; |
| 271 } |
| 272 return self->container_def->new_object_from_item_fn(item); |
| 273 } |
| 274 |
| 275 static int AssSubscript(PyContainer* self, PyObject* key, PyObject* value) { |
| 276 if (_CalledFromGeneratedFile(0)) { |
| 277 return 0; |
| 278 } |
| 279 PyErr_Format(PyExc_TypeError, |
| 280 "'%.200s' object does not support item assignment", |
| 281 Py_TYPE(self)->tp_name); |
| 282 return -1; |
| 283 } |
| 284 |
| 285 static PyMappingMethods MappingMappingMethods = { |
| 286 (lenfunc)Length, // mp_length |
| 287 (binaryfunc)Subscript, // mp_subscript |
| 288 (objobjargproc)AssSubscript, // mp_ass_subscript |
| 289 }; |
| 290 |
| 291 static int Contains(PyContainer* self, PyObject* key) { |
| 292 const void* item = NULL; |
| 293 if (!_GetItemByKey(self, key, &item)) { |
| 294 return -1; |
| 295 } |
| 296 if (item) { |
| 297 return 1; |
| 298 } else { |
| 299 return 0; |
| 300 } |
| 301 } |
| 302 |
| 303 static PyObject* ContainerRepr(PyContainer* self) { |
| 304 const char* kind = ""; |
| 305 switch (self->kind) { |
| 306 case PyContainer::KIND_SEQUENCE: |
| 307 kind = "sequence"; |
| 308 break; |
| 309 case PyContainer::KIND_BYNAME: |
| 310 kind = "mapping by name"; |
| 311 break; |
| 312 case PyContainer::KIND_BYCAMELCASENAME: |
| 313 kind = "mapping by camelCase name"; |
| 314 break; |
| 315 case PyContainer::KIND_BYNUMBER: |
| 316 kind = "mapping by number"; |
| 317 break; |
| 318 } |
| 319 return PyString_FromFormat( |
| 320 "<%s %s>", self->container_def->mapping_name, kind); |
| 321 } |
| 322 |
| 323 extern PyTypeObject DescriptorMapping_Type; |
| 324 extern PyTypeObject DescriptorSequence_Type; |
| 325 |
| 326 // A sequence container can only be equal to another sequence container, or (for |
| 327 // backward compatibility) to a list containing the same items. |
| 328 // Returns 1 if equal, 0 if unequal, -1 on error. |
| 329 static int DescriptorSequence_Equal(PyContainer* self, PyObject* other) { |
| 330 // Check the identity of C++ pointers. |
| 331 if (PyObject_TypeCheck(other, &DescriptorSequence_Type)) { |
| 332 PyContainer* other_container = reinterpret_cast<PyContainer*>(other); |
| 333 if (self->descriptor == other_container->descriptor && |
| 334 self->container_def == other_container->container_def && |
| 335 self->kind == other_container->kind) { |
| 336 return 1; |
| 337 } else { |
| 338 return 0; |
| 339 } |
| 340 } |
| 341 |
| 342 // If other is a list |
| 343 if (PyList_Check(other)) { |
| 344 // return list(self) == other |
| 345 int size = Length(self); |
| 346 if (size != PyList_Size(other)) { |
| 347 return false; |
| 348 } |
| 349 for (int index = 0; index < size; index++) { |
| 350 ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index)); |
| 351 if (value1 == NULL) { |
| 352 return -1; |
| 353 } |
| 354 PyObject* value2 = PyList_GetItem(other, index); |
| 355 if (value2 == NULL) { |
| 356 return -1; |
| 357 } |
| 358 int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ); |
| 359 if (cmp != 1) // error or not equal |
| 360 return cmp; |
| 361 } |
| 362 // All items were found and equal |
| 363 return 1; |
| 364 } |
| 365 |
| 366 // Any other object is different. |
| 367 return 0; |
| 368 } |
| 369 |
| 370 // A mapping container can only be equal to another mapping container, or (for |
| 371 // backward compatibility) to a dict containing the same items. |
| 372 // Returns 1 if equal, 0 if unequal, -1 on error. |
| 373 static int DescriptorMapping_Equal(PyContainer* self, PyObject* other) { |
| 374 // Check the identity of C++ pointers. |
| 375 if (PyObject_TypeCheck(other, &DescriptorMapping_Type)) { |
| 376 PyContainer* other_container = reinterpret_cast<PyContainer*>(other); |
| 377 if (self->descriptor == other_container->descriptor && |
| 378 self->container_def == other_container->container_def && |
| 379 self->kind == other_container->kind) { |
| 380 return 1; |
| 381 } else { |
| 382 return 0; |
| 383 } |
| 384 } |
| 385 |
| 386 // If other is a dict |
| 387 if (PyDict_Check(other)) { |
| 388 // equivalent to dict(self.items()) == other |
| 389 int size = Length(self); |
| 390 if (size != PyDict_Size(other)) { |
| 391 return false; |
| 392 } |
| 393 for (int index = 0; index < size; index++) { |
| 394 ScopedPyObjectPtr key(_NewKey_ByIndex(self, index)); |
| 395 if (key == NULL) { |
| 396 return -1; |
| 397 } |
| 398 ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index)); |
| 399 if (value1 == NULL) { |
| 400 return -1; |
| 401 } |
| 402 PyObject* value2 = PyDict_GetItem(other, key.get()); |
| 403 if (value2 == NULL) { |
| 404 // Not found in the other dictionary |
| 405 return 0; |
| 406 } |
| 407 int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ); |
| 408 if (cmp != 1) // error or not equal |
| 409 return cmp; |
| 410 } |
| 411 // All items were found and equal |
| 412 return 1; |
| 413 } |
| 414 |
| 415 // Any other object is different. |
| 416 return 0; |
| 417 } |
| 418 |
| 419 static PyObject* RichCompare(PyContainer* self, PyObject* other, int opid) { |
| 420 if (opid != Py_EQ && opid != Py_NE) { |
| 421 Py_INCREF(Py_NotImplemented); |
| 422 return Py_NotImplemented; |
| 423 } |
| 424 |
| 425 int result; |
| 426 |
| 427 if (self->kind == PyContainer::KIND_SEQUENCE) { |
| 428 result = DescriptorSequence_Equal(self, other); |
| 429 } else { |
| 430 result = DescriptorMapping_Equal(self, other); |
| 431 } |
| 432 if (result < 0) { |
| 433 return NULL; |
| 434 } |
| 435 if (result ^ (opid == Py_NE)) { |
| 436 Py_RETURN_TRUE; |
| 437 } else { |
| 438 Py_RETURN_FALSE; |
| 439 } |
| 440 } |
| 441 |
| 442 static PySequenceMethods MappingSequenceMethods = { |
| 443 0, // sq_length |
| 444 0, // sq_concat |
| 445 0, // sq_repeat |
| 446 0, // sq_item |
| 447 0, // sq_slice |
| 448 0, // sq_ass_item |
| 449 0, // sq_ass_slice |
| 450 (objobjproc)Contains, // sq_contains |
| 451 }; |
| 452 |
| 453 static PyObject* Get(PyContainer* self, PyObject* args) { |
| 454 PyObject* key; |
| 455 PyObject* default_value = Py_None; |
| 456 if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_value)) { |
| 457 return NULL; |
| 458 } |
| 459 |
| 460 const void* item; |
| 461 if (!_GetItemByKey(self, key, &item)) { |
| 462 return NULL; |
| 463 } |
| 464 if (item == NULL) { |
| 465 Py_INCREF(default_value); |
| 466 return default_value; |
| 467 } |
| 468 return self->container_def->new_object_from_item_fn(item); |
| 469 } |
| 470 |
| 471 static PyObject* Keys(PyContainer* self, PyObject* args) { |
| 472 Py_ssize_t count = Length(self); |
| 473 ScopedPyObjectPtr list(PyList_New(count)); |
| 474 if (list == NULL) { |
| 475 return NULL; |
| 476 } |
| 477 for (Py_ssize_t index = 0; index < count; ++index) { |
| 478 PyObject* key = _NewKey_ByIndex(self, index); |
| 479 if (key == NULL) { |
| 480 return NULL; |
| 481 } |
| 482 PyList_SET_ITEM(list.get(), index, key); |
| 483 } |
| 484 return list.release(); |
| 485 } |
| 486 |
| 487 static PyObject* Values(PyContainer* self, PyObject* args) { |
| 488 Py_ssize_t count = Length(self); |
| 489 ScopedPyObjectPtr list(PyList_New(count)); |
| 490 if (list == NULL) { |
| 491 return NULL; |
| 492 } |
| 493 for (Py_ssize_t index = 0; index < count; ++index) { |
| 494 PyObject* value = _NewObj_ByIndex(self, index); |
| 495 if (value == NULL) { |
| 496 return NULL; |
| 497 } |
| 498 PyList_SET_ITEM(list.get(), index, value); |
| 499 } |
| 500 return list.release(); |
| 501 } |
| 502 |
| 503 static PyObject* Items(PyContainer* self, PyObject* args) { |
| 504 Py_ssize_t count = Length(self); |
| 505 ScopedPyObjectPtr list(PyList_New(count)); |
| 506 if (list == NULL) { |
| 507 return NULL; |
| 508 } |
| 509 for (Py_ssize_t index = 0; index < count; ++index) { |
| 510 ScopedPyObjectPtr obj(PyTuple_New(2)); |
| 511 if (obj == NULL) { |
| 512 return NULL; |
| 513 } |
| 514 PyObject* key = _NewKey_ByIndex(self, index); |
| 515 if (key == NULL) { |
| 516 return NULL; |
| 517 } |
| 518 PyTuple_SET_ITEM(obj.get(), 0, key); |
| 519 PyObject* value = _NewObj_ByIndex(self, index); |
| 520 if (value == NULL) { |
| 521 return NULL; |
| 522 } |
| 523 PyTuple_SET_ITEM(obj.get(), 1, value); |
| 524 PyList_SET_ITEM(list.get(), index, obj.release()); |
| 525 } |
| 526 return list.release(); |
| 527 } |
| 528 |
| 529 static PyObject* NewContainerIterator(PyContainer* mapping, |
| 530 PyContainerIterator::IterKind kind); |
| 531 |
| 532 static PyObject* Iter(PyContainer* self) { |
| 533 return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY); |
| 534 } |
| 535 static PyObject* IterKeys(PyContainer* self, PyObject* args) { |
| 536 return NewContainerIterator(self, PyContainerIterator::KIND_ITERKEY); |
| 537 } |
| 538 static PyObject* IterValues(PyContainer* self, PyObject* args) { |
| 539 return NewContainerIterator(self, PyContainerIterator::KIND_ITERVALUE); |
| 540 } |
| 541 static PyObject* IterItems(PyContainer* self, PyObject* args) { |
| 542 return NewContainerIterator(self, PyContainerIterator::KIND_ITERITEM); |
| 543 } |
| 544 |
| 545 static PyMethodDef MappingMethods[] = { |
| 546 { "get", (PyCFunction)Get, METH_VARARGS, }, |
| 547 { "keys", (PyCFunction)Keys, METH_NOARGS, }, |
| 548 { "values", (PyCFunction)Values, METH_NOARGS, }, |
| 549 { "items", (PyCFunction)Items, METH_NOARGS, }, |
| 550 { "iterkeys", (PyCFunction)IterKeys, METH_NOARGS, }, |
| 551 { "itervalues", (PyCFunction)IterValues, METH_NOARGS, }, |
| 552 { "iteritems", (PyCFunction)IterItems, METH_NOARGS, }, |
| 553 {NULL} |
| 554 }; |
| 555 |
| 556 PyTypeObject DescriptorMapping_Type = { |
| 557 PyVarObject_HEAD_INIT(&PyType_Type, 0) |
| 558 "DescriptorMapping", // tp_name |
| 559 sizeof(PyContainer), // tp_basicsize |
| 560 0, // tp_itemsize |
| 561 0, // tp_dealloc |
| 562 0, // tp_print |
| 563 0, // tp_getattr |
| 564 0, // tp_setattr |
| 565 0, // tp_compare |
| 566 (reprfunc)ContainerRepr, // tp_repr |
| 567 0, // tp_as_number |
| 568 &MappingSequenceMethods, // tp_as_sequence |
| 569 &MappingMappingMethods, // tp_as_mapping |
| 570 0, // tp_hash |
| 571 0, // tp_call |
| 572 0, // tp_str |
| 573 0, // tp_getattro |
| 574 0, // tp_setattro |
| 575 0, // tp_as_buffer |
| 576 Py_TPFLAGS_DEFAULT, // tp_flags |
| 577 0, // tp_doc |
| 578 0, // tp_traverse |
| 579 0, // tp_clear |
| 580 (richcmpfunc)RichCompare, // tp_richcompare |
| 581 0, // tp_weaklistoffset |
| 582 (getiterfunc)Iter, // tp_iter |
| 583 0, // tp_iternext |
| 584 MappingMethods, // tp_methods |
| 585 0, // tp_members |
| 586 0, // tp_getset |
| 587 0, // tp_base |
| 588 0, // tp_dict |
| 589 0, // tp_descr_get |
| 590 0, // tp_descr_set |
| 591 0, // tp_dictoffset |
| 592 0, // tp_init |
| 593 0, // tp_alloc |
| 594 0, // tp_new |
| 595 0, // tp_free |
| 596 }; |
| 597 |
| 598 // The DescriptorSequence type. |
| 599 |
| 600 static PyObject* GetItem(PyContainer* self, Py_ssize_t index) { |
| 601 if (index < 0) { |
| 602 index += Length(self); |
| 603 } |
| 604 if (index < 0 || index >= Length(self)) { |
| 605 PyErr_SetString(PyExc_IndexError, "index out of range"); |
| 606 return NULL; |
| 607 } |
| 608 return _NewObj_ByIndex(self, index); |
| 609 } |
| 610 |
| 611 // Returns the position of the item in the sequence, of -1 if not found. |
| 612 // This function never fails. |
| 613 int Find(PyContainer* self, PyObject* item) { |
| 614 // The item can only be in one position: item.index. |
| 615 // Check that self[item.index] == item, it's faster than a linear search. |
| 616 // |
| 617 // This assumes that sequences are only defined by syntax of the .proto file: |
| 618 // a specific item belongs to only one sequence, depending on its position in |
| 619 // the .proto file definition. |
| 620 const void* descriptor_ptr = PyDescriptor_AsVoidPtr(item); |
| 621 if (descriptor_ptr == NULL) { |
| 622 // Not a descriptor, it cannot be in the list. |
| 623 return -1; |
| 624 } |
| 625 if (self->container_def->get_item_index_fn) { |
| 626 int index = self->container_def->get_item_index_fn(descriptor_ptr); |
| 627 if (index < 0 || index >= Length(self)) { |
| 628 // This index is not from this collection. |
| 629 return -1; |
| 630 } |
| 631 if (self->container_def->get_by_index_fn(self, index) != descriptor_ptr) { |
| 632 // The descriptor at this index is not the same. |
| 633 return -1; |
| 634 } |
| 635 // self[item.index] == item, so return the index. |
| 636 return index; |
| 637 } else { |
| 638 // Fall back to linear search. |
| 639 int length = Length(self); |
| 640 for (int index=0; index < length; index++) { |
| 641 if (self->container_def->get_by_index_fn(self, index) == descriptor_ptr) { |
| 642 return index; |
| 643 } |
| 644 } |
| 645 // Not found |
| 646 return -1; |
| 647 } |
| 648 } |
| 649 |
| 650 // Implements list.index(): the position of the item is in the sequence. |
| 651 static PyObject* Index(PyContainer* self, PyObject* item) { |
| 652 int position = Find(self, item); |
| 653 if (position < 0) { |
| 654 // Not found |
| 655 PyErr_SetNone(PyExc_ValueError); |
| 656 return NULL; |
| 657 } else { |
| 658 return PyInt_FromLong(position); |
| 659 } |
| 660 } |
| 661 // Implements "list.__contains__()": is the object in the sequence. |
| 662 static int SeqContains(PyContainer* self, PyObject* item) { |
| 663 int position = Find(self, item); |
| 664 if (position < 0) { |
| 665 return 0; |
| 666 } else { |
| 667 return 1; |
| 668 } |
| 669 } |
| 670 |
| 671 // Implements list.count(): number of occurrences of the item in the sequence. |
| 672 // An item can only appear once in a sequence. If it exists, return 1. |
| 673 static PyObject* Count(PyContainer* self, PyObject* item) { |
| 674 int position = Find(self, item); |
| 675 if (position < 0) { |
| 676 return PyInt_FromLong(0); |
| 677 } else { |
| 678 return PyInt_FromLong(1); |
| 679 } |
| 680 } |
| 681 |
| 682 static PyObject* Append(PyContainer* self, PyObject* args) { |
| 683 if (_CalledFromGeneratedFile(0)) { |
| 684 Py_RETURN_NONE; |
| 685 } |
| 686 PyErr_Format(PyExc_TypeError, |
| 687 "'%.200s' object is not a mutable sequence", |
| 688 Py_TYPE(self)->tp_name); |
| 689 return NULL; |
| 690 } |
| 691 |
| 692 static PyObject* Reversed(PyContainer* self, PyObject* args) { |
| 693 return NewContainerIterator(self, |
| 694 PyContainerIterator::KIND_ITERVALUE_REVERSED); |
| 695 } |
| 696 |
| 697 static PyMethodDef SeqMethods[] = { |
| 698 { "index", (PyCFunction)Index, METH_O, }, |
| 699 { "count", (PyCFunction)Count, METH_O, }, |
| 700 { "append", (PyCFunction)Append, METH_O, }, |
| 701 { "__reversed__", (PyCFunction)Reversed, METH_NOARGS, }, |
| 702 {NULL} |
| 703 }; |
| 704 |
| 705 static PySequenceMethods SeqSequenceMethods = { |
| 706 (lenfunc)Length, // sq_length |
| 707 0, // sq_concat |
| 708 0, // sq_repeat |
| 709 (ssizeargfunc)GetItem, // sq_item |
| 710 0, // sq_slice |
| 711 0, // sq_ass_item |
| 712 0, // sq_ass_slice |
| 713 (objobjproc)SeqContains, // sq_contains |
| 714 }; |
| 715 |
| 716 PyTypeObject DescriptorSequence_Type = { |
| 717 PyVarObject_HEAD_INIT(&PyType_Type, 0) |
| 718 "DescriptorSequence", // tp_name |
| 719 sizeof(PyContainer), // tp_basicsize |
| 720 0, // tp_itemsize |
| 721 0, // tp_dealloc |
| 722 0, // tp_print |
| 723 0, // tp_getattr |
| 724 0, // tp_setattr |
| 725 0, // tp_compare |
| 726 (reprfunc)ContainerRepr, // tp_repr |
| 727 0, // tp_as_number |
| 728 &SeqSequenceMethods, // tp_as_sequence |
| 729 0, // tp_as_mapping |
| 730 0, // tp_hash |
| 731 0, // tp_call |
| 732 0, // tp_str |
| 733 0, // tp_getattro |
| 734 0, // tp_setattro |
| 735 0, // tp_as_buffer |
| 736 Py_TPFLAGS_DEFAULT, // tp_flags |
| 737 0, // tp_doc |
| 738 0, // tp_traverse |
| 739 0, // tp_clear |
| 740 (richcmpfunc)RichCompare, // tp_richcompare |
| 741 0, // tp_weaklistoffset |
| 742 0, // tp_iter |
| 743 0, // tp_iternext |
| 744 SeqMethods, // tp_methods |
| 745 0, // tp_members |
| 746 0, // tp_getset |
| 747 0, // tp_base |
| 748 0, // tp_dict |
| 749 0, // tp_descr_get |
| 750 0, // tp_descr_set |
| 751 0, // tp_dictoffset |
| 752 0, // tp_init |
| 753 0, // tp_alloc |
| 754 0, // tp_new |
| 755 0, // tp_free |
| 756 }; |
| 757 |
| 758 static PyObject* NewMappingByName( |
| 759 DescriptorContainerDef* container_def, const void* descriptor) { |
| 760 PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type); |
| 761 if (self == NULL) { |
| 762 return NULL; |
| 763 } |
| 764 self->descriptor = descriptor; |
| 765 self->container_def = container_def; |
| 766 self->kind = PyContainer::KIND_BYNAME; |
| 767 return reinterpret_cast<PyObject*>(self); |
| 768 } |
| 769 |
| 770 static PyObject* NewMappingByCamelcaseName( |
| 771 DescriptorContainerDef* container_def, const void* descriptor) { |
| 772 PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type); |
| 773 if (self == NULL) { |
| 774 return NULL; |
| 775 } |
| 776 self->descriptor = descriptor; |
| 777 self->container_def = container_def; |
| 778 self->kind = PyContainer::KIND_BYCAMELCASENAME; |
| 779 return reinterpret_cast<PyObject*>(self); |
| 780 } |
| 781 |
| 782 static PyObject* NewMappingByNumber( |
| 783 DescriptorContainerDef* container_def, const void* descriptor) { |
| 784 if (container_def->get_by_number_fn == NULL || |
| 785 container_def->get_item_number_fn == NULL) { |
| 786 PyErr_SetNone(PyExc_NotImplementedError); |
| 787 return NULL; |
| 788 } |
| 789 PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type); |
| 790 if (self == NULL) { |
| 791 return NULL; |
| 792 } |
| 793 self->descriptor = descriptor; |
| 794 self->container_def = container_def; |
| 795 self->kind = PyContainer::KIND_BYNUMBER; |
| 796 return reinterpret_cast<PyObject*>(self); |
| 797 } |
| 798 |
| 799 static PyObject* NewSequence( |
| 800 DescriptorContainerDef* container_def, const void* descriptor) { |
| 801 PyContainer* self = PyObject_New(PyContainer, &DescriptorSequence_Type); |
| 802 if (self == NULL) { |
| 803 return NULL; |
| 804 } |
| 805 self->descriptor = descriptor; |
| 806 self->container_def = container_def; |
| 807 self->kind = PyContainer::KIND_SEQUENCE; |
| 808 return reinterpret_cast<PyObject*>(self); |
| 809 } |
| 810 |
| 811 // Implement iterators over PyContainers. |
| 812 |
| 813 static void Iterator_Dealloc(PyContainerIterator* self) { |
| 814 Py_CLEAR(self->container); |
| 815 Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); |
| 816 } |
| 817 |
| 818 static PyObject* Iterator_Next(PyContainerIterator* self) { |
| 819 int count = self->container->container_def->count_fn(self->container); |
| 820 if (self->index >= count) { |
| 821 // Return NULL with no exception to indicate the end. |
| 822 return NULL; |
| 823 } |
| 824 int index = self->index; |
| 825 self->index += 1; |
| 826 switch (self->kind) { |
| 827 case PyContainerIterator::KIND_ITERKEY: |
| 828 return _NewKey_ByIndex(self->container, index); |
| 829 case PyContainerIterator::KIND_ITERVALUE: |
| 830 return _NewObj_ByIndex(self->container, index); |
| 831 case PyContainerIterator::KIND_ITERVALUE_REVERSED: |
| 832 return _NewObj_ByIndex(self->container, count - index - 1); |
| 833 case PyContainerIterator::KIND_ITERITEM: |
| 834 { |
| 835 PyObject* obj = PyTuple_New(2); |
| 836 if (obj == NULL) { |
| 837 return NULL; |
| 838 } |
| 839 PyObject* key = _NewKey_ByIndex(self->container, index); |
| 840 if (key == NULL) { |
| 841 Py_DECREF(obj); |
| 842 return NULL; |
| 843 } |
| 844 PyTuple_SET_ITEM(obj, 0, key); |
| 845 PyObject* value = _NewObj_ByIndex(self->container, index); |
| 846 if (value == NULL) { |
| 847 Py_DECREF(obj); |
| 848 return NULL; |
| 849 } |
| 850 PyTuple_SET_ITEM(obj, 1, value); |
| 851 return obj; |
| 852 } |
| 853 default: |
| 854 PyErr_SetNone(PyExc_NotImplementedError); |
| 855 return NULL; |
| 856 } |
| 857 } |
| 858 |
| 859 static PyTypeObject ContainerIterator_Type = { |
| 860 PyVarObject_HEAD_INIT(&PyType_Type, 0) |
| 861 "DescriptorContainerIterator", // tp_name |
| 862 sizeof(PyContainerIterator), // tp_basicsize |
| 863 0, // tp_itemsize |
| 864 (destructor)Iterator_Dealloc, // tp_dealloc |
| 865 0, // tp_print |
| 866 0, // tp_getattr |
| 867 0, // tp_setattr |
| 868 0, // tp_compare |
| 869 0, // tp_repr |
| 870 0, // tp_as_number |
| 871 0, // tp_as_sequence |
| 872 0, // tp_as_mapping |
| 873 0, // tp_hash |
| 874 0, // tp_call |
| 875 0, // tp_str |
| 876 0, // tp_getattro |
| 877 0, // tp_setattro |
| 878 0, // tp_as_buffer |
| 879 Py_TPFLAGS_DEFAULT, // tp_flags |
| 880 0, // tp_doc |
| 881 0, // tp_traverse |
| 882 0, // tp_clear |
| 883 0, // tp_richcompare |
| 884 0, // tp_weaklistoffset |
| 885 PyObject_SelfIter, // tp_iter |
| 886 (iternextfunc)Iterator_Next, // tp_iternext |
| 887 0, // tp_methods |
| 888 0, // tp_members |
| 889 0, // tp_getset |
| 890 0, // tp_base |
| 891 0, // tp_dict |
| 892 0, // tp_descr_get |
| 893 0, // tp_descr_set |
| 894 0, // tp_dictoffset |
| 895 0, // tp_init |
| 896 0, // tp_alloc |
| 897 0, // tp_new |
| 898 0, // tp_free |
| 899 }; |
| 900 |
| 901 static PyObject* NewContainerIterator(PyContainer* container, |
| 902 PyContainerIterator::IterKind kind) { |
| 903 PyContainerIterator* self = PyObject_New(PyContainerIterator, |
| 904 &ContainerIterator_Type); |
| 905 if (self == NULL) { |
| 906 return NULL; |
| 907 } |
| 908 Py_INCREF(container); |
| 909 self->container = container; |
| 910 self->kind = kind; |
| 911 self->index = 0; |
| 912 |
| 913 return reinterpret_cast<PyObject*>(self); |
| 914 } |
| 915 |
| 916 } // namespace descriptor |
| 917 |
| 918 // Now define the real collections! |
| 919 |
| 920 namespace message_descriptor { |
| 921 |
| 922 typedef const Descriptor* ParentDescriptor; |
| 923 |
| 924 static ParentDescriptor GetDescriptor(PyContainer* self) { |
| 925 return reinterpret_cast<ParentDescriptor>(self->descriptor); |
| 926 } |
| 927 |
| 928 namespace fields { |
| 929 |
| 930 typedef const FieldDescriptor* ItemDescriptor; |
| 931 |
| 932 static int Count(PyContainer* self) { |
| 933 return GetDescriptor(self)->field_count(); |
| 934 } |
| 935 |
| 936 static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| 937 return GetDescriptor(self)->FindFieldByName(name); |
| 938 } |
| 939 |
| 940 static ItemDescriptor GetByCamelcaseName(PyContainer* self, |
| 941 const string& name) { |
| 942 return GetDescriptor(self)->FindFieldByCamelcaseName(name); |
| 943 } |
| 944 |
| 945 static ItemDescriptor GetByNumber(PyContainer* self, int number) { |
| 946 return GetDescriptor(self)->FindFieldByNumber(number); |
| 947 } |
| 948 |
| 949 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 950 return GetDescriptor(self)->field(index); |
| 951 } |
| 952 |
| 953 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 954 return PyFieldDescriptor_FromDescriptor(item); |
| 955 } |
| 956 |
| 957 static const string& GetItemName(ItemDescriptor item) { |
| 958 return item->name(); |
| 959 } |
| 960 |
| 961 static const string& GetItemCamelcaseName(ItemDescriptor item) { |
| 962 return item->camelcase_name(); |
| 963 } |
| 964 |
| 965 static int GetItemNumber(ItemDescriptor item) { |
| 966 return item->number(); |
| 967 } |
| 968 |
| 969 static int GetItemIndex(ItemDescriptor item) { |
| 970 return item->index(); |
| 971 } |
| 972 |
| 973 static DescriptorContainerDef ContainerDef = { |
| 974 "MessageFields", |
| 975 (CountMethod)Count, |
| 976 (GetByIndexMethod)GetByIndex, |
| 977 (GetByNameMethod)GetByName, |
| 978 (GetByCamelcaseNameMethod)GetByCamelcaseName, |
| 979 (GetByNumberMethod)GetByNumber, |
| 980 (NewObjectFromItemMethod)NewObjectFromItem, |
| 981 (GetItemNameMethod)GetItemName, |
| 982 (GetItemCamelcaseNameMethod)GetItemCamelcaseName, |
| 983 (GetItemNumberMethod)GetItemNumber, |
| 984 (GetItemIndexMethod)GetItemIndex, |
| 985 }; |
| 986 |
| 987 } // namespace fields |
| 988 |
| 989 PyObject* NewMessageFieldsByName(ParentDescriptor descriptor) { |
| 990 return descriptor::NewMappingByName(&fields::ContainerDef, descriptor); |
| 991 } |
| 992 |
| 993 PyObject* NewMessageFieldsByCamelcaseName(ParentDescriptor descriptor) { |
| 994 return descriptor::NewMappingByCamelcaseName(&fields::ContainerDef, |
| 995 descriptor); |
| 996 } |
| 997 |
| 998 PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) { |
| 999 return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor); |
| 1000 } |
| 1001 |
| 1002 PyObject* NewMessageFieldsSeq(ParentDescriptor descriptor) { |
| 1003 return descriptor::NewSequence(&fields::ContainerDef, descriptor); |
| 1004 } |
| 1005 |
| 1006 namespace nested_types { |
| 1007 |
| 1008 typedef const Descriptor* ItemDescriptor; |
| 1009 |
| 1010 static int Count(PyContainer* self) { |
| 1011 return GetDescriptor(self)->nested_type_count(); |
| 1012 } |
| 1013 |
| 1014 static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| 1015 return GetDescriptor(self)->FindNestedTypeByName(name); |
| 1016 } |
| 1017 |
| 1018 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1019 return GetDescriptor(self)->nested_type(index); |
| 1020 } |
| 1021 |
| 1022 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1023 return PyMessageDescriptor_FromDescriptor(item); |
| 1024 } |
| 1025 |
| 1026 static const string& GetItemName(ItemDescriptor item) { |
| 1027 return item->name(); |
| 1028 } |
| 1029 |
| 1030 static int GetItemIndex(ItemDescriptor item) { |
| 1031 return item->index(); |
| 1032 } |
| 1033 |
| 1034 static DescriptorContainerDef ContainerDef = { |
| 1035 "MessageNestedTypes", |
| 1036 (CountMethod)Count, |
| 1037 (GetByIndexMethod)GetByIndex, |
| 1038 (GetByNameMethod)GetByName, |
| 1039 (GetByCamelcaseNameMethod)NULL, |
| 1040 (GetByNumberMethod)NULL, |
| 1041 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1042 (GetItemNameMethod)GetItemName, |
| 1043 (GetItemCamelcaseNameMethod)NULL, |
| 1044 (GetItemNumberMethod)NULL, |
| 1045 (GetItemIndexMethod)GetItemIndex, |
| 1046 }; |
| 1047 |
| 1048 } // namespace nested_types |
| 1049 |
| 1050 PyObject* NewMessageNestedTypesSeq(ParentDescriptor descriptor) { |
| 1051 return descriptor::NewSequence(&nested_types::ContainerDef, descriptor); |
| 1052 } |
| 1053 |
| 1054 PyObject* NewMessageNestedTypesByName(ParentDescriptor descriptor) { |
| 1055 return descriptor::NewMappingByName(&nested_types::ContainerDef, descriptor); |
| 1056 } |
| 1057 |
| 1058 namespace enums { |
| 1059 |
| 1060 typedef const EnumDescriptor* ItemDescriptor; |
| 1061 |
| 1062 static int Count(PyContainer* self) { |
| 1063 return GetDescriptor(self)->enum_type_count(); |
| 1064 } |
| 1065 |
| 1066 static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| 1067 return GetDescriptor(self)->FindEnumTypeByName(name); |
| 1068 } |
| 1069 |
| 1070 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1071 return GetDescriptor(self)->enum_type(index); |
| 1072 } |
| 1073 |
| 1074 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1075 return PyEnumDescriptor_FromDescriptor(item); |
| 1076 } |
| 1077 |
| 1078 static const string& GetItemName(ItemDescriptor item) { |
| 1079 return item->name(); |
| 1080 } |
| 1081 |
| 1082 static int GetItemIndex(ItemDescriptor item) { |
| 1083 return item->index(); |
| 1084 } |
| 1085 |
| 1086 static DescriptorContainerDef ContainerDef = { |
| 1087 "MessageNestedEnums", |
| 1088 (CountMethod)Count, |
| 1089 (GetByIndexMethod)GetByIndex, |
| 1090 (GetByNameMethod)GetByName, |
| 1091 (GetByCamelcaseNameMethod)NULL, |
| 1092 (GetByNumberMethod)NULL, |
| 1093 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1094 (GetItemNameMethod)GetItemName, |
| 1095 (GetItemCamelcaseNameMethod)NULL, |
| 1096 (GetItemNumberMethod)NULL, |
| 1097 (GetItemIndexMethod)GetItemIndex, |
| 1098 }; |
| 1099 |
| 1100 } // namespace enums |
| 1101 |
| 1102 PyObject* NewMessageEnumsByName(ParentDescriptor descriptor) { |
| 1103 return descriptor::NewMappingByName(&enums::ContainerDef, descriptor); |
| 1104 } |
| 1105 |
| 1106 PyObject* NewMessageEnumsSeq(ParentDescriptor descriptor) { |
| 1107 return descriptor::NewSequence(&enums::ContainerDef, descriptor); |
| 1108 } |
| 1109 |
| 1110 namespace enumvalues { |
| 1111 |
| 1112 // This is the "enum_values_by_name" mapping, which collects values from all |
| 1113 // enum types in a message. |
| 1114 // |
| 1115 // Note that the behavior of the C++ descriptor is different: it will search and |
| 1116 // return the first value that matches the name, whereas the Python |
| 1117 // implementation retrieves the last one. |
| 1118 |
| 1119 typedef const EnumValueDescriptor* ItemDescriptor; |
| 1120 |
| 1121 static int Count(PyContainer* self) { |
| 1122 int count = 0; |
| 1123 for (int i = 0; i < GetDescriptor(self)->enum_type_count(); ++i) { |
| 1124 count += GetDescriptor(self)->enum_type(i)->value_count(); |
| 1125 } |
| 1126 return count; |
| 1127 } |
| 1128 |
| 1129 static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| 1130 return GetDescriptor(self)->FindEnumValueByName(name); |
| 1131 } |
| 1132 |
| 1133 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1134 // This is not optimal, but the number of enums *types* in a given message |
| 1135 // is small. This function is only used when iterating over the mapping. |
| 1136 const EnumDescriptor* enum_type = NULL; |
| 1137 int enum_type_count = GetDescriptor(self)->enum_type_count(); |
| 1138 for (int i = 0; i < enum_type_count; ++i) { |
| 1139 enum_type = GetDescriptor(self)->enum_type(i); |
| 1140 int enum_value_count = enum_type->value_count(); |
| 1141 if (index < enum_value_count) { |
| 1142 // Found it! |
| 1143 break; |
| 1144 } |
| 1145 index -= enum_value_count; |
| 1146 } |
| 1147 // The next statement cannot overflow, because this function is only called by |
| 1148 // internal iterators which ensure that 0 <= index < Count(). |
| 1149 return enum_type->value(index); |
| 1150 } |
| 1151 |
| 1152 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1153 return PyEnumValueDescriptor_FromDescriptor(item); |
| 1154 } |
| 1155 |
| 1156 static const string& GetItemName(ItemDescriptor item) { |
| 1157 return item->name(); |
| 1158 } |
| 1159 |
| 1160 static DescriptorContainerDef ContainerDef = { |
| 1161 "MessageEnumValues", |
| 1162 (CountMethod)Count, |
| 1163 (GetByIndexMethod)GetByIndex, |
| 1164 (GetByNameMethod)GetByName, |
| 1165 (GetByCamelcaseNameMethod)NULL, |
| 1166 (GetByNumberMethod)NULL, |
| 1167 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1168 (GetItemNameMethod)GetItemName, |
| 1169 (GetItemCamelcaseNameMethod)NULL, |
| 1170 (GetItemNumberMethod)NULL, |
| 1171 (GetItemIndexMethod)NULL, |
| 1172 }; |
| 1173 |
| 1174 } // namespace enumvalues |
| 1175 |
| 1176 PyObject* NewMessageEnumValuesByName(ParentDescriptor descriptor) { |
| 1177 return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor); |
| 1178 } |
| 1179 |
| 1180 namespace extensions { |
| 1181 |
| 1182 typedef const FieldDescriptor* ItemDescriptor; |
| 1183 |
| 1184 static int Count(PyContainer* self) { |
| 1185 return GetDescriptor(self)->extension_count(); |
| 1186 } |
| 1187 |
| 1188 static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| 1189 return GetDescriptor(self)->FindExtensionByName(name); |
| 1190 } |
| 1191 |
| 1192 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1193 return GetDescriptor(self)->extension(index); |
| 1194 } |
| 1195 |
| 1196 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1197 return PyFieldDescriptor_FromDescriptor(item); |
| 1198 } |
| 1199 |
| 1200 static const string& GetItemName(ItemDescriptor item) { |
| 1201 return item->name(); |
| 1202 } |
| 1203 |
| 1204 static int GetItemIndex(ItemDescriptor item) { |
| 1205 return item->index(); |
| 1206 } |
| 1207 |
| 1208 static DescriptorContainerDef ContainerDef = { |
| 1209 "MessageExtensions", |
| 1210 (CountMethod)Count, |
| 1211 (GetByIndexMethod)GetByIndex, |
| 1212 (GetByNameMethod)GetByName, |
| 1213 (GetByCamelcaseNameMethod)NULL, |
| 1214 (GetByNumberMethod)NULL, |
| 1215 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1216 (GetItemNameMethod)GetItemName, |
| 1217 (GetItemCamelcaseNameMethod)NULL, |
| 1218 (GetItemNumberMethod)NULL, |
| 1219 (GetItemIndexMethod)GetItemIndex, |
| 1220 }; |
| 1221 |
| 1222 } // namespace extensions |
| 1223 |
| 1224 PyObject* NewMessageExtensionsByName(ParentDescriptor descriptor) { |
| 1225 return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor); |
| 1226 } |
| 1227 |
| 1228 PyObject* NewMessageExtensionsSeq(ParentDescriptor descriptor) { |
| 1229 return descriptor::NewSequence(&extensions::ContainerDef, descriptor); |
| 1230 } |
| 1231 |
| 1232 namespace oneofs { |
| 1233 |
| 1234 typedef const OneofDescriptor* ItemDescriptor; |
| 1235 |
| 1236 static int Count(PyContainer* self) { |
| 1237 return GetDescriptor(self)->oneof_decl_count(); |
| 1238 } |
| 1239 |
| 1240 static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| 1241 return GetDescriptor(self)->FindOneofByName(name); |
| 1242 } |
| 1243 |
| 1244 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1245 return GetDescriptor(self)->oneof_decl(index); |
| 1246 } |
| 1247 |
| 1248 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1249 return PyOneofDescriptor_FromDescriptor(item); |
| 1250 } |
| 1251 |
| 1252 static const string& GetItemName(ItemDescriptor item) { |
| 1253 return item->name(); |
| 1254 } |
| 1255 |
| 1256 static int GetItemIndex(ItemDescriptor item) { |
| 1257 return item->index(); |
| 1258 } |
| 1259 |
| 1260 static DescriptorContainerDef ContainerDef = { |
| 1261 "MessageOneofs", |
| 1262 (CountMethod)Count, |
| 1263 (GetByIndexMethod)GetByIndex, |
| 1264 (GetByNameMethod)GetByName, |
| 1265 (GetByCamelcaseNameMethod)NULL, |
| 1266 (GetByNumberMethod)NULL, |
| 1267 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1268 (GetItemNameMethod)GetItemName, |
| 1269 (GetItemCamelcaseNameMethod)NULL, |
| 1270 (GetItemNumberMethod)NULL, |
| 1271 (GetItemIndexMethod)GetItemIndex, |
| 1272 }; |
| 1273 |
| 1274 } // namespace oneofs |
| 1275 |
| 1276 PyObject* NewMessageOneofsByName(ParentDescriptor descriptor) { |
| 1277 return descriptor::NewMappingByName(&oneofs::ContainerDef, descriptor); |
| 1278 } |
| 1279 |
| 1280 PyObject* NewMessageOneofsSeq(ParentDescriptor descriptor) { |
| 1281 return descriptor::NewSequence(&oneofs::ContainerDef, descriptor); |
| 1282 } |
| 1283 |
| 1284 } // namespace message_descriptor |
| 1285 |
| 1286 namespace enum_descriptor { |
| 1287 |
| 1288 typedef const EnumDescriptor* ParentDescriptor; |
| 1289 |
| 1290 static ParentDescriptor GetDescriptor(PyContainer* self) { |
| 1291 return reinterpret_cast<ParentDescriptor>(self->descriptor); |
| 1292 } |
| 1293 |
| 1294 namespace enumvalues { |
| 1295 |
| 1296 typedef const EnumValueDescriptor* ItemDescriptor; |
| 1297 |
| 1298 static int Count(PyContainer* self) { |
| 1299 return GetDescriptor(self)->value_count(); |
| 1300 } |
| 1301 |
| 1302 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1303 return GetDescriptor(self)->value(index); |
| 1304 } |
| 1305 |
| 1306 static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| 1307 return GetDescriptor(self)->FindValueByName(name); |
| 1308 } |
| 1309 |
| 1310 static ItemDescriptor GetByNumber(PyContainer* self, int number) { |
| 1311 return GetDescriptor(self)->FindValueByNumber(number); |
| 1312 } |
| 1313 |
| 1314 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1315 return PyEnumValueDescriptor_FromDescriptor(item); |
| 1316 } |
| 1317 |
| 1318 static const string& GetItemName(ItemDescriptor item) { |
| 1319 return item->name(); |
| 1320 } |
| 1321 |
| 1322 static int GetItemNumber(ItemDescriptor item) { |
| 1323 return item->number(); |
| 1324 } |
| 1325 |
| 1326 static int GetItemIndex(ItemDescriptor item) { |
| 1327 return item->index(); |
| 1328 } |
| 1329 |
| 1330 static DescriptorContainerDef ContainerDef = { |
| 1331 "EnumValues", |
| 1332 (CountMethod)Count, |
| 1333 (GetByIndexMethod)GetByIndex, |
| 1334 (GetByNameMethod)GetByName, |
| 1335 (GetByCamelcaseNameMethod)NULL, |
| 1336 (GetByNumberMethod)GetByNumber, |
| 1337 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1338 (GetItemNameMethod)GetItemName, |
| 1339 (GetItemCamelcaseNameMethod)NULL, |
| 1340 (GetItemNumberMethod)GetItemNumber, |
| 1341 (GetItemIndexMethod)GetItemIndex, |
| 1342 }; |
| 1343 |
| 1344 } // namespace enumvalues |
| 1345 |
| 1346 PyObject* NewEnumValuesByName(ParentDescriptor descriptor) { |
| 1347 return descriptor::NewMappingByName(&enumvalues::ContainerDef, descriptor); |
| 1348 } |
| 1349 |
| 1350 PyObject* NewEnumValuesByNumber(ParentDescriptor descriptor) { |
| 1351 return descriptor::NewMappingByNumber(&enumvalues::ContainerDef, descriptor); |
| 1352 } |
| 1353 |
| 1354 PyObject* NewEnumValuesSeq(ParentDescriptor descriptor) { |
| 1355 return descriptor::NewSequence(&enumvalues::ContainerDef, descriptor); |
| 1356 } |
| 1357 |
| 1358 } // namespace enum_descriptor |
| 1359 |
| 1360 namespace oneof_descriptor { |
| 1361 |
| 1362 typedef const OneofDescriptor* ParentDescriptor; |
| 1363 |
| 1364 static ParentDescriptor GetDescriptor(PyContainer* self) { |
| 1365 return reinterpret_cast<ParentDescriptor>(self->descriptor); |
| 1366 } |
| 1367 |
| 1368 namespace fields { |
| 1369 |
| 1370 typedef const FieldDescriptor* ItemDescriptor; |
| 1371 |
| 1372 static int Count(PyContainer* self) { |
| 1373 return GetDescriptor(self)->field_count(); |
| 1374 } |
| 1375 |
| 1376 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1377 return GetDescriptor(self)->field(index); |
| 1378 } |
| 1379 |
| 1380 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1381 return PyFieldDescriptor_FromDescriptor(item); |
| 1382 } |
| 1383 |
| 1384 static int GetItemIndex(ItemDescriptor item) { |
| 1385 return item->index_in_oneof(); |
| 1386 } |
| 1387 |
| 1388 static DescriptorContainerDef ContainerDef = { |
| 1389 "OneofFields", |
| 1390 (CountMethod)Count, |
| 1391 (GetByIndexMethod)GetByIndex, |
| 1392 (GetByNameMethod)NULL, |
| 1393 (GetByCamelcaseNameMethod)NULL, |
| 1394 (GetByNumberMethod)NULL, |
| 1395 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1396 (GetItemNameMethod)NULL, |
| 1397 (GetItemCamelcaseNameMethod)NULL, |
| 1398 (GetItemNumberMethod)NULL, |
| 1399 (GetItemIndexMethod)GetItemIndex, |
| 1400 }; |
| 1401 |
| 1402 } // namespace fields |
| 1403 |
| 1404 PyObject* NewOneofFieldsSeq(ParentDescriptor descriptor) { |
| 1405 return descriptor::NewSequence(&fields::ContainerDef, descriptor); |
| 1406 } |
| 1407 |
| 1408 } // namespace oneof_descriptor |
| 1409 |
| 1410 namespace file_descriptor { |
| 1411 |
| 1412 typedef const FileDescriptor* ParentDescriptor; |
| 1413 |
| 1414 static ParentDescriptor GetDescriptor(PyContainer* self) { |
| 1415 return reinterpret_cast<ParentDescriptor>(self->descriptor); |
| 1416 } |
| 1417 |
| 1418 namespace messages { |
| 1419 |
| 1420 typedef const Descriptor* ItemDescriptor; |
| 1421 |
| 1422 static int Count(PyContainer* self) { |
| 1423 return GetDescriptor(self)->message_type_count(); |
| 1424 } |
| 1425 |
| 1426 static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| 1427 return GetDescriptor(self)->FindMessageTypeByName(name); |
| 1428 } |
| 1429 |
| 1430 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1431 return GetDescriptor(self)->message_type(index); |
| 1432 } |
| 1433 |
| 1434 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1435 return PyMessageDescriptor_FromDescriptor(item); |
| 1436 } |
| 1437 |
| 1438 static const string& GetItemName(ItemDescriptor item) { |
| 1439 return item->name(); |
| 1440 } |
| 1441 |
| 1442 static int GetItemIndex(ItemDescriptor item) { |
| 1443 return item->index(); |
| 1444 } |
| 1445 |
| 1446 static DescriptorContainerDef ContainerDef = { |
| 1447 "FileMessages", |
| 1448 (CountMethod)Count, |
| 1449 (GetByIndexMethod)GetByIndex, |
| 1450 (GetByNameMethod)GetByName, |
| 1451 (GetByCamelcaseNameMethod)NULL, |
| 1452 (GetByNumberMethod)NULL, |
| 1453 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1454 (GetItemNameMethod)GetItemName, |
| 1455 (GetItemCamelcaseNameMethod)NULL, |
| 1456 (GetItemNumberMethod)NULL, |
| 1457 (GetItemIndexMethod)GetItemIndex, |
| 1458 }; |
| 1459 |
| 1460 } // namespace messages |
| 1461 |
| 1462 PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor) { |
| 1463 return descriptor::NewMappingByName(&messages::ContainerDef, descriptor); |
| 1464 } |
| 1465 |
| 1466 namespace enums { |
| 1467 |
| 1468 typedef const EnumDescriptor* ItemDescriptor; |
| 1469 |
| 1470 static int Count(PyContainer* self) { |
| 1471 return GetDescriptor(self)->enum_type_count(); |
| 1472 } |
| 1473 |
| 1474 static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| 1475 return GetDescriptor(self)->FindEnumTypeByName(name); |
| 1476 } |
| 1477 |
| 1478 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1479 return GetDescriptor(self)->enum_type(index); |
| 1480 } |
| 1481 |
| 1482 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1483 return PyEnumDescriptor_FromDescriptor(item); |
| 1484 } |
| 1485 |
| 1486 static const string& GetItemName(ItemDescriptor item) { |
| 1487 return item->name(); |
| 1488 } |
| 1489 |
| 1490 static int GetItemIndex(ItemDescriptor item) { |
| 1491 return item->index(); |
| 1492 } |
| 1493 |
| 1494 static DescriptorContainerDef ContainerDef = { |
| 1495 "FileEnums", |
| 1496 (CountMethod)Count, |
| 1497 (GetByIndexMethod)GetByIndex, |
| 1498 (GetByNameMethod)GetByName, |
| 1499 (GetByCamelcaseNameMethod)NULL, |
| 1500 (GetByNumberMethod)NULL, |
| 1501 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1502 (GetItemNameMethod)GetItemName, |
| 1503 (GetItemCamelcaseNameMethod)NULL, |
| 1504 (GetItemNumberMethod)NULL, |
| 1505 (GetItemIndexMethod)GetItemIndex, |
| 1506 }; |
| 1507 |
| 1508 } // namespace enums |
| 1509 |
| 1510 PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor) { |
| 1511 return descriptor::NewMappingByName(&enums::ContainerDef, descriptor); |
| 1512 } |
| 1513 |
| 1514 namespace extensions { |
| 1515 |
| 1516 typedef const FieldDescriptor* ItemDescriptor; |
| 1517 |
| 1518 static int Count(PyContainer* self) { |
| 1519 return GetDescriptor(self)->extension_count(); |
| 1520 } |
| 1521 |
| 1522 static ItemDescriptor GetByName(PyContainer* self, const string& name) { |
| 1523 return GetDescriptor(self)->FindExtensionByName(name); |
| 1524 } |
| 1525 |
| 1526 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1527 return GetDescriptor(self)->extension(index); |
| 1528 } |
| 1529 |
| 1530 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1531 return PyFieldDescriptor_FromDescriptor(item); |
| 1532 } |
| 1533 |
| 1534 static const string& GetItemName(ItemDescriptor item) { |
| 1535 return item->name(); |
| 1536 } |
| 1537 |
| 1538 static int GetItemIndex(ItemDescriptor item) { |
| 1539 return item->index(); |
| 1540 } |
| 1541 |
| 1542 static DescriptorContainerDef ContainerDef = { |
| 1543 "FileExtensions", |
| 1544 (CountMethod)Count, |
| 1545 (GetByIndexMethod)GetByIndex, |
| 1546 (GetByNameMethod)GetByName, |
| 1547 (GetByCamelcaseNameMethod)NULL, |
| 1548 (GetByNumberMethod)NULL, |
| 1549 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1550 (GetItemNameMethod)GetItemName, |
| 1551 (GetItemCamelcaseNameMethod)NULL, |
| 1552 (GetItemNumberMethod)NULL, |
| 1553 (GetItemIndexMethod)GetItemIndex, |
| 1554 }; |
| 1555 |
| 1556 } // namespace extensions |
| 1557 |
| 1558 PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor) { |
| 1559 return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor); |
| 1560 } |
| 1561 |
| 1562 namespace dependencies { |
| 1563 |
| 1564 typedef const FileDescriptor* ItemDescriptor; |
| 1565 |
| 1566 static int Count(PyContainer* self) { |
| 1567 return GetDescriptor(self)->dependency_count(); |
| 1568 } |
| 1569 |
| 1570 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1571 return GetDescriptor(self)->dependency(index); |
| 1572 } |
| 1573 |
| 1574 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1575 return PyFileDescriptor_FromDescriptor(item); |
| 1576 } |
| 1577 |
| 1578 static DescriptorContainerDef ContainerDef = { |
| 1579 "FileDependencies", |
| 1580 (CountMethod)Count, |
| 1581 (GetByIndexMethod)GetByIndex, |
| 1582 (GetByNameMethod)NULL, |
| 1583 (GetByCamelcaseNameMethod)NULL, |
| 1584 (GetByNumberMethod)NULL, |
| 1585 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1586 (GetItemNameMethod)NULL, |
| 1587 (GetItemCamelcaseNameMethod)NULL, |
| 1588 (GetItemNumberMethod)NULL, |
| 1589 (GetItemIndexMethod)NULL, |
| 1590 }; |
| 1591 |
| 1592 } // namespace dependencies |
| 1593 |
| 1594 PyObject* NewFileDependencies(const FileDescriptor* descriptor) { |
| 1595 return descriptor::NewSequence(&dependencies::ContainerDef, descriptor); |
| 1596 } |
| 1597 |
| 1598 namespace public_dependencies { |
| 1599 |
| 1600 typedef const FileDescriptor* ItemDescriptor; |
| 1601 |
| 1602 static int Count(PyContainer* self) { |
| 1603 return GetDescriptor(self)->public_dependency_count(); |
| 1604 } |
| 1605 |
| 1606 static ItemDescriptor GetByIndex(PyContainer* self, int index) { |
| 1607 return GetDescriptor(self)->public_dependency(index); |
| 1608 } |
| 1609 |
| 1610 static PyObject* NewObjectFromItem(ItemDescriptor item) { |
| 1611 return PyFileDescriptor_FromDescriptor(item); |
| 1612 } |
| 1613 |
| 1614 static DescriptorContainerDef ContainerDef = { |
| 1615 "FilePublicDependencies", |
| 1616 (CountMethod)Count, |
| 1617 (GetByIndexMethod)GetByIndex, |
| 1618 (GetByNameMethod)NULL, |
| 1619 (GetByCamelcaseNameMethod)NULL, |
| 1620 (GetByNumberMethod)NULL, |
| 1621 (NewObjectFromItemMethod)NewObjectFromItem, |
| 1622 (GetItemNameMethod)NULL, |
| 1623 (GetItemCamelcaseNameMethod)NULL, |
| 1624 (GetItemNumberMethod)NULL, |
| 1625 (GetItemIndexMethod)NULL, |
| 1626 }; |
| 1627 |
| 1628 } // namespace public_dependencies |
| 1629 |
| 1630 PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor) { |
| 1631 return descriptor::NewSequence(&public_dependencies::ContainerDef, |
| 1632 descriptor); |
| 1633 } |
| 1634 |
| 1635 } // namespace file_descriptor |
| 1636 |
| 1637 |
| 1638 // Register all implementations |
| 1639 |
| 1640 bool InitDescriptorMappingTypes() { |
| 1641 if (PyType_Ready(&descriptor::DescriptorMapping_Type) < 0) |
| 1642 return false; |
| 1643 if (PyType_Ready(&descriptor::DescriptorSequence_Type) < 0) |
| 1644 return false; |
| 1645 if (PyType_Ready(&descriptor::ContainerIterator_Type) < 0) |
| 1646 return false; |
| 1647 return true; |
| 1648 } |
| 1649 |
| 1650 } // namespace python |
| 1651 } // namespace protobuf |
| 1652 } // namespace google |
OLD | NEW |