• Home
  • History
  • Annotate
  • only in /external/sl4a/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/provider/
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