1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// https://developers.google.com/protocol-buffers/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31// Author: anuraag@google.com (Anuraag Agrawal) 32// Author: tibell@google.com (Johan Tibell) 33 34#include <google/protobuf/pyext/repeated_composite_container.h> 35 36#include <memory> 37#ifndef _SHARED_PTR_H 38#include <google/protobuf/stubs/shared_ptr.h> 39#endif 40 41#include <google/protobuf/stubs/common.h> 42#include <google/protobuf/descriptor.h> 43#include <google/protobuf/dynamic_message.h> 44#include <google/protobuf/message.h> 45#include <google/protobuf/pyext/descriptor.h> 46#include <google/protobuf/pyext/message.h> 47#include <google/protobuf/pyext/scoped_pyobject_ptr.h> 48 49#if PY_MAJOR_VERSION >= 3 50 #define PyInt_Check PyLong_Check 51 #define PyInt_AsLong PyLong_AsLong 52 #define PyInt_FromLong PyLong_FromLong 53#endif 54 55namespace google { 56namespace protobuf { 57namespace python { 58 59extern google::protobuf::DynamicMessageFactory* global_message_factory; 60 61namespace repeated_composite_container { 62 63// TODO(tibell): We might also want to check: 64// GOOGLE_CHECK_NOTNULL((self)->owner.get()); 65#define GOOGLE_CHECK_ATTACHED(self) \ 66 do { \ 67 GOOGLE_CHECK_NOTNULL((self)->message); \ 68 GOOGLE_CHECK_NOTNULL((self)->parent_field); \ 69 } while (0); 70 71#define GOOGLE_CHECK_RELEASED(self) \ 72 do { \ 73 GOOGLE_CHECK((self)->owner.get() == NULL); \ 74 GOOGLE_CHECK((self)->message == NULL); \ 75 GOOGLE_CHECK((self)->parent_field == NULL); \ 76 GOOGLE_CHECK((self)->parent == NULL); \ 77 } while (0); 78 79// Returns a new reference. 80static PyObject* GetKey(PyObject* x) { 81 // Just the identity function. 82 Py_INCREF(x); 83 return x; 84} 85 86#define GET_KEY(keyfunc, value) \ 87 ((keyfunc) == NULL ? \ 88 GetKey((value)) : \ 89 PyObject_CallFunctionObjArgs((keyfunc), (value), NULL)) 90 91// Converts a comparison function that returns -1, 0, or 1 into a 92// less-than predicate. 93// 94// Returns -1 on error, 1 if x < y, 0 if x >= y. 95static int islt(PyObject *x, PyObject *y, PyObject *compare) { 96 if (compare == NULL) 97 return PyObject_RichCompareBool(x, y, Py_LT); 98 99 ScopedPyObjectPtr res(PyObject_CallFunctionObjArgs(compare, x, y, NULL)); 100 if (res == NULL) 101 return -1; 102 if (!PyInt_Check(res)) { 103 PyErr_Format(PyExc_TypeError, 104 "comparison function must return int, not %.200s", 105 Py_TYPE(res)->tp_name); 106 return -1; 107 } 108 return PyInt_AsLong(res) < 0; 109} 110 111// Copied from uarrsort.c but swaps memcpy swaps with protobuf/python swaps 112// TODO(anuraag): Is there a better way to do this then reinventing the wheel? 113static int InternalQuickSort(RepeatedCompositeContainer* self, 114 Py_ssize_t start, 115 Py_ssize_t limit, 116 PyObject* cmp, 117 PyObject* keyfunc) { 118 if (limit - start <= 1) 119 return 0; // Nothing to sort. 120 121 GOOGLE_CHECK_ATTACHED(self); 122 123 google::protobuf::Message* message = self->message; 124 const google::protobuf::Reflection* reflection = message->GetReflection(); 125 const google::protobuf::FieldDescriptor* descriptor = self->parent_field->descriptor; 126 Py_ssize_t left; 127 Py_ssize_t right; 128 129 PyObject* children = self->child_messages; 130 131 do { 132 left = start; 133 right = limit; 134 ScopedPyObjectPtr mid( 135 GET_KEY(keyfunc, PyList_GET_ITEM(children, (start + limit) / 2))); 136 do { 137 ScopedPyObjectPtr key(GET_KEY(keyfunc, PyList_GET_ITEM(children, left))); 138 int is_lt = islt(key, mid, cmp); 139 if (is_lt == -1) 140 return -1; 141 /* array[left]<x */ 142 while (is_lt) { 143 ++left; 144 ScopedPyObjectPtr key(GET_KEY(keyfunc, 145 PyList_GET_ITEM(children, left))); 146 is_lt = islt(key, mid, cmp); 147 if (is_lt == -1) 148 return -1; 149 } 150 key.reset(GET_KEY(keyfunc, PyList_GET_ITEM(children, right - 1))); 151 is_lt = islt(mid, key, cmp); 152 if (is_lt == -1) 153 return -1; 154 while (is_lt) { 155 --right; 156 ScopedPyObjectPtr key(GET_KEY(keyfunc, 157 PyList_GET_ITEM(children, right - 1))); 158 is_lt = islt(mid, key, cmp); 159 if (is_lt == -1) 160 return -1; 161 } 162 if (left < right) { 163 --right; 164 if (left < right) { 165 reflection->SwapElements(message, descriptor, left, right); 166 PyObject* tmp = PyList_GET_ITEM(children, left); 167 PyList_SET_ITEM(children, left, PyList_GET_ITEM(children, right)); 168 PyList_SET_ITEM(children, right, tmp); 169 } 170 ++left; 171 } 172 } while (left < right); 173 174 if ((right - start) < (limit - left)) { 175 /* sort [start..right[ */ 176 if (start < (right - 1)) { 177 InternalQuickSort(self, start, right, cmp, keyfunc); 178 } 179 180 /* sort [left..limit[ */ 181 start = left; 182 } else { 183 /* sort [left..limit[ */ 184 if (left < (limit - 1)) { 185 InternalQuickSort(self, left, limit, cmp, keyfunc); 186 } 187 188 /* sort [start..right[ */ 189 limit = right; 190 } 191 } while (start < (limit - 1)); 192 193 return 0; 194} 195 196#undef GET_KEY 197 198// --------------------------------------------------------------------- 199// len() 200 201static Py_ssize_t Length(RepeatedCompositeContainer* self) { 202 google::protobuf::Message* message = self->message; 203 if (message != NULL) { 204 return message->GetReflection()->FieldSize(*message, 205 self->parent_field->descriptor); 206 } else { 207 // The container has been released (i.e. by a call to Clear() or 208 // ClearField() on the parent) and thus there's no message. 209 return PyList_GET_SIZE(self->child_messages); 210 } 211} 212 213// Returns 0 if successful; returns -1 and sets an exception if 214// unsuccessful. 215static int UpdateChildMessages(RepeatedCompositeContainer* self) { 216 if (self->message == NULL) 217 return 0; 218 219 // A MergeFrom on a parent message could have caused extra messages to be 220 // added in the underlying protobuf so add them to our list. They can never 221 // be removed in such a way so there's no need to worry about that. 222 Py_ssize_t message_length = Length(self); 223 Py_ssize_t child_length = PyList_GET_SIZE(self->child_messages); 224 google::protobuf::Message* message = self->message; 225 const google::protobuf::Reflection* reflection = message->GetReflection(); 226 for (Py_ssize_t i = child_length; i < message_length; ++i) { 227 const Message& sub_message = reflection->GetRepeatedMessage( 228 *(self->message), self->parent_field->descriptor, i); 229 ScopedPyObjectPtr py_cmsg(cmessage::NewEmpty(self->subclass_init)); 230 if (py_cmsg == NULL) { 231 return -1; 232 } 233 CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg.get()); 234 cmsg->owner = self->owner; 235 cmsg->message = const_cast<google::protobuf::Message*>(&sub_message); 236 cmsg->parent = self->parent; 237 if (cmessage::InitAttributes(cmsg, NULL, NULL) < 0) { 238 return -1; 239 } 240 PyList_Append(self->child_messages, py_cmsg); 241 } 242 return 0; 243} 244 245// --------------------------------------------------------------------- 246// add() 247 248static PyObject* AddToAttached(RepeatedCompositeContainer* self, 249 PyObject* args, 250 PyObject* kwargs) { 251 GOOGLE_CHECK_ATTACHED(self); 252 253 if (UpdateChildMessages(self) < 0) { 254 return NULL; 255 } 256 if (cmessage::AssureWritable(self->parent) == -1) 257 return NULL; 258 google::protobuf::Message* message = self->message; 259 google::protobuf::Message* sub_message = 260 message->GetReflection()->AddMessage(message, 261 self->parent_field->descriptor); 262 PyObject* py_cmsg = cmessage::NewEmpty(self->subclass_init); 263 if (py_cmsg == NULL) { 264 return NULL; 265 } 266 CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg); 267 268 cmsg->owner = self->owner; 269 cmsg->message = sub_message; 270 cmsg->parent = self->parent; 271 // cmessage::InitAttributes must be called after cmsg->message has 272 // been set. 273 if (cmessage::InitAttributes(cmsg, NULL, kwargs) < 0) { 274 Py_DECREF(py_cmsg); 275 return NULL; 276 } 277 PyList_Append(self->child_messages, py_cmsg); 278 return py_cmsg; 279} 280 281static PyObject* AddToReleased(RepeatedCompositeContainer* self, 282 PyObject* args, 283 PyObject* kwargs) { 284 GOOGLE_CHECK_RELEASED(self); 285 286 // Create the CMessage 287 PyObject* py_cmsg = PyObject_CallObject(self->subclass_init, NULL); 288 if (py_cmsg == NULL) 289 return NULL; 290 CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg); 291 if (cmessage::InitAttributes(cmsg, NULL, kwargs) < 0) { 292 Py_DECREF(py_cmsg); 293 return NULL; 294 } 295 296 // The Message got created by the call to subclass_init above and 297 // it set self->owner to the newly allocated message. 298 299 PyList_Append(self->child_messages, py_cmsg); 300 return py_cmsg; 301} 302 303PyObject* Add(RepeatedCompositeContainer* self, 304 PyObject* args, 305 PyObject* kwargs) { 306 if (self->message == NULL) 307 return AddToReleased(self, args, kwargs); 308 else 309 return AddToAttached(self, args, kwargs); 310} 311 312// --------------------------------------------------------------------- 313// extend() 314 315PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value) { 316 cmessage::AssureWritable(self->parent); 317 if (UpdateChildMessages(self) < 0) { 318 return NULL; 319 } 320 ScopedPyObjectPtr iter(PyObject_GetIter(value)); 321 if (iter == NULL) { 322 PyErr_SetString(PyExc_TypeError, "Value must be iterable"); 323 return NULL; 324 } 325 ScopedPyObjectPtr next; 326 while ((next.reset(PyIter_Next(iter))) != NULL) { 327 if (!PyObject_TypeCheck(next, &CMessage_Type)) { 328 PyErr_SetString(PyExc_TypeError, "Not a cmessage"); 329 return NULL; 330 } 331 ScopedPyObjectPtr new_message(Add(self, NULL, NULL)); 332 if (new_message == NULL) { 333 return NULL; 334 } 335 CMessage* new_cmessage = reinterpret_cast<CMessage*>(new_message.get()); 336 if (cmessage::MergeFrom(new_cmessage, next) == NULL) { 337 return NULL; 338 } 339 } 340 if (PyErr_Occurred()) { 341 return NULL; 342 } 343 Py_RETURN_NONE; 344} 345 346PyObject* MergeFrom(RepeatedCompositeContainer* self, PyObject* other) { 347 if (UpdateChildMessages(self) < 0) { 348 return NULL; 349 } 350 return Extend(self, other); 351} 352 353PyObject* Subscript(RepeatedCompositeContainer* self, PyObject* slice) { 354 if (UpdateChildMessages(self) < 0) { 355 return NULL; 356 } 357 Py_ssize_t from; 358 Py_ssize_t to; 359 Py_ssize_t step; 360 Py_ssize_t length = Length(self); 361 Py_ssize_t slicelength; 362 if (PySlice_Check(slice)) { 363#if PY_MAJOR_VERSION >= 3 364 if (PySlice_GetIndicesEx(slice, 365#else 366 if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice), 367#endif 368 length, &from, &to, &step, &slicelength) == -1) { 369 return NULL; 370 } 371 return PyList_GetSlice(self->child_messages, from, to); 372 } else if (PyInt_Check(slice) || PyLong_Check(slice)) { 373 from = to = PyLong_AsLong(slice); 374 if (from < 0) { 375 from = to = length + from; 376 } 377 PyObject* result = PyList_GetItem(self->child_messages, from); 378 if (result == NULL) { 379 return NULL; 380 } 381 Py_INCREF(result); 382 return result; 383 } 384 PyErr_SetString(PyExc_TypeError, "index must be an integer or slice"); 385 return NULL; 386} 387 388int AssignSubscript(RepeatedCompositeContainer* self, 389 PyObject* slice, 390 PyObject* value) { 391 if (UpdateChildMessages(self) < 0) { 392 return -1; 393 } 394 if (value != NULL) { 395 PyErr_SetString(PyExc_TypeError, "does not support assignment"); 396 return -1; 397 } 398 399 // Delete from the underlying Message, if any. 400 if (self->message != NULL) { 401 if (cmessage::InternalDeleteRepeatedField(self->message, 402 self->parent_field->descriptor, 403 slice, 404 self->child_messages) < 0) { 405 return -1; 406 } 407 } else { 408 Py_ssize_t from; 409 Py_ssize_t to; 410 Py_ssize_t step; 411 Py_ssize_t length = Length(self); 412 Py_ssize_t slicelength; 413 if (PySlice_Check(slice)) { 414#if PY_MAJOR_VERSION >= 3 415 if (PySlice_GetIndicesEx(slice, 416#else 417 if (PySlice_GetIndicesEx(reinterpret_cast<PySliceObject*>(slice), 418#endif 419 length, &from, &to, &step, &slicelength) == -1) { 420 return -1; 421 } 422 return PySequence_DelSlice(self->child_messages, from, to); 423 } else if (PyInt_Check(slice) || PyLong_Check(slice)) { 424 from = to = PyLong_AsLong(slice); 425 if (from < 0) { 426 from = to = length + from; 427 } 428 return PySequence_DelItem(self->child_messages, from); 429 } 430 } 431 432 return 0; 433} 434 435static PyObject* Remove(RepeatedCompositeContainer* self, PyObject* value) { 436 if (UpdateChildMessages(self) < 0) { 437 return NULL; 438 } 439 Py_ssize_t index = PySequence_Index(self->child_messages, value); 440 if (index == -1) { 441 return NULL; 442 } 443 ScopedPyObjectPtr py_index(PyLong_FromLong(index)); 444 if (AssignSubscript(self, py_index, NULL) < 0) { 445 return NULL; 446 } 447 Py_RETURN_NONE; 448} 449 450static PyObject* RichCompare(RepeatedCompositeContainer* self, 451 PyObject* other, 452 int opid) { 453 if (UpdateChildMessages(self) < 0) { 454 return NULL; 455 } 456 if (!PyObject_TypeCheck(other, &RepeatedCompositeContainer_Type)) { 457 PyErr_SetString(PyExc_TypeError, 458 "Can only compare repeated composite fields " 459 "against other repeated composite fields."); 460 return NULL; 461 } 462 if (opid == Py_EQ || opid == Py_NE) { 463 // TODO(anuraag): Don't make new lists just for this... 464 ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL)); 465 if (full_slice == NULL) { 466 return NULL; 467 } 468 ScopedPyObjectPtr list(Subscript(self, full_slice)); 469 if (list == NULL) { 470 return NULL; 471 } 472 ScopedPyObjectPtr other_list( 473 Subscript( 474 reinterpret_cast<RepeatedCompositeContainer*>(other), full_slice)); 475 if (other_list == NULL) { 476 return NULL; 477 } 478 return PyObject_RichCompare(list, other_list, opid); 479 } else { 480 Py_INCREF(Py_NotImplemented); 481 return Py_NotImplemented; 482 } 483} 484 485// --------------------------------------------------------------------- 486// sort() 487 488static PyObject* SortAttached(RepeatedCompositeContainer* self, 489 PyObject* args, 490 PyObject* kwds) { 491 // Sort the underlying Message array. 492 PyObject *compare = NULL; 493 int reverse = 0; 494 PyObject *keyfunc = NULL; 495 static char *kwlist[] = {"cmp", "key", "reverse", 0}; 496 497 if (args != NULL) { 498 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:sort", 499 kwlist, &compare, &keyfunc, &reverse)) 500 return NULL; 501 } 502 if (compare == Py_None) 503 compare = NULL; 504 if (keyfunc == Py_None) 505 keyfunc = NULL; 506 507 const Py_ssize_t length = Length(self); 508 if (InternalQuickSort(self, 0, length, compare, keyfunc) < 0) 509 return NULL; 510 511 // Finally reverse the result if requested. 512 if (reverse) { 513 google::protobuf::Message* message = self->message; 514 const google::protobuf::Reflection* reflection = message->GetReflection(); 515 const google::protobuf::FieldDescriptor* descriptor = self->parent_field->descriptor; 516 517 // Reverse the Message array. 518 for (int i = 0; i < length / 2; ++i) 519 reflection->SwapElements(message, descriptor, i, length - i - 1); 520 521 // Reverse the Python list. 522 ScopedPyObjectPtr res(PyObject_CallMethod(self->child_messages, 523 "reverse", NULL)); 524 if (res == NULL) 525 return NULL; 526 } 527 528 Py_RETURN_NONE; 529} 530 531static PyObject* SortReleased(RepeatedCompositeContainer* self, 532 PyObject* args, 533 PyObject* kwds) { 534 ScopedPyObjectPtr m(PyObject_GetAttrString(self->child_messages, "sort")); 535 if (m == NULL) 536 return NULL; 537 if (PyObject_Call(m, args, kwds) == NULL) 538 return NULL; 539 Py_RETURN_NONE; 540} 541 542static PyObject* Sort(RepeatedCompositeContainer* self, 543 PyObject* args, 544 PyObject* kwds) { 545 // Support the old sort_function argument for backwards 546 // compatibility. 547 if (kwds != NULL) { 548 PyObject* sort_func = PyDict_GetItemString(kwds, "sort_function"); 549 if (sort_func != NULL) { 550 // Must set before deleting as sort_func is a borrowed reference 551 // and kwds might be the only thing keeping it alive. 552 PyDict_SetItemString(kwds, "cmp", sort_func); 553 PyDict_DelItemString(kwds, "sort_function"); 554 } 555 } 556 557 if (UpdateChildMessages(self) < 0) 558 return NULL; 559 if (self->message == NULL) { 560 return SortReleased(self, args, kwds); 561 } else { 562 return SortAttached(self, args, kwds); 563 } 564} 565 566// --------------------------------------------------------------------- 567 568static PyObject* Item(RepeatedCompositeContainer* self, Py_ssize_t index) { 569 if (UpdateChildMessages(self) < 0) { 570 return NULL; 571 } 572 Py_ssize_t length = Length(self); 573 if (index < 0) { 574 index = length + index; 575 } 576 PyObject* item = PyList_GetItem(self->child_messages, index); 577 if (item == NULL) { 578 return NULL; 579 } 580 Py_INCREF(item); 581 return item; 582} 583 584// The caller takes ownership of the returned Message. 585Message* ReleaseLast(const FieldDescriptor* field, 586 const Descriptor* type, 587 Message* message) { 588 GOOGLE_CHECK_NOTNULL(field); 589 GOOGLE_CHECK_NOTNULL(type); 590 GOOGLE_CHECK_NOTNULL(message); 591 592 Message* released_message = message->GetReflection()->ReleaseLast( 593 message, field); 594 // TODO(tibell): Deal with proto1. 595 596 // ReleaseMessage will return NULL which differs from 597 // child_cmessage->message, if the field does not exist. In this case, 598 // the latter points to the default instance via a const_cast<>, so we 599 // have to reset it to a new mutable object since we are taking ownership. 600 if (released_message == NULL) { 601 const Message* prototype = global_message_factory->GetPrototype(type); 602 GOOGLE_CHECK_NOTNULL(prototype); 603 return prototype->New(); 604 } else { 605 return released_message; 606 } 607} 608 609// Release field of message and transfer the ownership to cmessage. 610void ReleaseLastTo(const FieldDescriptor* field, 611 Message* message, 612 CMessage* cmessage) { 613 GOOGLE_CHECK_NOTNULL(field); 614 GOOGLE_CHECK_NOTNULL(message); 615 GOOGLE_CHECK_NOTNULL(cmessage); 616 617 shared_ptr<Message> released_message( 618 ReleaseLast(field, cmessage->message->GetDescriptor(), message)); 619 cmessage->parent = NULL; 620 cmessage->parent_field = NULL; 621 cmessage->message = released_message.get(); 622 cmessage->read_only = false; 623 cmessage::SetOwner(cmessage, released_message); 624} 625 626// Called to release a container using 627// ClearField('container_field_name') on the parent. 628int Release(RepeatedCompositeContainer* self) { 629 if (UpdateChildMessages(self) < 0) { 630 PyErr_WriteUnraisable(PyBytes_FromString("Failed to update released " 631 "messages")); 632 return -1; 633 } 634 635 Message* message = self->message; 636 const FieldDescriptor* field = self->parent_field->descriptor; 637 638 // The reflection API only lets us release the last message in a 639 // repeated field. Therefore we iterate through the children 640 // starting with the last one. 641 const Py_ssize_t size = PyList_GET_SIZE(self->child_messages); 642 GOOGLE_DCHECK_EQ(size, message->GetReflection()->FieldSize(*message, field)); 643 for (Py_ssize_t i = size - 1; i >= 0; --i) { 644 CMessage* child_cmessage = reinterpret_cast<CMessage*>( 645 PyList_GET_ITEM(self->child_messages, i)); 646 ReleaseLastTo(field, message, child_cmessage); 647 } 648 649 // Detach from containing message. 650 self->parent = NULL; 651 self->parent_field = NULL; 652 self->message = NULL; 653 self->owner.reset(); 654 655 return 0; 656} 657 658int SetOwner(RepeatedCompositeContainer* self, 659 const shared_ptr<Message>& new_owner) { 660 GOOGLE_CHECK_ATTACHED(self); 661 662 self->owner = new_owner; 663 const Py_ssize_t n = PyList_GET_SIZE(self->child_messages); 664 for (Py_ssize_t i = 0; i < n; ++i) { 665 PyObject* msg = PyList_GET_ITEM(self->child_messages, i); 666 if (cmessage::SetOwner(reinterpret_cast<CMessage*>(msg), new_owner) == -1) { 667 return -1; 668 } 669 } 670 return 0; 671} 672 673static int Init(RepeatedCompositeContainer* self, 674 PyObject* args, 675 PyObject* kwargs) { 676 self->message = NULL; 677 self->parent = NULL; 678 self->parent_field = NULL; 679 self->subclass_init = NULL; 680 self->child_messages = PyList_New(0); 681 return 0; 682} 683 684static void Dealloc(RepeatedCompositeContainer* self) { 685 Py_CLEAR(self->child_messages); 686 // TODO(tibell): Do we need to call delete on these objects to make 687 // sure their destructors are called? 688 self->owner.reset(); 689 Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); 690} 691 692static PySequenceMethods SqMethods = { 693 (lenfunc)Length, /* sq_length */ 694 0, /* sq_concat */ 695 0, /* sq_repeat */ 696 (ssizeargfunc)Item /* sq_item */ 697}; 698 699static PyMappingMethods MpMethods = { 700 (lenfunc)Length, /* mp_length */ 701 (binaryfunc)Subscript, /* mp_subscript */ 702 (objobjargproc)AssignSubscript,/* mp_ass_subscript */ 703}; 704 705static PyMethodDef Methods[] = { 706 { "add", (PyCFunction) Add, METH_VARARGS | METH_KEYWORDS, 707 "Adds an object to the repeated container." }, 708 { "extend", (PyCFunction) Extend, METH_O, 709 "Adds objects to the repeated container." }, 710 { "remove", (PyCFunction) Remove, METH_O, 711 "Removes an object from the repeated container." }, 712 { "sort", (PyCFunction) Sort, METH_VARARGS | METH_KEYWORDS, 713 "Sorts the repeated container." }, 714 { "MergeFrom", (PyCFunction) MergeFrom, METH_O, 715 "Adds objects to the repeated container." }, 716 { NULL, NULL } 717}; 718 719} // namespace repeated_composite_container 720 721PyTypeObject RepeatedCompositeContainer_Type = { 722 PyVarObject_HEAD_INIT(&PyType_Type, 0) 723 "google.protobuf.internal." 724 "cpp._message.RepeatedCompositeContainer", // tp_name 725 sizeof(RepeatedCompositeContainer), // tp_basicsize 726 0, // tp_itemsize 727 (destructor)repeated_composite_container::Dealloc, // tp_dealloc 728 0, // tp_print 729 0, // tp_getattr 730 0, // tp_setattr 731 0, // tp_compare 732 0, // tp_repr 733 0, // tp_as_number 734 &repeated_composite_container::SqMethods, // tp_as_sequence 735 &repeated_composite_container::MpMethods, // tp_as_mapping 736 0, // tp_hash 737 0, // tp_call 738 0, // tp_str 739 0, // tp_getattro 740 0, // tp_setattro 741 0, // tp_as_buffer 742 Py_TPFLAGS_DEFAULT, // tp_flags 743 "A Repeated scalar container", // tp_doc 744 0, // tp_traverse 745 0, // tp_clear 746 (richcmpfunc)repeated_composite_container::RichCompare, // tp_richcompare 747 0, // tp_weaklistoffset 748 0, // tp_iter 749 0, // tp_iternext 750 repeated_composite_container::Methods, // tp_methods 751 0, // tp_members 752 0, // tp_getset 753 0, // tp_base 754 0, // tp_dict 755 0, // tp_descr_get 756 0, // tp_descr_set 757 0, // tp_dictoffset 758 (initproc)repeated_composite_container::Init, // tp_init 759}; 760 761} // namespace python 762} // namespace protobuf 763} // namespace google 764