repeated_composite_container.cc 25 KB

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