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